Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion quest/m3/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ generic std gap is planned here even when moq never calls it.
- [bytes' Chain as a Buf object](/quest/m3/ts-buf-chain.md) - `Chain::copy_to_bytes` across both halves translates, and with it a `Chain` as a `dyn Buf`
- [A Buf object's size](/quest/m3/ts-dyn-buf-size.md) - a `dyn Buf` object holds only the methods some call dispatches to
- [A boxed iterator folds as std's box does](/quest/m3/ts-box-folds.md) - a `Box<I>` reads by `next` where std's `Iterator` for `Box<I>` forwards nothing else
- [by_ref of a mutable reference to an iterator](/quest/m3/ts-by-ref-place.md) - `Iterator::by_ref` of a `&mut I` in a local translates
- [mem::take as a function value](/quest/m3/ts-take-value.md) - `mem::take`, `replace`, and `swap` passed as a function value translate
- [Debug of a RefCell](/quest/m3/ts-refcell-debug.md) - `{:?}` of a `RefCell`, `Ref`, and `RefMut` translates as std's writes them
- [Placeholders written to a crate's own fmt::Write](/quest/m3/ts-fmt-calls.md) - `write!` with placeholders into a crate's own writer translates, its `write_str` seeing each call std makes
Expand Down
15 changes: 0 additions & 15 deletions quest/m3/ts-by-ref-place.md

This file was deleted.

4 changes: 3 additions & 1 deletion ts/fixtures/lang/expected/harness.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ import { spills, remnants, layouts } from "./heap.ts";
import { hints, reserves } from "./hints.ts";
import { holds } from "./holds.ts";
import { u8Op, u16Op, u32Op, u64Op, u128Op, usizeOp, i8Op, i16Op, i32Op, i64Op, i128Op, isizeOp, i8Neg, i16Neg, i32Neg, i64Neg, i128Neg, isizeNeg, cast as ints_cast, convert, parses as ints_parses, widenings } from "./ints.ts";
import { adaptors, consumers as iters_consumers, reducers, peekedOthers, skips, ranked as iters_ranked, ranges as iters_ranges, options as iters_options, optionItems, own as iters_own, values as iters_values, returned, zips, zipsBack, rangeFroms, rangeMethods, compares } from "./iters.ts";
import { adaptors, consumers as iters_consumers, reducers, peekedOthers, skips, ranked as iters_ranked, ranges as iters_ranges, options as iters_options, optionItems, own as iters_own, values as iters_values, returned, zips, zipsBack, rangeFroms, rangeMethods, compares, lent as iters_lent } from "./iters.ts";
import { joins } from "./joins.ts";
import { keys as keys_keys, overrides, bytes as keys_bytes, lentKeys, lentValues, arrays as keys_arrays, byteRefs } from "./keys.ts";
import { lengths } from "./lengths.ts";
Expand Down Expand Up @@ -329,6 +329,8 @@ export function cases(): [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec)
dyns_iters(data113, out114);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["errors::objects", (_2214: rt.u8, data114: rt.ByteSlice, out115: rt.ByteVec): undefined => {
errors_objects(data114.data, data114.start, data114.length, out115);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined], ["iters::lent", (_2215: rt.u8, data115: rt.ByteSlice, out116: rt.ByteVec): undefined => {
iters_lent(data115, out116);
}] as [string, (a0: rt.u8, a1: rt.ByteSlice, a2: rt.ByteVec) => undefined]];
}

Expand Down
52 changes: 52 additions & 0 deletions ts/fixtures/lang/expected/iters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9500,4 +9500,56 @@ export function compares(kind: rt.u8, data: rt.ByteSlice, out: rt.ByteVec): void
rt.refRelease(_1004);
}

/**
* `by_ref` of a `&mut` to an iterator held in a local, of a `&mut` to that, and of a
* `&mut dyn Iterator`: each advances the iterator it points at, which the original reads
* on from where the borrow stopped, and writing through what it returns rebinds the local.
*/
export function lent(data: rt.ByteSlice, out: rt.ByteVec): void {
const n: rt.usize = option_mapOr$1t0muvr(rt.byteSliceFirst(data), 0, (_2: rt.u8): rt.usize => {
return rt.u8Rem(_2, 4) as rt.usize;
});
const it: rt.Iter<rt.u8> = rt.iterSlice(rt.byteSliceView(data));
const lent: rt.Iter<rt.u8> = it;
rt.iterExtendBytes(out, rt.iterTake(rt.iterBorrow(lent), n), undefined, true);
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(lent.next()), 170));
rt.iterExtendBytes(out, rt.iterTake(rt.iterBorrow(it), 1), undefined, true);
let once: rt.Iter<rt.u8> = it;
const twice: rt.Place<rt.Iter<rt.u8>> = rt.place(() => once, (value2) => once = value2);
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterNth(rt.iterBorrow(twice.v), n), 187));
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(twice.v.next()), 204));
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(it.next()), 221));
const own: iters_Countdown.Countdown = { left: rt.u8Mul(n & 0xff, 3), step: 2 };
const other: iters_Countdown.Countdown = { left: 9, step: 4 };
let held: iters_Countdown.Countdown = own;
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(iters_Countdown.next$iter_Iterator(held)), 170));
held = other;
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(iters_Countdown.next$iter_Iterator(held)), 187));
rt.iterExtendBytes(out, rt.iterFrom(own, (it: iters_Countdown.Countdown) => iters_Countdown.next$iter_Iterator(it)), "next");
rt.iterExtendBytes(out, rt.iterFrom(other, (it: iters_Countdown.Countdown) => iters_Countdown.next$iter_Iterator(it)), "next");
const range: rt.Range<rt.u8> = new rt.Range(0, rt.u8Mul(n & 0xff, 3));
let erased: rt.Iter<rt.u8> = rt.iterDyn(rt.iterBorrow(range));
rt.iterExtendBytes(out, rt.iterTake(rt.iterStepBy(rt.iterBorrow(erased), 2), 2), "next");
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(erased.next()), 238));
rt.byteVecPush(out, option_unwrapOr$0r2bmpr(rt.iterToOption(erased.next()), 238));
rt.iterExtendBytes(out, range, undefined, true);
let boxed: rt.Iter<rt.u8> = rt.iterDyn(rt.iterRev(rt.iterSlice(rt.byteSliceView(data))));
rt.iterExtendBytes(out, rt.iterTake(rt.iterBorrow(boxed), n), "next");
rt.iterExtendBytes(out, rt.iterTake(boxed, 1), "next");
const rest: rt.Iter<rt.u8> = rt.iterSlice(rt.byteSliceView(data));
rt.iterExtendBytes(out, rt.byteVecIntoIter(halves$mut_iter_Copied_slice_Iter_u8(rest, n)), undefined, true);
rt.iterExtendBytes(out, rest, undefined, true);
rt.iterExtendBytes(out, rt.byteVecIntoIter(halves$iter_Copied_slice_Iter_u8(rt.iterSlice(rt.byteSliceView(data)), n)), undefined, true);
}

/** The first `n` items, then one more. */
export function halves$iter_Copied_slice_Iter_u8(it: rt.Iter<rt.u8>, n: rt.usize): rt.ByteVec {
return rt.byteSlicesJoin([rt.iterToByteVec(rt.iterTake(rt.iterBorrow(it), n), undefined, true), rt.iterToByteVec(rt.iterTake(it, 1), undefined, true)], undefined, rt.byteVecSlice);
}

/** The first `n` items, then one more. */
export function halves$mut_iter_Copied_slice_Iter_u8(it: rt.Iter<rt.u8>, n: rt.usize): rt.ByteVec {
return rt.byteSlicesJoin([rt.iterToByteVec(rt.iterTake(rt.iterBorrow(it), n), undefined, true), rt.iterToByteVec(rt.iterTake(rt.iterBorrow(it), 1), undefined, true)], undefined, rt.byteVecSlice);
}

//# sourceMappingURL=iters.ts.map
1 change: 1 addition & 0 deletions ts/fixtures/lang/src/harness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ fn cases() -> Vec<(&'static str, Case)> {
("searches::texts", searches::texts),
("dyns::iters", |_, data, out| dyns::iters(data, out)),
("errors::objects", |_, data, out| errors::objects(data, out)),
("iters::lent", |_, data, out| iters::lent(data, out)),
]
}

Expand Down
55 changes: 55 additions & 0 deletions ts/fixtures/lang/src/iters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1840,3 +1840,58 @@ pub fn compares(kind: u8, data: &[u8], out: &mut Vec<u8>) {
}
out.extend_from_slice(&log.borrow());
}

/// `by_ref` of a `&mut` to an iterator held in a local, of a `&mut` to that, and of a
/// `&mut dyn Iterator`: each advances the iterator it points at, which the original reads
/// on from where the borrow stopped, and writing through what it returns rebinds the local.
pub fn lent(data: &[u8], out: &mut Vec<u8>) {
let n = data.first().map_or(0, |&b| usize::from(b % 4));
let mut it = data.iter().copied();
let mut lent = &mut it;
out.extend((&mut lent).by_ref().take(n));
out.push(lent.next().unwrap_or(0xaa));
out.extend(it.by_ref().take(1));
let mut once = &mut it;
let mut twice = &mut once;
out.push((&mut twice).by_ref().nth(n).unwrap_or(0xbb));
out.push(twice.next().unwrap_or(0xcc));
out.push(it.next().unwrap_or(0xdd));

// Rebound through the `&mut` that `by_ref` returns, the local reads the other iterator,
// and the first is left where it stopped.
let mut own = Countdown {
left: n as u8 * 3,
step: 2,
};
let mut other = Countdown { left: 9, step: 4 };
let mut held = &mut own;
out.push(held.next().unwrap_or(0xaa));
*(&mut held).by_ref() = &mut other;
out.push(held.next().unwrap_or(0xbb));
out.extend(own);
out.extend(other);

let mut range = 0..n as u8 * 3;
let mut erased: &mut dyn Iterator<Item = u8> = &mut range;
out.extend((&mut erased).by_ref().step_by(2).take(2));
out.push(erased.next().unwrap_or(0xee));
let mut deeper = &mut erased;
out.push((&mut deeper).by_ref().next().unwrap_or(0xee));
out.extend(range);
let mut boxed: Box<dyn Iterator<Item = u8>> = Box::new(data.iter().rev().copied());
let mut lent = &mut boxed;
out.extend((&mut lent).by_ref().take(n));
out.extend(boxed.take(1));

// Generic over an iterator that is itself a `&mut`, or one it owns.
let mut rest = data.iter().copied();
out.extend(halves(&mut rest, n));
out.extend(rest);
out.extend(halves(data.iter().copied(), n));
}

/// The first `n` items, then one more.
fn halves<I: Iterator<Item = u8>>(mut it: I, n: usize) -> Vec<u8> {
let front: Vec<u8> = it.by_ref().take(n).collect();
[front, it.take(1).collect()].concat()
}
10 changes: 5 additions & 5 deletions ts/src/lower/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,11 @@ pub fn call<'tcx>(
let value = args.pop()?;
return into_iter(b, targ(0)?, value, span);
}
// The `&mut` it was given, an `rt.Place` where that points at a `&mut`.
("Iterator", "by_ref") => {
not_bound(b, targ(0)?, span);
return args.pop();
}
_ => {}
}
match path.as_slice() {
Expand Down Expand Up @@ -607,11 +612,6 @@ pub fn call<'tcx>(
};
return Some(Expr::rt("iterToOption", [item].into_iter().chain(none).collect()));
}
// The same object, borrowed.
if name == "by_ref" {
return Some(recv);
}

let recv = into_iter(b, iter_ty, recv, span)?;
// `rt.iter<Name>(recv, ...args)`, or `peekable<Name>` of a `Peekable`'s own.
let method = |name: &str, args: Vec<Expr>| {
Expand Down
5 changes: 3 additions & 2 deletions ts/src/lower/mir/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,8 +371,8 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> {
// Mappings that lend an element JS copies as its place, as a map's `get_mut` does, the
// item a `Peekable` peeked, the place a `&mut dyn Any` wraps, a `RefCell` key's value,
// a `Result`'s payload, the value of an `Arc`, a lock, or a cell, what a write guard
// lends its map or its leak, or what `zip` makes of the collection it is given by
// `into_iter`, as the free `zip` does of either.
// lends its map or its leak, the `&mut` an iterator's `by_ref` is given, or what `zip`
// makes of the collection it is given by `into_iter`, as the free `zip` does of either.
let lends = match library::key(tcx, def_id) {
Some((owner, name)) => match (owner.as_str(), name.as_str()) {
("slice", "get_mut" | "first_mut" | "last_mut" | "iter_mut" | "split_first_mut" | "split_last_mut")
Expand All @@ -385,6 +385,7 @@ impl<'m, 'b, 'a, 'tcx> Fx<'m, 'b, 'a, 'tcx> {
| ("Mutex" | "RwLock" | "RefCell" | "OnceCell" | "OnceLock", "get_mut")
| ("RefMut", "leak")
| ("RefCell", "undo_leak")
| ("Iterator", "by_ref")
| (
"RefMut" | "MutexGuard" | "MappedMutexGuard" | "RwLockWriteGuard" | "MappedRwLockWriteGuard",
"map" | "filter_map" | "try_map" | "map_split",
Expand Down
5 changes: 3 additions & 2 deletions ts/src/lower/pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,8 @@ pub fn keeps<'tcx>(tcx: ty::TyCtxt<'tcx>, def_id: rustc_hir::def_id::DefId, args
/// rather than what it points at: a `MaybeUninit`'s or a `ManuallyDrop`'s, which it points
/// into, an `Arc`'s that `make_mut` replaces, a `String`'s that a drain edits as it drops,
/// a `Result`'s whose payload JS copies, which `iter_mut` lends as a place that writes the
/// whole `Result`, and a well-known crate's, such as a `Bytes` that `Buf::advance` moves
/// past its front.
/// whole `Result`, an iterator's that `by_ref` returns, and a well-known crate's, such as a
/// `Bytes` that `Buf::advance` moves past its front.
fn takes_place<'tcx>(
t: &Translator<'_, 'tcx>,
def_id: rustc_hir::def_id::DefId,
Expand All @@ -410,6 +410,7 @@ fn takes_place<'tcx>(
Some((owner, name)) if matches!(owner.as_str(), "MaybeUninit" | "ManuallyDrop")
|| matches!(owner.as_str(), "Arc" | "Rc") && name == "make_mut"
|| (owner.as_str(), name.as_str()) == ("String", "drain")
|| (owner.as_str(), name.as_str()) == ("Iterator", "by_ref")
|| (owner.as_str(), name.as_str()) == ("Result", "iter_mut") && t.needs_place(args.type_at(0))
) || super::stock::is_stock(t.tcx, def_id)
}
Expand Down