diff --git a/quest/m3/README.md b/quest/m3/README.md index f451cc0fd..cbb5b1a3c 100644 --- a/quest/m3/README.md +++ b/quest/m3/README.md @@ -49,4 +49,3 @@ memory model for values whose address is reinterpreted, without a consumer. - [Throw only where Rust panics](/quest/m3/ts-runtime-throws.md) - no runtime `rust2-ts:` error where native Rust goes on: an exact slower path, or a refusal at translation - [rust2-ts with no ts.toml](/quest/m3/ts-configless.md) - a crate's whole `pub` API translates with no config and no bound items - [Browser APIs through wasm-bindgen](/quest/m3/ts-wasm-bindgen/README.md) - web-sys and js-sys imports become direct JS calls, so idiomatic crates such as web-rs's web-codecs translate as stock crates -- [Fields typed by an associated type](/quest/m3/ts-assoc-type-fields.md) - a generic struct's field of `::Item` translates at each instance diff --git a/quest/m3/ts-assoc-type-fields.md b/quest/m3/ts-assoc-type-fields.md deleted file mode 100644 index 1efd288ba..000000000 --- a/quest/m3/ts-assoc-type-fields.md +++ /dev/null @@ -1,20 +0,0 @@ -# [M] Fields typed by an associated type - -## Goal - -[rust2-ts](/ts/README.md) translates a generic struct whose field is typed by an -associated type of its parameter, such as smallvec's `Drain<'a, T: Array>` holding -`::Item`, by resolving the projection at each instance, proven by differential -tests against native Rust. - -## Plan - -Suggested on [#600](https://github.com/moq-dev/rust2/pull/600) (rangemap): it is 1 of -smallvec's 10 model refusals at the moq pin. The rest are `unsafe` that the -[ts-unsafe epic](/quest/m3/ts-unsafe/README.md) owns, and moq drops or binds smallvec, so -this is a language gap rather than a consumer's. - -Decided with the maintainer on 2026-11-07: ✅ m3 (rejected: m2, drop), as a core language -gap, not a smallvec-specific one. - -Public API: the translator's output. diff --git a/ts/README.md b/ts/README.md index a195a06da..5e2dc89f1 100644 --- a/ts/README.md +++ b/ts/README.md @@ -491,7 +491,16 @@ function is suffixed instead by a hash of its text, with what it calls by name, translation reaches. Types are translated once, generically over their type parameters but not their const ones, which type nothing in TS: arrayvec's `ArrayString<4>` and `ArrayString<16>` are one `ArrayString`, and each instance's functions read its own -`CAP`. So a function of a generic type is one instance's, declaring the instance it +`CAP`. A projection its fields name, such as smallvec's `::Item`, directly, +through a generic type of the crate's they hold, or as a std iterator's item, is a type +parameter of its own after them, named for its associated type and numbered past any it +would shadow, which each instance gives what the projection is there: +`Drain<[u8; 4]>` is a `Drain`. An instance a projection argument +holds is named by an exported alias of its own, `type Held$Src = Held`, so +one that holds itself again ends, and the output grows with the instances rather than +the paths through them; an enum's alias spells out its union at the instance, as +TypeScript refuses an alias naming itself through a generic one. Types typed with each +other, as a tree and its branches are, each take the projections either names. So a function of a generic type is one instance's, declaring the instance it takes as `self`: `fmt$fmt_Debug_fmt_Pair(self: Wrap, f: rs.Formatter)`. A reference or pointer in a generic type to what only an instance decides the form of, such as `*mut T` or @@ -1191,9 +1200,12 @@ that drops given to a std function that keeps it other than in an iterator or a `poll_fn`, or whose mapping doesn't drop it where std's does, a `Cow` of other than `str` or a slice, a std function without a mapping of its own that makes or reads an `Option` whose `None` is `rs.None`, an `Option` of an `Option` of `()` or another -`Option`, an instance of a generic type whose field is an `Option` of a type parameter -that can be `undefined` though TypeScript's type of it can't, as a `MaybeUninit` -can, or an `Option` or a `Poll` of another form of it whose instance can be `undefined` or pending, a `String`'s `capacity`, looking up a key by +`Option`, an instance of a generic type whose field is an `Option` of a type parameter, +or of a projection from one, that can be `undefined` though TypeScript's type of it can't, as a `MaybeUninit` +can, or an `Option` or a `Poll` of another form of it whose instance can be `undefined` or pending, a `ControlFlow` breaking with one that an instance +makes an `Option` or `Result`, or a future of one whose instance can be pending, each also through a generic type it holds, an instance of a generic type +over type parameters whose projection is a type holding that instance again, in a generic type's definition (`Held>` where `Wrap::Item` is a `Held>`), a generic type that +holds itself at other arguments than its own parameters whose instances name new instances or projections for more rounds than the crate's recursion limit, a `String`'s `capacity`, looking up a key by another type it borrows as through the crate's own `Borrow`, a `&mut` to a value JS copies that std makes, other than a map's, or hands a closure, as `iter_mut` and `and_modify` do, one into a `Result`'s payload passed on or kept, the adaptors diff --git a/ts/fixtures/lang/shapes/expected/core/bool.ts b/ts/fixtures/lang/shapes/expected/core/bool.ts index e30f27734..6fec500c8 100644 --- a/ts/fixtures/lang/shapes/expected/core/bool.ts +++ b/ts/fixtures/lang/shapes/expected/core/bool.ts @@ -2,6 +2,19 @@ import * as rs from "../rs.ts"; import type * as Pair from "../fmt.Pair.ts"; +import type * as Copse from "../generics.Copse.ts"; +import type * as Grove from "../generics.Grove.ts"; +import type * as Holder from "../generics.Holder.ts"; +import type * as Layer from "../generics.Layer.ts"; +import type * as Peel from "../generics.Peel.ts"; +import type * as Remade from "../generics.Remade.ts"; +import type * as Seed from "../generics.Seed.ts"; +import type * as Shoot from "../generics.Shoot.ts"; +import type * as Sibling from "../generics.Sibling.ts"; +import type * as Sprout from "../generics.Sprout.ts"; +import type * as Ticked from "../generics.Ticked.ts"; +import type * as Top from "../generics.Top.ts"; +import type * as Twig from "../generics.Twig.ts"; import type * as Void from "../shapes.Void.ts"; export function thenSome$1ctlqen(self: boolean, t: rs.u8 | undefined): rs.u8 | undefined | rs.None { @@ -32,6 +45,41 @@ export function thenSome$05ku0zn(self: boolean, t: rs.i32): rs.i32 | undefined { return t; } +export function thenSome$0bd8znh(self: boolean, t: Layer.Layer, boolean, rs.u8>): Layer.Layer, boolean, rs.u8> | undefined { + if (!self) { + return undefined; + } + return t; +} + +export function thenSome$0czqe00(self: boolean, t: Shoot.Shoot): Shoot.Shoot | undefined { + if (!self) { + return undefined; + } + return t; +} + +export function thenSome$0rdxccx(self: boolean, t: Sibling.Sibling, rs.u8, rs.u8>): Sibling.Sibling, rs.u8, rs.u8> | undefined { + if (!self) { + return undefined; + } + return t; +} + +export function thenSome$0tbnivw(self: boolean, t: Ticked.Ticked): Ticked.Ticked | undefined { + if (!self) { + return undefined; + } + return t; +} + +export function thenSome$0epplxd(self: boolean, t: Twig.Twig): Twig.Twig | undefined { + if (!self) { + return undefined; + } + return t; +} + export function thenSome$19pue01(self: boolean, t: rs.Poll): rs.Poll | undefined { if (!self) { return undefined; @@ -67,6 +115,20 @@ export function then$0y7on52(self: boolean, _: () => rs.ByteVec): rs.ByteVec | u return new rs.ByteVec(); } +export function then$1tgze8k(self: boolean, f: () => Holder.Holder): Holder.Holder | undefined { + if (!self) { + return undefined; + } + return f(); +} + +export function then$1qflv5x(self: boolean, f: () => Ticked.Ticked): Ticked.Ticked | undefined { + if (!self) { + return undefined; + } + return f(); +} + export function then$1ldvmdq(self: boolean, f: () => rs.u8): rs.u8 | undefined { if (!self) { return undefined; diff --git a/ts/fixtures/lang/shapes/expected/core/option.ts b/ts/fixtures/lang/shapes/expected/core/option.ts index a836601c1..451569538 100644 --- a/ts/fixtures/lang/shapes/expected/core/option.ts +++ b/ts/fixtures/lang/shapes/expected/core/option.ts @@ -1,7 +1,28 @@ // Generated by rust2-ts. Do not edit. import * as rs from "../rs.ts"; +import type * as Back from "../generics.Back.ts"; +import type * as Carried from "../generics.Carried.ts"; +import type * as Copse from "../generics.Copse.ts"; +import type * as Counted from "../generics.Counted.ts"; +import type * as Defaulted from "../generics.Defaulted.ts"; +import type * as Depth from "../generics.Depth.ts"; +import type * as Forked from "../generics.Forked.ts"; +import type * as Grove from "../generics.Grove.ts"; +import type * as Head from "../generics.Head.ts"; +import type * as Holder from "../generics.Holder.ts"; +import type * as Layer from "../generics.Layer.ts"; +import type * as Looped from "../generics.Looped.ts"; +import type * as Node from "../generics.Node.ts"; +import type * as Peel from "../generics.Peel.ts"; +import type * as Remade from "../generics.Remade.ts"; +import type * as Seed from "../generics.Seed.ts"; +import type * as Shoot from "../generics.Shoot.ts"; +import type * as Sibling from "../generics.Sibling.ts"; +import type * as Sprout from "../generics.Sprout.ts"; import type * as Ticked from "../generics.Ticked.ts"; +import type * as Top from "../generics.Top.ts"; +import type * as Twig from "../generics.Twig.ts"; import { from$convert_From_shapes_Dir_u8 } from "../shapes.ts"; import type * as Dir from "../shapes.Dir.ts"; import type * as Meters from "../shapes.Meters.ts"; @@ -43,6 +64,104 @@ export function unwrapOrDefault$03apme8(self: rs.u8 | undefined): rs.u8 { return self; } +export function map$00jdj9f(self: Carried.Carried | undefined, _: (a0: Carried.Carried) => Carried.Carried): Carried.Carried | undefined { + if (self === undefined) { + return undefined; + } + return self; +} + +export function map$0xoixq7(self: Counted.Counted | undefined, _: (a0: Counted.Counted) => Counted.Counted): Counted.Counted | undefined { + if (self === undefined) { + return undefined; + } + return self; +} + +export function map$0983ug4(self: Defaulted.Defaulted | undefined, _: (a0: Defaulted.Defaulted) => Defaulted.Defaulted): Defaulted.Defaulted | undefined { + if (self === undefined) { + return undefined; + } + return self; +} + +export function map$14wqhyc(self: Holder.Holder | undefined, f: (a0: Holder.Holder) => [rs.u8, rs.u8 | undefined]): [rs.u8, rs.u8 | undefined] | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$04m4r6n(self: Counted.Counted | undefined, f: (a0: Counted.Counted) => rs.u8): rs.u8 | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1ug09xc(self: Forked.Forked | undefined, f: (a0: Forked.Forked) => rs.u8): rs.u8 | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1747o3c(self: Forked.Forked | undefined, f: (a0: Forked.Forked) => rs.u8): rs.u8 | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1mvacy3(self: Forked.Forked | undefined, f: (a0: Forked.Forked) => [rs.u8, rs.u8 | undefined, rs.u8 | undefined]): [rs.u8, rs.u8 | undefined, rs.u8 | undefined] | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1es1113(self: Node.Node | undefined, f: (a0: Node.Node) => rs.u8): rs.u8 | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1ub01y7(self: Ticked.Ticked | undefined, f: (a0: Ticked.Ticked) => rs.u8): rs.u8 | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1a3j889(self: Layer.Layer, boolean, rs.u8> | undefined, f: (a0: Layer.Layer, boolean, rs.u8>) => [boolean, boolean]): [boolean, boolean] | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1avgfgw(self: Shoot.Shoot | undefined, f: (a0: Shoot.Shoot) => boolean): boolean | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$0e9v36n(self: Sibling.Sibling, rs.u8, rs.u8> | undefined, f: (a0: Sibling.Sibling, rs.u8, rs.u8>) => [rs.u8, boolean]): [rs.u8, boolean] | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1i2swnz(self: Twig.Twig | undefined, f: (a0: Twig.Twig) => boolean): boolean | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + export function map$0ggarad(self: rs.u8 | undefined, f: (a0: rs.u8) => rs.Vec): rs.Vec | undefined { if (self === undefined) { return undefined; @@ -50,6 +169,56 @@ export function map$0ggarad(self: rs.u8 | undefined, f: (a0: rs.u8) => rs.Vec boolean): boolean | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1olalbb(self: rs.u8 | undefined, f: (a0: rs.u8) => Forked.Forked): Forked.Forked | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1htvaju(self: rs.u8 | undefined, f: (a0: rs.u8) => Node.Node): Node.Node | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$0xpm57l(self: rs.u8 | undefined, f: (a0: rs.u8) => Ticked.Ticked): Ticked.Ticked | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$1yjmt5m(self: rs.u8 | undefined, f: (a0: rs.u8) => rs.u8): rs.u8 | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$0ydco3f(self: rs.u8 | undefined, f: (a0: rs.u8) => rs.u16): rs.u16 | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + +export function map$057a36e(self: rs.u8 | undefined, f: (a0: rs.u8) => undefined): undefined | rs.None { + if (self === undefined) { + return rs.None; + } + f(self); + return undefined; +} + export function map$0600mq0(self: Dir.Dir | undefined, f: (a0: Dir.Dir) => Shape.Shape): Shape.Shape | undefined { if (self === undefined) { return undefined; @@ -120,6 +289,25 @@ export function okOr$1j8owgb(self: rs.u8 | undefined, err: rs.u8): rs.Result | undefined): Carried.Carried | undefined { + return map$00jdj9f(self, (a0: Carried.Carried): Carried.Carried => { + return a0; + }); +} + +export function asDeref$1z13rqi(self: Defaulted.Defaulted | undefined): Defaulted.Defaulted | undefined { + return map$0983ug4(self, (a0: Defaulted.Defaulted): Defaulted.Defaulted => { + return a0; + }); +} + +export function andThen$0jij6xn(self: Counted.Counted | undefined, f: (a0: Counted.Counted) => Counted.Counted | undefined): Counted.Counted | undefined { + if (self === undefined) { + return undefined; + } + return f(self); +} + export function andThen$0jc4o0i(self: rs.u8 | undefined, f: (a0: rs.u8) => rs.u8 | undefined | rs.None): rs.u8 | undefined | rs.None { if (self === undefined) { return rs.None; diff --git a/ts/fixtures/lang/shapes/expected/generics.Ahead.ts b/ts/fixtures/lang/shapes/expected/generics.Ahead.ts new file mode 100644 index 000000000..00e606cfe --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Ahead.ts @@ -0,0 +1,55 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Flags from "./generics.Flags.ts"; + +/** + * A std iterator's items, which only its `Iterator` impl names, beside the same + * projection named again; a parameter named for an associated type, so each projection's + * name is numbered past it. + */ +export class Ahead<_Item, _I, Item2, Item3> { + iter: rs.Peekable; + seen: rs.VecOf; + stored: rs.OptionOf; + + constructor(iter: rs.Peekable, seen: rs.VecOf, stored: rs.OptionOf) { + this.iter = iter; + this.seen = seen; + this.stored = stored; + } +} + +/** Takes each item that repeats the one before it. */ +export function repeats$array1_u16_iter_Map_slice_Iter_u8_generics_projections_closure1(self: Ahead, rs.u8, rs.u16>): rs.usize { + while (true) { + const _2: rs.u8 | rs.Done = self.iter.next(); + if (_2 !== rs.DONE) { + const item: rs.u8 = _2; + if (rs.peekablePeek(self.iter) === item) { + rs.byteVecPush(self.seen as rs.ByteVec, item); + } + } else { + break; + } + } + return (self.seen as rs.ByteVec).length; +} + +/** Takes each item that repeats the one before it. */ +export function repeats$generics_Flags_slice_Iter_u8(self: Ahead, rs.u8, boolean>): rs.usize { + while (true) { + const _2: rs.u8 | rs.Done = self.iter.next(); + if (_2 !== rs.DONE) { + const item: rs.u8 = _2; + if (rs.peekablePeek(self.iter) === item) { + (self.seen as rs.Vec).items.push(item); + } + } else { + break; + } + } + return (self.seen as rs.Vec).items.length; +} + +//# sourceMappingURL=generics.Ahead.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Back.ts b/ts/fixtures/lang/shapes/expected/generics.Back.ts new file mode 100644 index 000000000..7c865a8f6 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Back.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** The default source of a [`Defaulted`]. */ +export interface Back { +} + +//# sourceMappingURL=generics.Back.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Batch.ts b/ts/fixtures/lang/shapes/expected/generics.Batch.ts new file mode 100644 index 000000000..0a54d4b55 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Batch.ts @@ -0,0 +1,62 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import * as Drained from "./generics.Drained.ts"; +import type * as Flags from "./generics.Flags.ts"; + +/** A [`Drained`] in another generic type, which names the projection only through it. */ +export class Batch { + drain: Drained.Drained; + taken: rs.u8; + + constructor(drain: Drained.Drained, taken: rs.u8) { + this.drain = drain; + this.taken = taken; + } +} + +export function take$array1_Option_u8(self: Batch, rs.u8 | undefined>): rs.u8 | undefined | rs.None { + const _2: rs.u8 | undefined | rs.None = Drained.next$array1_Option_u8(self.drain); + if (_2 !== rs.None) { + self.taken = rs.u8WrappingAdd(self.taken, 1); + return _2; + } + return rs.None; +} + +export function take$array2_u16(self: Batch): rs.u16 | undefined { + const _2: rs.u16 | undefined = Drained.next$array2_u16(self.drain); + if (_2 !== undefined) { + self.taken = rs.u8WrappingAdd(self.taken, 1); + return _2; + } + return undefined; +} + +export function take$array3_unit(self: Batch): undefined | rs.None { + if (Drained.next$array3_unit(self.drain) !== rs.None) { + self.taken = rs.u8WrappingAdd(self.taken, 1); + return undefined; + } + return rs.None; +} + +export function take$array4_u8(self: Batch): rs.u8 | undefined { + const _2: rs.u8 | undefined = Drained.next$array4_u8(self.drain); + if (_2 !== undefined) { + self.taken = rs.u8WrappingAdd(self.taken, 1); + return _2; + } + return undefined; +} + +export function take$generics_Flags(self: Batch): boolean | undefined { + const _2: boolean | undefined = Drained.next$generics_Flags(self.drain); + if (_2 !== undefined) { + self.taken = rs.u8WrappingAdd(self.taken, 1); + return _2; + } + return undefined; +} + +//# sourceMappingURL=generics.Batch.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Branch.ts b/ts/fixtures/lang/shapes/expected/generics.Branch.ts new file mode 100644 index 000000000..862b4260f --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Branch.ts @@ -0,0 +1,19 @@ +// Generated by rust2-ts. Do not edit. + +import type * as Tree from "./generics.Tree.ts"; + +/** + * One branch of a [`Tree`], whose projection only the tree's other type names, typed with + * it, so each learns its projections from the other. + */ +export class Branch { + item: Item; + below: Tree.Tree | undefined; + + constructor(item: Item, below: Tree.Tree | undefined) { + this.item = item; + this.below = below; + } +} + +//# sourceMappingURL=generics.Branch.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Carried.ts b/ts/fixtures/lang/shapes/expected/generics.Carried.ts new file mode 100644 index 000000000..7af6402ca --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Carried.ts @@ -0,0 +1,28 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Looped from "./generics.Looped.ts"; +import type * as Ticked from "./generics.Ticked.ts"; + +/** + * What a source holds next, which TypeScript names through an alias where the item is it + * again. + */ +export class Carried<_S, Item> { + tick: Ticked.Ticked; + next: rs.OptionOf; + + constructor(tick: Ticked.Ticked, next: rs.OptionOf) { + this.tick = tick; + this.next = next; + } + + [Symbol.dispose](): void { + this.tick[Symbol.dispose](); + rs.drop(this.next); + } +} + +export type Carried$generics_Looped = Carried; + +//# sourceMappingURL=generics.Carried.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Chain.ts b/ts/fixtures/lang/shapes/expected/generics.Chain.ts new file mode 100644 index 000000000..b0b41cbd0 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Chain.ts @@ -0,0 +1,23 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Linked from "./generics.Linked.ts"; + +/** + * An enum of what a source holds next, whose alias at an instance whose items are it again + * spells out its union. + */ +export type Chain<_S, Item> = { tag: "End" } | { tag: "Link"; _0: rs.u8; _1: Item }; + +export type Chain$generics_Linked = + | { tag: "End" } + | { tag: "Link"; _0: rs.u8; _1: Chain$generics_Linked }; + +export function ids$generics_Linked(self: Chain, out: rs.ByteVec): void { + if (self.tag === "Link") { + rs.byteVecPush(out, self._0); + ids$generics_Linked(self._1, out); + } +} + +//# sourceMappingURL=generics.Chain.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Copse.ts b/ts/fixtures/lang/shapes/expected/generics.Copse.ts new file mode 100644 index 000000000..668bb0718 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Copse.ts @@ -0,0 +1,16 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Shoot from "./generics.Shoot.ts"; +import type * as Tail from "./generics.Tail.ts"; + +/** A [`Grove`] with its item typed first. */ +export type Copse = + | { tag: "Item"; _0: Item } + | { tag: "Branch"; _0: Shoot.Shoot }; + +export type Copse$generics_Tail = + | { tag: "Item"; _0: rs.u8 } + | { tag: "Branch"; _0: Shoot.Shoot }; + +//# sourceMappingURL=generics.Copse.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Counted.ts b/ts/fixtures/lang/shapes/expected/generics.Counted.ts new file mode 100644 index 000000000..3e511a0ee --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Counted.ts @@ -0,0 +1,18 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** What a source at a depth holds next, an instance only of its const parameter. */ +export class Counted { + id: rs.u8; + next: rs.OptionOf; + + constructor(id: rs.u8, next: rs.OptionOf) { + this.id = id; + this.next = next; + } +} + +export type Counted$0 = Counted; + +//# sourceMappingURL=generics.Counted.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Deep.ts b/ts/fixtures/lang/shapes/expected/generics.Deep.ts new file mode 100644 index 000000000..f30e996a3 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Deep.ts @@ -0,0 +1,24 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** A projection from a projection, which is one parameter whole. */ +export class Deep<_S, Item> { + inner: rs.OptionOf; + len: rs.usize; + + constructor(inner: rs.OptionOf, len: rs.usize) { + this.inner = inner; + this.len = len; + } +} + +export function new$array3_array2_u8(inner: rs.u8 | undefined): Deep { + return new Deep(inner as rs.OptionOf, 3 * 2); +} + +export function new$array4_array2_unit(inner: undefined | rs.None): Deep { + return new Deep(inner as rs.OptionOf, 4 * 2); +} + +//# sourceMappingURL=generics.Deep.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Defaulted.ts b/ts/fixtures/lang/shapes/expected/generics.Defaulted.ts new file mode 100644 index 000000000..abd289f57 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Defaulted.ts @@ -0,0 +1,22 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Back from "./generics.Back.ts"; + +/** + * What a source holds next, whose source defaults to the one whose items are it again, + * so its alias is named by the default too. + */ +export class Defaulted<_S, Item> { + id: rs.u8; + next: rs.OptionOf; + + constructor(id: rs.u8, next: rs.OptionOf) { + this.id = id; + this.next = next; + } +} + +export type Defaulted$generics_Back = Defaulted; + +//# sourceMappingURL=generics.Defaulted.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Depth.ts b/ts/fixtures/lang/shapes/expected/generics.Depth.ts new file mode 100644 index 000000000..7327949b2 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Depth.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** The source at a depth. */ +export interface Depth { +} + +//# sourceMappingURL=generics.Depth.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Drained.ts b/ts/fixtures/lang/shapes/expected/generics.Drained.ts new file mode 100644 index 000000000..dc0a5615a --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Drained.ts @@ -0,0 +1,91 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Flags from "./generics.Flags.ts"; + +/** + * A drain over a store's items, as smallvec's `Drain` holds `::Item`s: + * directly, in an `Option`, whose `None` each instance decides, and through a slice's + * iterator. + */ +export class Drained<_S, Item> { + last: rs.OptionOf; + iter: rs.Iter>; + first: Item; + + constructor(last: rs.OptionOf, iter: rs.Iter>, first: Item) { + this.last = last; + this.iter = iter; + this.first = first; + } +} + +export function new$array1_Option_u8(first: rs.u8 | undefined, items: rs.Slice): Drained, rs.u8 | undefined> { + return new Drained(rs.None as rs.OptionOf, rs.iterSlice(rs.sliceItems(items)) as rs.Iter>, first); +} + +export function new$array2_u16(first: rs.u16, items: rs.Slice): Drained { + return new Drained(undefined as rs.OptionOf, rs.iterSlice(rs.sliceItems(items)) as rs.Iter>, first); +} + +export function new$array3_unit(_: undefined, items: rs.Slice): Drained { + return new Drained(rs.None as rs.OptionOf, rs.iterSlice(rs.sliceItems(items)) as rs.Iter>, undefined); +} + +export function new$array4_u8(first: rs.u8, items: rs.ByteSlice): Drained { + return new Drained(undefined as rs.OptionOf, rs.iterSlice(rs.byteSliceView(items)) as rs.Iter>, first); +} + +export function new$generics_Flags(first: boolean, items: rs.Slice): Drained { + return new Drained(undefined as rs.OptionOf, rs.iterSlice(rs.sliceItems(items)) as rs.Iter>, first); +} + +export function next$array1_Option_u8(self: Drained, rs.u8 | undefined>): rs.u8 | undefined | rs.None { + const _3: rs.u8 | undefined | rs.Done = (self.iter as rs.Iter).next(); + if (_3 !== rs.DONE) { + const item: rs.u8 | undefined = _3; + self.last = item; + return item; + } + return rs.None; +} + +export function next$array2_u16(self: Drained): rs.u16 | undefined { + const _3: rs.u16 | rs.Done = (self.iter as rs.Iter).next(); + if (_3 !== rs.DONE) { + const item: rs.u16 = _3; + self.last = item; + return item; + } + return undefined; +} + +export function next$array3_unit(self: Drained): undefined | rs.None { + if ((self.iter as rs.Iter).next() !== rs.DONE) { + self.last = undefined; + return undefined; + } + return rs.None; +} + +export function next$array4_u8(self: Drained): rs.u8 | undefined { + const _3: rs.u8 | rs.Done = (self.iter as rs.Iter).next(); + if (_3 !== rs.DONE) { + const item: rs.u8 = _3; + self.last = item; + return item; + } + return undefined; +} + +export function next$generics_Flags(self: Drained): boolean | undefined { + const _3: boolean | rs.Done = (self.iter as rs.Iter).next(); + if (_3 !== rs.DONE) { + const item: boolean = _3; + self.last = item; + return item; + } + return undefined; +} + +//# sourceMappingURL=generics.Drained.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Even.ts b/ts/fixtures/lang/shapes/expected/generics.Even.ts new file mode 100644 index 000000000..e7d496855 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Even.ts @@ -0,0 +1,27 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Flags from "./generics.Flags.ts"; +import type * as Odd from "./generics.Odd.ts"; + +/** + * Two types typed with each other, each naming a projection the other doesn't, so each + * takes both, in the order it named them. + */ +export type Even = + | { tag: "End" } + | { tag: "Next"; _0: Item; _1: Odd.Odd }; + +export function walk$generics_Flags_vec_IntoIter_u8(self: Even, boolean, rs.u8>, out: rs.String): void { + if (self.tag === "Next") { + const _22: Odd.Odd, rs.u8, boolean> = self._1; + const arg = self._0; + const _16: rs.Fmt = (f: rs.Formatter) => rs.fmtBool(arg, f); + const arg2 = _22.seen; + const args3 = [_16, (f: rs.Formatter) => rs.fmtOption(arg2, f, rs.u8Debug)]; + rs.stringPushStr(out, rs.fmtFormat([args3[0], " ", args3[1], " "]).v); + walk$generics_Flags_vec_IntoIter_u8(self._1.next, out); + } +} + +//# sourceMappingURL=generics.Even.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Flags.ts b/ts/fixtures/lang/shapes/expected/generics.Flags.ts new file mode 100644 index 000000000..840693580 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Flags.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** A store of flags, whose items are no array's. */ +export interface Flags { +} + +//# sourceMappingURL=generics.Flags.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Forked.ts b/ts/fixtures/lang/shapes/expected/generics.Forked.ts new file mode 100644 index 000000000..e5bea62d5 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Forked.ts @@ -0,0 +1,99 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Depth from "./generics.Depth.ts"; +import type * as Ticked from "./generics.Ticked.ts"; + +/** A fork of what its source's projections both are. */ +export class Forked<_F, Left, Right> { + id: rs.u8; + left: rs.OptionOf; + right: rs.OptionOf; + + constructor(id: rs.u8, left: rs.OptionOf, right: rs.OptionOf) { + this.id = id; + this.left = left; + this.right = right; + } + + [Symbol.dispose](): void { + rs.drop(this.left); + rs.drop(this.right); + } +} + +export type Forked$generics_Depth_0 = + | Forked; + +export type Forked$generics_Depth_1 = + | Forked; + +export type Forked$generics_Depth_10 = + | Forked; + +export type Forked$generics_Depth_11 = + | Forked; + +export type Forked$generics_Depth_12 = + | Forked; + +export type Forked$generics_Depth_13 = + | Forked; + +export type Forked$generics_Depth_14 = + | Forked; + +export type Forked$generics_Depth_15 = + | Forked; + +export type Forked$generics_Depth_16 = + | Forked; + +export type Forked$generics_Depth_17 = + | Forked; + +export type Forked$generics_Depth_18 = + | Forked; + +export type Forked$generics_Depth_19 = + | Forked; + +export type Forked$generics_Depth_2 = + | Forked; + +export type Forked$generics_Depth_20 = + | Forked; + +export type Forked$generics_Depth_21 = + | Forked; + +export type Forked$generics_Depth_22 = + | Forked; + +export type Forked$generics_Depth_23 = + | Forked; + +export type Forked$generics_Depth_24 = Forked; + +export type Forked$generics_Depth_3 = + | Forked; + +export type Forked$generics_Depth_4 = + | Forked; + +export type Forked$generics_Depth_5 = + | Forked; + +export type Forked$generics_Depth_6 = + | Forked; + +export type Forked$generics_Depth_7 = + | Forked; + +export type Forked$generics_Depth_8 = + | Forked; + +export type Forked$generics_Depth_9 = + | Forked; + +//# sourceMappingURL=generics.Forked.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Get.ts b/ts/fixtures/lang/shapes/expected/generics.Get.ts new file mode 100644 index 000000000..8834fba8a --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Get.ts @@ -0,0 +1,12 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Holder from "./generics.Holder.ts"; + +/** + * A getter of its parameter, and of the type holding it, which its object's type names + * while that type's definition is still being typed. + */ +export type Get = { get$Get: () => rs.OptionOf; holder$Get: () => Holder.Holder | undefined }; + +//# sourceMappingURL=generics.Get.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Getter.ts b/ts/fixtures/lang/shapes/expected/generics.Getter.ts new file mode 100644 index 000000000..3018c0f05 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Getter.ts @@ -0,0 +1,22 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import { thenSome$0quywni, then$1tgze8k } from "./core/bool.ts"; +import * as Holder from "./generics.Holder.ts"; + +/** A getter of a byte, holding half of it again past `0x80`. */ +export interface Getter { + _0: rs.u8; +} + +export function get$generics_Get_u8(self: Getter): rs.u8 | undefined { + return thenSome$0quywni(rs.u8Rem(self._0, 3) !== 0, self._0); +} + +export function holder$generics_Get_u8(self: Getter): Holder.Holder | undefined { + return then$1tgze8k(self._0 > 128, (): Holder.Holder => { + return Holder.new(rs.u8Div(self._0, 2), rs.u8Div(self._0, 2)); + }); +} + +//# sourceMappingURL=generics.Getter.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Ghost.ts b/ts/fixtures/lang/shapes/expected/generics.Ghost.ts new file mode 100644 index 000000000..bb30ef2bf --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Ghost.ts @@ -0,0 +1,17 @@ +// Generated by rust2-ts. Do not edit. + +/** + * A projection beside an `Option` of it only a `PhantomData` holds, which types nothing, so + * no instance is refused for what that `Option` would erase to. + */ +export class Ghost<_S, Item> { + item: Item; + marker: undefined; + + constructor(item: Item, marker: undefined) { + this.item = item; + this.marker = marker; + } +} + +//# sourceMappingURL=generics.Ghost.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Grove.ts b/ts/fixtures/lang/shapes/expected/generics.Grove.ts new file mode 100644 index 000000000..9abb6a551 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Grove.ts @@ -0,0 +1,18 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Tail from "./generics.Tail.ts"; +import type * as Twig from "./generics.Twig.ts"; + +/** + * A grove's branch, or its source's item, its branch typed first: typing [`Twig`] names + * `Grove` while the grove's own definition, still being typed, has yet to name its + * item, so the twig completes with the grove. + */ +export type Grove = { tag: "Branch"; _0: Twig.Twig } | { tag: "Item"; _0: Item }; + +export type Grove$generics_Tail = + | { tag: "Branch"; _0: Twig.Twig } + | { tag: "Item"; _0: rs.u8 }; + +//# sourceMappingURL=generics.Grove.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Head.ts b/ts/fixtures/lang/shapes/expected/generics.Head.ts new file mode 100644 index 000000000..063773c64 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Head.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** The source of the node a [`Node`] holds. */ +export interface Head { +} + +//# sourceMappingURL=generics.Head.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Holder.ts b/ts/fixtures/lang/shapes/expected/generics.Holder.ts new file mode 100644 index 000000000..a716fb916 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Holder.ts @@ -0,0 +1,29 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import { of$generics_Getter } from "./lib.ts"; +import type * as Get from "./generics.Get.ts"; + +/** A type holding a getter whose methods return it. */ +export class Holder { + id: rs.u8; + get: Get.Get; + + constructor(id: rs.u8, get: Get.Get) { + this.id = id; + this.get = get; + } + + [Symbol.dispose](): void { + rs.drop(this.get); + } +} + +/** A holder of a getter of `b`, whose type is typed before its getter's object is. */ +function new_(id: rs.u8, b: rs.u8): Holder { + return new Holder(id, new of$generics_Getter({ _0: b })); +} + +export { new_ as new }; + +//# sourceMappingURL=generics.Holder.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Kept.ts b/ts/fixtures/lang/shapes/expected/generics.Kept.ts new file mode 100644 index 000000000..19d385c00 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Kept.ts @@ -0,0 +1,30 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** + * Items that drop beside the store that names them, which drops nothing, so only the + * items' type decides whether and how each instance drops. + */ +export class Kept { + item: Item; + store: S; + rest: rs.VecOf; + maybe: rs.OptionOf; + + constructor(item: Item, store: S, rest: rs.VecOf, maybe: rs.OptionOf) { + this.item = item; + this.store = store; + this.rest = rest; + this.maybe = maybe; + } + + [Symbol.dispose](): void { + rs.drop(this.item); + rs.drop(this.store); + rs.dropVec(this.rest as rs.Vec); + rs.drop(this.maybe); + } +} + +//# sourceMappingURL=generics.Kept.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Layer.ts b/ts/fixtures/lang/shapes/expected/generics.Layer.ts new file mode 100644 index 000000000..28ac099e8 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Layer.ts @@ -0,0 +1,20 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Peel from "./generics.Peel.ts"; + +/** + * A layer lending the one under it, peeled, whose item is a projection its own definition + * names only once that instance is filled in. + */ +export class Layer { + item: Item; + under: Layer, Other, rs.u8> | undefined; + + constructor(item: Item, under: Layer, Other, rs.u8> | undefined) { + this.item = item; + this.under = under; + } +} + +//# sourceMappingURL=generics.Layer.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Lent.ts b/ts/fixtures/lang/shapes/expected/generics.Lent.ts new file mode 100644 index 000000000..2fae72189 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Lent.ts @@ -0,0 +1,8 @@ +// Generated by rust2-ts. Do not edit. + +/** A store that lends [`Ticked`]s, whose items drop nothing. */ +export interface Lent { + _0: undefined; +} + +//# sourceMappingURL=generics.Lent.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Linked.ts b/ts/fixtures/lang/shapes/expected/generics.Linked.ts new file mode 100644 index 000000000..1afc6804b --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Linked.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** A source whose items chain it again. */ +export interface Linked { +} + +//# sourceMappingURL=generics.Linked.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Looped.ts b/ts/fixtures/lang/shapes/expected/generics.Looped.ts new file mode 100644 index 000000000..76ccd257b --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Looped.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** A source whose items hold it again. */ +export interface Looped { +} + +//# sourceMappingURL=generics.Looped.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Marked.ts b/ts/fixtures/lang/shapes/expected/generics.Marked.ts new file mode 100644 index 000000000..46837a308 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Marked.ts @@ -0,0 +1,12 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** A projection that only a `PhantomData` holds, which types nothing, in an `Option` too. */ +export interface Marked<_S> { + marker: undefined; + maybe: undefined; + count: rs.u8; +} + +//# sourceMappingURL=generics.Marked.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Node.ts b/ts/fixtures/lang/shapes/expected/generics.Node.ts new file mode 100644 index 000000000..4c7789c35 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Node.ts @@ -0,0 +1,23 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Head from "./generics.Head.ts"; +import type * as Tail from "./generics.Tail.ts"; + +/** + * A node holding the node at [`Head`], typed while its own definition is, whose item is the + * node at [`Tail`], whose item ends the chain. + */ +export class Node<_S, Item> { + item: Item; + next: Node | undefined; + + constructor(item: Item, next: Node | undefined) { + this.item = item; + this.next = next; + } +} + +export type Node$generics_Tail = Node; + +//# sourceMappingURL=generics.Node.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Odd.ts b/ts/fixtures/lang/shapes/expected/generics.Odd.ts new file mode 100644 index 000000000..6c5535720 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Odd.ts @@ -0,0 +1,16 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Even from "./generics.Even.ts"; + +export class Odd { + seen: rs.OptionOf; + next: Even.Even; + + constructor(seen: rs.OptionOf, next: Even.Even) { + this.seen = seen; + this.next = next; + } +} + +//# sourceMappingURL=generics.Odd.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Paths.ts b/ts/fixtures/lang/shapes/expected/generics.Paths.ts new file mode 100644 index 000000000..0b0a8c306 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Paths.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** A store of what translation types no other way, which only a `PhantomData` names. */ +export interface Paths { +} + +//# sourceMappingURL=generics.Paths.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Peel.ts b/ts/fixtures/lang/shapes/expected/generics.Peel.ts new file mode 100644 index 000000000..92709ee3e --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Peel.ts @@ -0,0 +1,12 @@ +// Generated by rust2-ts. Do not edit. + +/** A source with a layer peeled off. */ +export class Peel { + _0: S; + + constructor(_0: S) { + this._0 = _0; + } +} + +//# sourceMappingURL=generics.Peel.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Pile.ts b/ts/fixtures/lang/shapes/expected/generics.Pile.ts new file mode 100644 index 000000000..601fcc4f7 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Pile.ts @@ -0,0 +1,48 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Flags from "./generics.Flags.ts"; + +/** A projection in an enum's variants, and in a type that holds itself. */ +export type Pile = + | { tag: "Empty" } + | { tag: "Full"; _0: Item } + | { tag: "Linked"; item: Item; next: Pile }; + +export function push$array2_u8(self: Pile, item: rs.u8): Pile { + if (self.tag === "Empty") { + return { tag: "Full", _0: item } as Pile; + } + return { tag: "Linked", item, next: self } as Pile; +} + +export function push$generics_Flags(self: Pile, item: boolean): Pile { + if (self.tag === "Empty") { + return { tag: "Full", _0: item } as Pile; + } + return { tag: "Linked", item, next: self } as Pile; +} + +export function items$array2_u8(self: Pile, out: rs.ByteVec): void { + if (self.tag !== "Empty") { + if (self.tag === "Full") { + rs.byteVecPush(out, self._0); + } else { + rs.byteVecPush(out, self.item); + items$array2_u8(self.next, out); + } + } +} + +export function items$generics_Flags(self: Pile, out: rs.Vec): void { + if (self.tag !== "Empty") { + if (self.tag === "Full") { + out.items.push(self._0); + } else { + out.items.push(self.item); + items$generics_Flags(self.next, out); + } + } +} + +//# sourceMappingURL=generics.Pile.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Ping.ts b/ts/fixtures/lang/shapes/expected/generics.Ping.ts new file mode 100644 index 000000000..23c1e3406 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Ping.ts @@ -0,0 +1,30 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Pong from "./generics.Pong.ts"; +import type * as Rally from "./generics.Rally.ts"; + +/** What holds a [`Duo`]'s pong. */ +export class Ping<_D, Pong> { + id: rs.u8; + pong: rs.OptionOf; + + constructor(id: rs.u8, pong: rs.OptionOf) { + this.id = id; + this.pong = pong; + } +} + +export type Ping$generics_Rally = Ping; + +export function ids$generics_Rally(self: Ping, out: rs.ByteVec): void { + rs.byteVecPush(out, self.id); + if (self.pong !== undefined) { + if (self.pong.tag === "Hit") { + rs.byteVecPush(out, self.pong._0); + ids$generics_Rally(self.pong._1, out); + } + } +} + +//# sourceMappingURL=generics.Ping.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Pong.ts b/ts/fixtures/lang/shapes/expected/generics.Pong.ts new file mode 100644 index 000000000..ca3cf134b --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Pong.ts @@ -0,0 +1,13 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Ping from "./generics.Ping.ts"; + +/** What holds a [`Duo`]'s ping, or misses. */ +export type Pong<_D, Ping> = { tag: "Miss" } | { tag: "Hit"; _0: rs.u8; _1: Ping }; + +export type Pong$generics_Rally = + | { tag: "Miss" } + | { tag: "Hit"; _0: rs.u8; _1: Ping.Ping$generics_Rally }; + +//# sourceMappingURL=generics.Pong.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Rally.ts b/ts/fixtures/lang/shapes/expected/generics.Rally.ts new file mode 100644 index 000000000..86ee5b8df --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Rally.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** A duo of its own ping and pong. */ +export interface Rally { +} + +//# sourceMappingURL=generics.Rally.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Remade.ts b/ts/fixtures/lang/shapes/expected/generics.Remade.ts new file mode 100644 index 000000000..e92a1b9bc --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Remade.ts @@ -0,0 +1,15 @@ +// Generated by rust2-ts. Do not edit. + +/** + * A source made once more, whose item is what its source makes of what it makes of 130 + * types: more projections than the crate's recursion limit, side by side, but only two deep. + */ +export class Remade { + _0: S; + + constructor(_0: S) { + this._0 = _0; + } +} + +//# sourceMappingURL=generics.Remade.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Seed.ts b/ts/fixtures/lang/shapes/expected/generics.Seed.ts new file mode 100644 index 000000000..0ba851cf9 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Seed.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** The source of a [`Shoot`]'s next. */ +export interface Seed { +} + +//# sourceMappingURL=generics.Seed.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Shoot.ts b/ts/fixtures/lang/shapes/expected/generics.Shoot.ts new file mode 100644 index 000000000..1d6cab527 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Shoot.ts @@ -0,0 +1,17 @@ +// Generated by rust2-ts. Do not edit. + +import type * as Copse from "./generics.Copse.ts"; +import type * as Seed from "./generics.Seed.ts"; + +/** A [`Twig`] of a [`Copse`]. */ +export class Shoot<_S, Item> { + next: Shoot | undefined; + item: Item; + + constructor(next: Shoot | undefined, item: Item) { + this.next = next; + this.item = item; + } +} + +//# sourceMappingURL=generics.Shoot.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Sibling.ts b/ts/fixtures/lang/shapes/expected/generics.Sibling.ts new file mode 100644 index 000000000..465fcecd7 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Sibling.ts @@ -0,0 +1,20 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Remade from "./generics.Remade.ts"; + +/** + * A source's item, lending the same at a source made once more, whose item is a projection + * of 130 sibling projections, which settles at its second. + */ +export class Sibling { + item: Item; + next: Sibling, Made, rs.u8> | undefined; + + constructor(item: Item, next: Sibling, Made, rs.u8> | undefined) { + this.item = item; + this.next = next; + } +} + +//# sourceMappingURL=generics.Sibling.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Slot.ts b/ts/fixtures/lang/shapes/expected/generics.Slot.ts new file mode 100644 index 000000000..89c53d092 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Slot.ts @@ -0,0 +1,14 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +/** An `Option` of a type parameter. */ +export class Slot { + value: rs.OptionOf; + + constructor(value: rs.OptionOf) { + this.value = value; + } +} + +//# sourceMappingURL=generics.Slot.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Sprout.ts b/ts/fixtures/lang/shapes/expected/generics.Sprout.ts new file mode 100644 index 000000000..eedb0cece --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Sprout.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** The source of a [`Twig`]'s next. */ +export interface Sprout { +} + +//# sourceMappingURL=generics.Sprout.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Swap.ts b/ts/fixtures/lang/shapes/expected/generics.Swap.ts new file mode 100644 index 000000000..31331d188 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Swap.ts @@ -0,0 +1,36 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Flags from "./generics.Flags.ts"; + +/** + * A type that holds itself with its parameters swapped, so its projections at the inner + * instance are its own in the other order. + */ +export class Swap { + item: Item; + next: Swap | undefined; + + constructor(item: Item, next: Swap | undefined) { + this.item = item; + this.next = next; + } +} + +export function show$array1_u16_generics_Flags(self: Swap, out: rs.String): void { + const arg = self.item; + rs.stringPushStr(out, rs.fmtFormat([(f: rs.Formatter) => rs.u16Debug(arg, f), " "]).v); + if (self.next !== undefined) { + show$generics_Flags_array1_u16(self.next, out); + } +} + +export function show$generics_Flags_array1_u16(self: Swap, out: rs.String): void { + const arg = self.item; + rs.stringPushStr(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtBool(arg, f), " "]).v); + if (self.next !== undefined) { + show$array1_u16_generics_Flags(self.next, out); + } +} + +//# sourceMappingURL=generics.Swap.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Tail.ts b/ts/fixtures/lang/shapes/expected/generics.Tail.ts new file mode 100644 index 000000000..ac4f7751e --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Tail.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** The last source of a [`Node`] chain. */ +export interface Tail { +} + +//# sourceMappingURL=generics.Tail.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Ticks.ts b/ts/fixtures/lang/shapes/expected/generics.Ticks.ts new file mode 100644 index 000000000..e7e61dd41 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Ticks.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** A store of [`Ticked`]s, which drops nothing itself. */ +export interface Ticks { +} + +//# sourceMappingURL=generics.Ticks.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Top.ts b/ts/fixtures/lang/shapes/expected/generics.Top.ts new file mode 100644 index 000000000..cd233a80f --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Top.ts @@ -0,0 +1,7 @@ +// Generated by rust2-ts. Do not edit. + +/** The outermost layer. */ +export interface Top { +} + +//# sourceMappingURL=generics.Top.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Tree.ts b/ts/fixtures/lang/shapes/expected/generics.Tree.ts new file mode 100644 index 000000000..b67499ddb --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Tree.ts @@ -0,0 +1,24 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; +import type * as Branch from "./generics.Branch.ts"; + +/** Branches that each may hold a tree again. */ +export class Tree { + branches: rs.Vec>; + + constructor(branches: rs.Vec>) { + this.branches = branches; + } +} + +export function items$array1_u8(self: Tree, out: rs.ByteVec): void { + for (const _6 of self.branches.items) { + rs.byteVecPush(out, _6.item); + if (_6.below !== undefined) { + items$array1_u8(_6.below, out); + } + } +} + +//# sourceMappingURL=generics.Tree.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Twig.ts b/ts/fixtures/lang/shapes/expected/generics.Twig.ts new file mode 100644 index 000000000..839126ec5 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Twig.ts @@ -0,0 +1,17 @@ +// Generated by rust2-ts. Do not edit. + +import type * as Grove from "./generics.Grove.ts"; +import type * as Sprout from "./generics.Sprout.ts"; + +/** A twig lending the twig at [`Sprout`], whose item is a grove, and its source's item. */ +export class Twig<_S, Item> { + next: Twig | undefined; + item: Item; + + constructor(next: Twig | undefined, item: Item) { + this.next = next; + this.item = item; + } +} + +//# sourceMappingURL=generics.Twig.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Uninit.ts b/ts/fixtures/lang/shapes/expected/generics.Uninit.ts new file mode 100644 index 000000000..dd54571ed --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Uninit.ts @@ -0,0 +1,13 @@ +// Generated by rust2-ts. Do not edit. + +import type * as generics_Slot from "./generics.Slot.ts"; + +/** + * A [`Slot`] of a `MaybeUninit` of its own parameter, which at a byte is `0` rather than + * `undefined`, as that slot's instance is. + */ +export interface Uninit { + slot: generics_Slot.Slot; +} + +//# sourceMappingURL=generics.Uninit.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.Wide.ts b/ts/fixtures/lang/shapes/expected/generics.Wide.ts new file mode 100644 index 000000000..5daf8a3b6 --- /dev/null +++ b/ts/fixtures/lang/shapes/expected/generics.Wide.ts @@ -0,0 +1,277 @@ +// Generated by rust2-ts. Do not edit. + +import * as rs from "./rs.ts"; + +export class Wide { + a0: A0; + a1: A1; + a2: A2; + a3: A3; + a4: A4; + a5: A5; + a6: A6; + a7: A7; + a8: A8; + a9: A9; + a10: A10; + a11: A11; + a12: A12; + a13: A13; + a14: A14; + a15: A15; + a16: A16; + a17: A17; + a18: A18; + a19: A19; + a20: A20; + a21: A21; + a22: A22; + a23: A23; + a24: A24; + a25: A25; + a26: A26; + a27: A27; + a28: A28; + a29: A29; + a30: A30; + a31: A31; + a32: A32; + a33: A33; + a34: A34; + a35: A35; + a36: A36; + a37: A37; + a38: A38; + a39: A39; + a40: A40; + a41: A41; + a42: A42; + a43: A43; + a44: A44; + a45: A45; + a46: A46; + a47: A47; + a48: A48; + a49: A49; + a50: A50; + a51: A51; + a52: A52; + a53: A53; + a54: A54; + a55: A55; + a56: A56; + a57: A57; + a58: A58; + a59: A59; + a60: A60; + a61: A61; + a62: A62; + a63: A63; + a64: A64; + a65: A65; + a66: A66; + a67: A67; + a68: A68; + a69: A69; + a70: A70; + a71: A71; + a72: A72; + a73: A73; + a74: A74; + a75: A75; + a76: A76; + a77: A77; + a78: A78; + a79: A79; + a80: A80; + a81: A81; + a82: A82; + a83: A83; + a84: A84; + a85: A85; + a86: A86; + a87: A87; + a88: A88; + a89: A89; + a90: A90; + a91: A91; + a92: A92; + a93: A93; + a94: A94; + a95: A95; + a96: A96; + a97: A97; + a98: A98; + a99: A99; + a100: A100; + a101: A101; + a102: A102; + a103: A103; + a104: A104; + a105: A105; + a106: A106; + a107: A107; + a108: A108; + a109: A109; + a110: A110; + a111: A111; + a112: A112; + a113: A113; + a114: A114; + a115: A115; + a116: A116; + a117: A117; + a118: A118; + a119: A119; + a120: A120; + a121: A121; + a122: A122; + a123: A123; + a124: A124; + a125: A125; + a126: A126; + a127: A127; + a128: A128; + a129: A129; + next: Wide | undefined; + + constructor(a0: A0, a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8, a9: A9, a10: A10, a11: A11, a12: A12, a13: A13, a14: A14, a15: A15, a16: A16, a17: A17, a18: A18, a19: A19, a20: A20, a21: A21, a22: A22, a23: A23, a24: A24, a25: A25, a26: A26, a27: A27, a28: A28, a29: A29, a30: A30, a31: A31, a32: A32, a33: A33, a34: A34, a35: A35, a36: A36, a37: A37, a38: A38, a39: A39, a40: A40, a41: A41, a42: A42, a43: A43, a44: A44, a45: A45, a46: A46, a47: A47, a48: A48, a49: A49, a50: A50, a51: A51, a52: A52, a53: A53, a54: A54, a55: A55, a56: A56, a57: A57, a58: A58, a59: A59, a60: A60, a61: A61, a62: A62, a63: A63, a64: A64, a65: A65, a66: A66, a67: A67, a68: A68, a69: A69, a70: A70, a71: A71, a72: A72, a73: A73, a74: A74, a75: A75, a76: A76, a77: A77, a78: A78, a79: A79, a80: A80, a81: A81, a82: A82, a83: A83, a84: A84, a85: A85, a86: A86, a87: A87, a88: A88, a89: A89, a90: A90, a91: A91, a92: A92, a93: A93, a94: A94, a95: A95, a96: A96, a97: A97, a98: A98, a99: A99, a100: A100, a101: A101, a102: A102, a103: A103, a104: A104, a105: A105, a106: A106, a107: A107, a108: A108, a109: A109, a110: A110, a111: A111, a112: A112, a113: A113, a114: A114, a115: A115, a116: A116, a117: A117, a118: A118, a119: A119, a120: A120, a121: A121, a122: A122, a123: A123, a124: A124, a125: A125, a126: A126, a127: A127, a128: A128, a129: A129, next: Wide | undefined) { + this.a0 = a0; + this.a1 = a1; + this.a2 = a2; + this.a3 = a3; + this.a4 = a4; + this.a5 = a5; + this.a6 = a6; + this.a7 = a7; + this.a8 = a8; + this.a9 = a9; + this.a10 = a10; + this.a11 = a11; + this.a12 = a12; + this.a13 = a13; + this.a14 = a14; + this.a15 = a15; + this.a16 = a16; + this.a17 = a17; + this.a18 = a18; + this.a19 = a19; + this.a20 = a20; + this.a21 = a21; + this.a22 = a22; + this.a23 = a23; + this.a24 = a24; + this.a25 = a25; + this.a26 = a26; + this.a27 = a27; + this.a28 = a28; + this.a29 = a29; + this.a30 = a30; + this.a31 = a31; + this.a32 = a32; + this.a33 = a33; + this.a34 = a34; + this.a35 = a35; + this.a36 = a36; + this.a37 = a37; + this.a38 = a38; + this.a39 = a39; + this.a40 = a40; + this.a41 = a41; + this.a42 = a42; + this.a43 = a43; + this.a44 = a44; + this.a45 = a45; + this.a46 = a46; + this.a47 = a47; + this.a48 = a48; + this.a49 = a49; + this.a50 = a50; + this.a51 = a51; + this.a52 = a52; + this.a53 = a53; + this.a54 = a54; + this.a55 = a55; + this.a56 = a56; + this.a57 = a57; + this.a58 = a58; + this.a59 = a59; + this.a60 = a60; + this.a61 = a61; + this.a62 = a62; + this.a63 = a63; + this.a64 = a64; + this.a65 = a65; + this.a66 = a66; + this.a67 = a67; + this.a68 = a68; + this.a69 = a69; + this.a70 = a70; + this.a71 = a71; + this.a72 = a72; + this.a73 = a73; + this.a74 = a74; + this.a75 = a75; + this.a76 = a76; + this.a77 = a77; + this.a78 = a78; + this.a79 = a79; + this.a80 = a80; + this.a81 = a81; + this.a82 = a82; + this.a83 = a83; + this.a84 = a84; + this.a85 = a85; + this.a86 = a86; + this.a87 = a87; + this.a88 = a88; + this.a89 = a89; + this.a90 = a90; + this.a91 = a91; + this.a92 = a92; + this.a93 = a93; + this.a94 = a94; + this.a95 = a95; + this.a96 = a96; + this.a97 = a97; + this.a98 = a98; + this.a99 = a99; + this.a100 = a100; + this.a101 = a101; + this.a102 = a102; + this.a103 = a103; + this.a104 = a104; + this.a105 = a105; + this.a106 = a106; + this.a107 = a107; + this.a108 = a108; + this.a109 = a109; + this.a110 = a110; + this.a111 = a111; + this.a112 = a112; + this.a113 = a113; + this.a114 = a114; + this.a115 = a115; + this.a116 = a116; + this.a117 = a117; + this.a118 = a118; + this.a119 = a119; + this.a120 = a120; + this.a121 = a121; + this.a122 = a122; + this.a123 = a123; + this.a124 = a124; + this.a125 = a125; + this.a126 = a126; + this.a127 = a127; + this.a128 = a128; + this.a129 = a129; + this.next = next; + } +} + +export function new$u8(n: rs.u8): Wide { + return new Wide(n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, n, undefined); +} + +//# sourceMappingURL=generics.Wide.ts.map diff --git a/ts/fixtures/lang/shapes/expected/generics.ts b/ts/fixtures/lang/shapes/expected/generics.ts index 0577bed29..88a59e69b 100644 --- a/ts/fixtures/lang/shapes/expected/generics.ts +++ b/ts/fixtures/lang/shapes/expected/generics.ts @@ -1,19 +1,66 @@ // Generated by rust2-ts. Do not edit. import * as rs from "./rs.ts"; -import { copy$array_generics_Either_u8_shapes_Point, copy$generics_Fixed_u16, copy$generics_Fixed_u8, copy$generics_Wrap_shapes_Point, copy$generics_Wrap_u8, copy$shapes_Gauge, drop$generics_Run_generics_Ticked } from "./lib.ts"; -import { thenSome$1ctlqen, thenSome$19pue01, thenSome$0quywni, thenSome$1n1oy1h, then$01xsbgy, then$0y7on52 } from "./core/bool.ts"; -import { unwrapOr$1fr498u as option_unwrapOr$1fr498u, unwrapOrDefault$0w7995p as option_unwrapOrDefault$0w7995p, unwrapOrDefault$03apme8 as option_unwrapOrDefault$03apme8, map$0ggarad as option_map$0ggarad } from "./core/option.ts"; +import { copy$array_generics_Either_u8_shapes_Point, copy$generics_Fixed_u16, copy$generics_Fixed_u8, copy$generics_Wrap_shapes_Point, copy$generics_Wrap_u8, copy$shapes_Gauge, drop$generics_Pile_generics_Ticks, drop$generics_Run_generics_Ticked } from "./lib.ts"; +import { thenSome$1ctlqen, thenSome$0bd8znh, thenSome$0czqe00, thenSome$0rdxccx, thenSome$0tbnivw, thenSome$0epplxd, thenSome$19pue01, thenSome$0quywni, thenSome$1n1oy1h, then$01xsbgy, then$0y7on52, then$1qflv5x } from "./core/bool.ts"; +import { unwrapOr$1fr498u as option_unwrapOr$1fr498u, unwrapOrDefault$0w7995p as option_unwrapOrDefault$0w7995p, unwrapOrDefault$03apme8 as option_unwrapOrDefault$03apme8, map$00jdj9f as option_map$00jdj9f, map$0xoixq7 as option_map$0xoixq7, map$0983ug4 as option_map$0983ug4, map$14wqhyc as option_map$14wqhyc, map$04m4r6n as option_map$04m4r6n, map$1ug09xc as option_map$1ug09xc, map$1747o3c as option_map$1747o3c, map$1mvacy3 as option_map$1mvacy3, map$1es1113 as option_map$1es1113, map$1ub01y7 as option_map$1ub01y7, map$1a3j889 as option_map$1a3j889, map$1avgfgw as option_map$1avgfgw, map$0e9v36n as option_map$0e9v36n, map$1i2swnz as option_map$1i2swnz, map$0ggarad as option_map$0ggarad, map$132wgz4 as option_map$132wgz4, map$1olalbb as option_map$1olalbb, map$1htvaju as option_map$1htvaju, map$0xpm57l as option_map$0xpm57l, map$1yjmt5m as option_map$1yjmt5m, map$0ydco3f as option_map$0ydco3f, map$057a36e as option_map$057a36e, asDeref$10lhnlx as option_asDeref$10lhnlx, asDeref$1z13rqi as option_asDeref$1z13rqi, andThen$0jij6xn as option_andThen$0jij6xn } from "./core/option.ts"; import { eq$1qrb1lw as poll_eq$1qrb1lw, isPending$07fnw8g, isPending$1imonrp, isPending$189w6zf, isPending$1yqrsts } from "./core/task/poll.ts"; import type * as Pair from "./fmt.Pair.ts"; +import * as Ahead from "./generics.Ahead.ts"; +import type * as Back from "./generics.Back.ts"; +import * as Batch from "./generics.Batch.ts"; +import * as Branch from "./generics.Branch.ts"; +import * as Carried from "./generics.Carried.ts"; +import * as Chain from "./generics.Chain.ts"; +import type * as Copse from "./generics.Copse.ts"; +import * as Counted from "./generics.Counted.ts"; +import * as Deep from "./generics.Deep.ts"; +import * as Defaulted from "./generics.Defaulted.ts"; +import type * as Depth from "./generics.Depth.ts"; +import * as Drained from "./generics.Drained.ts"; import * as Either from "./generics.Either.ts"; +import * as Even from "./generics.Even.ts"; import * as Fixed from "./generics.Fixed.ts"; +import type * as Flags from "./generics.Flags.ts"; +import * as Forked from "./generics.Forked.ts"; +import * as Ghost from "./generics.Ghost.ts"; +import type * as Grove from "./generics.Grove.ts"; +import type * as Head from "./generics.Head.ts"; +import * as Holder from "./generics.Holder.ts"; +import * as Kept from "./generics.Kept.ts"; +import * as Layer from "./generics.Layer.ts"; import type * as Lends from "./generics.Lends.ts"; +import type * as Lent from "./generics.Lent.ts"; +import type * as Linked from "./generics.Linked.ts"; +import type * as Looped from "./generics.Looped.ts"; +import type * as Marked from "./generics.Marked.ts"; +import * as Node from "./generics.Node.ts"; +import * as Odd from "./generics.Odd.ts"; import * as Parked from "./generics.Parked.ts"; +import type * as Paths from "./generics.Paths.ts"; +import type * as Peel from "./generics.Peel.ts"; +import * as Pile from "./generics.Pile.ts"; +import * as Ping from "./generics.Ping.ts"; +import type * as Pong from "./generics.Pong.ts"; +import type * as Rally from "./generics.Rally.ts"; +import type * as Remade from "./generics.Remade.ts"; import * as Run from "./generics.Run.ts"; import * as Runs from "./generics.Runs.ts"; +import type * as Seed from "./generics.Seed.ts"; +import * as Shoot from "./generics.Shoot.ts"; +import * as Sibling from "./generics.Sibling.ts"; +import * as generics_Slot from "./generics.Slot.ts"; +import type * as Sprout from "./generics.Sprout.ts"; +import * as Swap from "./generics.Swap.ts"; import * as Tagged from "./generics.Tagged.ts"; +import type * as Tail from "./generics.Tail.ts"; import * as Ticked from "./generics.Ticked.ts"; +import type * as Ticks from "./generics.Ticks.ts"; +import type * as Top from "./generics.Top.ts"; +import * as Tree from "./generics.Tree.ts"; +import * as Twig from "./generics.Twig.ts"; +import type * as Uninit from "./generics.Uninit.ts"; +import * as generics_Wide from "./generics.Wide.ts"; import * as Wrap from "./generics.Wrap.ts"; import { put } from "./harness.ts"; import * as shapes_Gauge from "./shapes.Gauge.ts"; @@ -386,4 +433,504 @@ export function units(data: rs.ByteSlice, out: rs.ByteVec): void { put(out, rs.fmtFormat([args12[0], " ", args12[1], " ", args12[2], " ", args12[3]]).v); } +/** + * Generic types whose fields are typed by an associated type of their parameters, at + * arrays of bytes, of `u16`s, of `()`, whose `None` is `rs.None`, and of `Option`s, + * and at a store that is no array. + */ +export function projections(data: rs.ByteSlice, out: rs.ByteVec): void { + let _428!: rs.u8; + const items: rs.ByteVec = rs.iterToByteVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (b3: rs.u8): rs.u8 => { + return b3; + }), undefined, true); + const drain: Drained.Drained = Drained.new$array4_u8(((b4: rs.u8): rs.u8 => { + return b4; + })(90), rs.byteVecSlice(items)); + let count: rs.usize = 0; + while (Drained.next$array4_u8(drain) !== undefined) { + count = rs.usizeAdd(count, 1); + } + const _21: rs.u8 = ((b5: rs.u8): rs.u8 => { + return b5; + })(1); + const part = rs.usizeDiv(items.length, 2); + const batch: Batch.Batch = new Batch.Batch(Drained.new$array4_u8(_21, rs.byteSliceRange(rs.byteVecSlice(items), part)), 0); + const half: rs.u8 | undefined = Batch.take$array4_u8(batch); + const _46: rs.usize = count; + const arg = drain.last; + const _49: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg, f, rs.u8Debug); + const arg2 = drain.first; + const _50: rs.Fmt = (f: rs.Formatter) => rs.u8Debug(arg2, f); + const _51: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(_46, f); + const _52: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(4, f); + const _53: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(half, f, rs.u8Debug); + const arg3 = batch.drain.last; + const _54: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg3, f, rs.u8Debug); + const arg4 = batch.taken; + const args19 = [_49, _50, _51, _52, _53, _54, (f: rs.Formatter) => rs.u8Display(arg4, f)]; + put(out, rs.fmtFormat([args19[0], " ", args19[1], " ", args19[2], " ", args19[3], " ", args19[4], " ", args19[5], " ", args19[6]]).v); + const items2: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (b6: rs.u8): rs.u16 => { + return rs.u16Mul(b6 as rs.u16, 257); + }), undefined, 2, true); + const drain2: Drained.Drained = Drained.new$array2_u16(((b7: rs.u8): rs.u16 => { + return rs.u16Mul(b7 as rs.u16, 257); + })(90), rs.sliceFrom(items2.items)); + let count2: rs.usize = 0; + while (Drained.next$array2_u16(drain2) !== undefined) { + count2 = rs.usizeAdd(count2, 1); + } + const _76: rs.u16 = ((b8: rs.u8): rs.u16 => { + return rs.u16Mul(b8 as rs.u16, 257); + })(1); + const part2 = rs.usizeDiv(items2.items.length, 2); + const batch2: Batch.Batch = new Batch.Batch(Drained.new$array2_u16(_76, rs.sliceRange(rs.sliceFrom(items2.items), part2)), 0); + const half2: rs.u16 | undefined = Batch.take$array2_u16(batch2); + const _101: rs.usize = count2; + const arg5 = drain2.last; + const _104: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg5, f, rs.u16Debug); + const arg6 = drain2.first; + const _105: rs.Fmt = (f: rs.Formatter) => rs.u16Debug(arg6, f); + const _106: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(_101, f); + const _107: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(2, f); + const _108: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(half2, f, rs.u16Debug); + const arg7 = batch2.drain.last; + const _109: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg7, f, rs.u16Debug); + const arg8 = batch2.taken; + const args20 = [_104, _105, _106, _107, _108, _109, (f: rs.Formatter) => rs.u8Display(arg8, f)]; + put(out, rs.fmtFormat([args20[0], " ", args20[1], " ", args20[2], " ", args20[3], " ", args20[4], " ", args20[5], " ", args20[6]]).v); + const items3: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (_2: rs.u8): undefined => {}), undefined, 0, true); + ((_26: rs.u8): undefined => {})(90); + const drain3: Drained.Drained = Drained.new$array3_unit(undefined, rs.sliceFrom(items3.items)); + let count3: rs.usize = 0; + while (Drained.next$array3_unit(drain3) !== rs.None) { + count3 = rs.usizeAdd(count3, 1); + } + ((_210: rs.u8): undefined => {})(1); + const part3 = rs.usizeDiv(items3.items.length, 2); + const batch3: Batch.Batch = new Batch.Batch(Drained.new$array3_unit(undefined, rs.sliceRange(rs.sliceFrom(items3.items), part3)), 0); + const half3: undefined | rs.None = Batch.take$array3_unit(batch3); + const _156: rs.usize = count3; + const arg9 = drain3.last; + const _159: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg9, f, rs.fmtUnit, rs.None); + const _160: rs.Fmt = (f: rs.Formatter) => rs.fmtUnit(undefined, f); + const _161: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(_156, f); + const _162: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(3, f); + const _163: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(half3, f, rs.fmtUnit, rs.None); + const arg10 = batch3.drain.last; + const _164: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg10, f, rs.fmtUnit, rs.None); + const arg11 = batch3.taken; + const args21 = [_159, _160, _161, _162, _163, _164, (f: rs.Formatter) => rs.u8Display(arg11, f)]; + put(out, rs.fmtFormat([args21[0], " ", args21[1], " ", args21[2], " ", args21[3], " ", args21[4], " ", args21[5], " ", args21[6]]).v); + const items4: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (b9: rs.u8): rs.u8 | undefined => { + return thenSome$0quywni(rs.u8Rem(b9, 3) !== 0, b9); + }), undefined, 2, true); + const drain4: Drained.Drained, rs.u8 | undefined> = Drained.new$array1_Option_u8(((b10: rs.u8): rs.u8 | undefined => { + return thenSome$0quywni(rs.u8Rem(b10, 3) !== 0, b10); + })(90), rs.sliceFrom(items4.items)); + let count4: rs.usize = 0; + while (Drained.next$array1_Option_u8(drain4) !== rs.None) { + count4 = rs.usizeAdd(count4, 1); + } + const _186: rs.u8 | undefined = ((b11: rs.u8): rs.u8 | undefined => { + return thenSome$0quywni(rs.u8Rem(b11, 3) !== 0, b11); + })(1); + const part4 = rs.usizeDiv(items4.items.length, 2); + const batch4: Batch.Batch, rs.u8 | undefined> = new Batch.Batch(Drained.new$array1_Option_u8(_186, rs.sliceRange(rs.sliceFrom(items4.items), part4)), 0); + const half4: rs.u8 | undefined | rs.None = Batch.take$array1_Option_u8(batch4); + const _211: rs.usize = count4; + const arg12 = drain4.last; + const _214: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg12, f, (value: rs.u8 | undefined, f: rs.Formatter) => rs.fmtOption(value, f, rs.u8Debug), rs.None); + const arg13 = drain4.first; + const _215: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg13, f, rs.u8Debug); + const _216: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(_211, f); + const _217: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(1, f); + const _218: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(half4, f, (value: rs.u8 | undefined, f: rs.Formatter) => rs.fmtOption(value, f, rs.u8Debug), rs.None); + const arg14 = batch4.drain.last; + const _219: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg14, f, (value: rs.u8 | undefined, f: rs.Formatter) => rs.fmtOption(value, f, rs.u8Debug), rs.None); + const arg15 = batch4.taken; + const args22 = [_214, _215, _216, _217, _218, _219, (f: rs.Formatter) => rs.u8Display(arg15, f)]; + put(out, rs.fmtFormat([args22[0], " ", args22[1], " ", args22[2], " ", args22[3], " ", args22[4], " ", args22[5], " ", args22[6]]).v); + const items5: rs.Vec = rs.iterToVec(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (b12: rs.u8): boolean => { + return (b12 & 1) !== 0; + }), undefined, 1, true); + const drain5: Drained.Drained = Drained.new$generics_Flags(((b13: rs.u8): boolean => { + return (b13 & 1) !== 0; + })(90), rs.sliceFrom(items5.items)); + let count5: rs.usize = 0; + while (Drained.next$generics_Flags(drain5) !== undefined) { + count5 = rs.usizeAdd(count5, 1); + } + const _241: boolean = ((b14: rs.u8): boolean => { + return (b14 & 1) !== 0; + })(1); + const part5 = rs.usizeDiv(items5.items.length, 2); + const batch5: Batch.Batch = new Batch.Batch(Drained.new$generics_Flags(_241, rs.sliceRange(rs.sliceFrom(items5.items), part5)), 0); + const half5: boolean | undefined = Batch.take$generics_Flags(batch5); + const _266: rs.usize = count5; + const arg16 = drain5.last; + const _269: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg16, f, rs.fmtBool); + const arg17 = drain5.first; + const _270: rs.Fmt = (f: rs.Formatter) => rs.fmtBool(arg17, f); + const _271: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(_266, f); + const _272: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(8, f); + const _273: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(half5, f, rs.fmtBool); + const arg18 = batch5.drain.last; + const _274: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg18, f, rs.fmtBool); + const arg19 = batch5.taken; + const args23 = [_269, _270, _271, _272, _273, _274, (f: rs.Formatter) => rs.u8Display(arg19, f)]; + put(out, rs.fmtFormat([args23[0], " ", args23[1], " ", args23[2], " ", args23[3], " ", args23[4], " ", args23[5], " ", args23[6]]).v); + const ahead: Ahead.Ahead, rs.u8, boolean> = new Ahead.Ahead(rs.iterPeekable(rs.iterSlice(rs.byteSliceView(data))), new rs.Vec(), option_map$132wgz4(rs.byteSliceFirst(data), (b15: rs.u8): boolean => { + return (b15 & 2) !== 0; + }) as rs.OptionOf); + const repeats: rs.usize = Ahead.repeats$generics_Flags_slice_Iter_u8(ahead); + const part6 = ahead.seen as rs.Vec; + const _297: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(repeats, f); + const _298: rs.Fmt = (f: rs.Formatter) => rs.fmtList(part6.items, f, rs.u8Debug); + const arg20 = ahead.stored; + const args24 = [_297, _298, (f: rs.Formatter) => rs.fmtOption(arg20, f, rs.fmtBool)]; + put(out, rs.fmtFormat([args24[0], " ", args24[1], " ", args24[2]]).v); + const ahead2: Ahead.Ahead, rs.u8, rs.u16> = new Ahead.Ahead(rs.iterPeekable(rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (b16: rs.u8): rs.u8 => { + return rs.u8Rem(b16, 4); + })), new rs.ByteVec(), option_map$0ydco3f(rs.byteSliceLast(data), (_212: rs.u8): rs.u16 => { + return _212 as rs.u16; + }) as rs.OptionOf); + const repeats2: rs.usize = Ahead.repeats$array1_u16_iter_Map_slice_Iter_u8_generics_projections_closure1(ahead2); + const part7 = ahead2.seen as rs.ByteVec; + const _322: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(repeats2, f); + const _323: rs.Fmt = (f: rs.Formatter) => rs.fmtList(rs.byteVecView(part7), f, rs.u8Debug); + const arg21 = ahead2.stored; + const args25 = [_322, _323, (f: rs.Formatter) => rs.fmtOption(arg21, f, rs.u16Debug)]; + put(out, rs.fmtFormat([args25[0], " ", args25[1], " ", args25[2]]).v); + let pile: Pile.Pile = { tag: "Empty" }; + let flags: Pile.Pile = { tag: "Empty" }; + for (const b of rs.byteSliceView(data)) { + pile = Pile.push$array2_u8(pile, b); + flags = Pile.push$generics_Flags(flags, b > 127); + } + const _342: [rs.ByteVec, rs.Vec] = [new rs.ByteVec(), new rs.Vec()]; + const bytes: rs.ByteVec = _342[0]; + const bits: rs.Vec = _342[1]; + Pile.items$array2_u8(pile, bytes); + Pile.items$generics_Flags(flags, bits); + const args26 = [(f: rs.Formatter) => rs.fmtList(rs.byteVecView(bytes), f, rs.u8Debug), (f: rs.Formatter) => rs.fmtList(bits.items, f, rs.fmtBool)]; + put(out, rs.fmtFormat([args26[0], " ", args26[1]]).v); + const deep: Deep.Deep = Deep.new$array3_array2_u8(rs.byteSliceFirst(data)); + const units: Deep.Deep = Deep.new$array4_array2_unit(option_map$057a36e(rs.byteSliceGet(data, 1), (_213: rs.u8): undefined => {})); + const arg22 = deep.inner; + const _383: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg22, f, rs.u8Debug); + const arg23 = deep.len; + const _384: rs.Fmt = (f: rs.Formatter) => rs.usizeDisplay(arg23, f); + const arg24 = units.inner; + const _385: rs.Fmt = (f: rs.Formatter) => rs.fmtOption(arg24, f, rs.fmtUnit, rs.None); + const arg25 = units.len; + const args27 = [_383, _384, _385, (f: rs.Formatter) => rs.usizeDisplay(arg25, f)]; + put(out, rs.fmtFormat([args27[0], " ", args27[1], " ", args27[2], " ", args27[3]]).v); + const log: rs.Arc> = new rs.Arc(new rs.RefCell(new rs.ByteVec())); + const tick: (a0: rs.u8) => Ticked.Ticked = (id2: rs.u8): Ticked.Ticked => { + return new Ticked.Ticked(id2, rs.arcClone(log)); + }; + for (const b2 of rs.byteSliceView(data)) { + new Kept.Kept(tick(b2), {}, rs.vecFrom([tick(b2 ^ 1), tick(b2 ^ 2)]), then$1qflv5x(rs.u8Rem(b2, 2) === 0, (): Ticked.Ticked => { + return tick(b2 ^ 3); + }) as rs.OptionOf)[Symbol.dispose](); + let ticks: Pile.Pile = { tag: "Empty" }; + const _425: rs.u8 = rs.u8Rem(b2, 3); + let iterStart: rs.u8 = 0; + const iterEnd: rs.u8 = _425; + while ((_428 = iterStart++) < iterEnd) { + ticks = { tag: "Linked", item: tick(_428), next: ticks } as Pile.Pile; + } + const _441: rs.RefCell = rs.refCellBorrowMut(log.value); + rs.byteVecPush(_441.value, 254); + rs.refMutRelease(_441); + drop$generics_Pile_generics_Ticks(ticks); + const _447: Uint8Array = Uint8Array.of(b2); + const _448: rs.ByteVec = rs.byteVecFrom(Uint8Array.of(b2)); + const kept2: Kept.Kept = new Kept.Kept(b2, _447, _448, undefined as rs.OptionOf); + const _454: rs.RefCell = rs.refCellBorrowMut(log.value); + const _458: rs.u8 = kept2.item; + const _459: rs.u8 = kept2.store[0]; + const slice6 = kept2.rest as rs.ByteVec; + rs.iterExtendBytes(_454.value, rs.iterSlice(Uint8Array.of(_458, _459, slice6.data[rs.idx(slice6, 0)])), undefined, true); + rs.refMutRelease(_454); + const owner: Ticked.Ticked = tick(b2 ^ 4); + const _472: rs.Vec = rs.vecFrom([owner]); + const _475: Ticked.Ticked | undefined = thenSome$0tbnivw(rs.u8Rem(b2, 2) === 1, owner); + const lent: rs.Arc> = new rs.Arc(new Kept.Kept(owner, { _0: undefined }, _472, _475 as rs.OptionOf)); + const _483: rs.RefCell = rs.refCellBorrowMut(log.value); + rs.byteVecPush(_483.value, lent.value.item.id); + rs.refMutRelease(_483); + rs.arcDrop(lent); + const _493: rs.RefCell = rs.refCellBorrowMut(log.value); + rs.byteVecPush(_493.value, 253); + rs.refMutRelease(_493); + owner[Symbol.dispose](); + } + const marked: Marked.Marked = { marker: undefined, maybe: undefined, count: data.length & 0xff }; + const bytes2: Marked.Marked = { marker: undefined, maybe: undefined, count: ~marked.count & 0xff }; + const _506: rs.RefCell = rs.refCellBorrowMut(log.value); + rs.iterExtendBytes(_506.value, rs.iterSlice(Uint8Array.of(marked.count, bytes2.count)), undefined, true); + rs.refMutRelease(_506); + const _517: rs.RefCell = rs.refCellBorrow(log.value); + rs.iterExtendBytes(out, rs.iterSlice(rs.byteSliceView(rs.byteVecSlice(_517.value))), undefined, true); + rs.refRelease(_517); + log[Symbol.dispose](); +} + +/** Types typed with themselves, or with each other, that name projections. */ +export function projectedCycles(data: rs.ByteSlice, out: rs.ByteVec): void { + const tree: Tree.Tree = rs.iterFold(rs.byteSliceChunks(data, 2), new Tree.Tree(new rs.Vec()), (below: Tree.Tree, chunk: rs.ByteSlice): Tree.Tree => { + return new Tree.Tree(rs.iterToVec(rs.iterChain(rs.iterMap(rs.iterSlice(rs.byteSliceView(chunk)), (_2: rs.u8): Branch.Branch => { + return new Branch.Branch(_2, undefined); + }), rs.iterSlice([new Branch.Branch(255, below)])), undefined, 8, true)); + }); + const items: rs.ByteVec = new rs.ByteVec(); + Tree.items$array1_u8(tree, items); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(items), f, rs.u8Debug)]).v); + const seen: rs.Iter = rs.iterMap(rs.iterSlice(rs.byteSliceView(data)), (b3: rs.u8): rs.u8 => { + return rs.u8Rem(b3, 5); + }); + let even: Even.Even, boolean, rs.u8> = { tag: "End" }; + const iter: rs.Iter = rs.iterRev(rs.iterSlice(rs.byteSliceView(data))); + while (true) { + const _30: rs.u8 | rs.Done = iter.next(); + if (_30 === rs.DONE) { + break; + } + even = { tag: "Next", _0: (_30 & 1) !== 0, _1: new Odd.Odd(rs.iterToOption(seen.next()) as rs.OptionOf, even) } as Even.Even, boolean, rs.u8>; + } + const walked: rs.String = rs.stringNew(); + Even.walk$generics_Flags_vec_IntoIter_u8(even, walked); + put(out, walked.v); + let swap: Swap.Swap | undefined = undefined; + const iter2: rs.Iter<[rs.usize, rs.u8]> = rs.iterRev(rs.iterEnumerate(rs.iterSlice(rs.byteSliceView(data)))); + while (true) { + const _55: [rs.usize, rs.u8] | rs.Done = iter2.next(); + if (_55 === rs.DONE) { + break; + } + const i: rs.usize = _55[0]; + const b2: rs.u8 = _55[1]; + const _61: boolean = b2 > 64; + const _63: rs.Place | undefined> = rs.place(() => swap, (value) => swap = value); + const taken = _63.v; + _63.v = undefined; + const inner: Swap.Swap = new Swap.Swap(_61, taken); + if (rs.usizeRem(i, 2) === 0) { + swap = new Swap.Swap(((b2 as rs.u16) << 4) & 0xffff, inner); + } + } + const shown: rs.String = rs.stringNew(); + const _78: Swap.Swap | undefined = swap; + if (_78 !== undefined) { + Swap.show$array1_u16_generics_Flags(_78, shown); + } + put(out, shown.v); + const arg = new Ghost.Ghost(option_map$057a36e(rs.byteSliceFirst(data), (_23: rs.u8): undefined => {}), undefined).item; + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtOption(arg, f, rs.fmtUnit, rs.None)]).v); +} + +/** + * Types whose projections hold their instances again, directly or through each other, as + * structs and enums, and a type whose two projections each name the next of 25 instances, + * the last holding the first again, which an alias per instance names once rather than + * once per path. + */ +export function projectedSelves(data: rs.ByteSlice, out: rs.ByteVec): void { + let grove!: Grove.Grove; + let copse!: Copse.Copse; + let grown!: [rs.u8, boolean | undefined]; + let sown!: [rs.u8, boolean | undefined]; + let _302!: Pong.Pong; + const log: rs.Arc> = new rs.Arc(new rs.RefCell(new rs.ByteVec())); + const tick: (a0: rs.u8) => Ticked.Ticked = (id: rs.u8): Ticked.Ticked => { + return new Ticked.Ticked(id, rs.arcClone(log)); + }; + let held: Carried.Carried | undefined = undefined; + for (const _11 of rs.byteSliceView(data)) { + held = new Carried.Carried(tick(_11), option_map$00jdj9f(held, (a0: Carried.Carried): Carried.Carried => { + return a0; + }) as rs.OptionOf); + } + let depth: rs.u8 = 0; + let at: Carried.Carried | undefined = held; + while (at !== undefined) { + const next: Carried.Carried = at; + depth = rs.u8Add(depth, 1); + at = option_asDeref$10lhnlx(next.next); + } + const _33: rs.RefCell = rs.refCellBorrowMut(log.value); + rs.byteVecPush(_33.value, depth); + rs.refMutRelease(_33); + rs.drop(held); + const chain: Chain.Chain = rs.iterFold(rs.iterRev(rs.iterSlice(rs.byteSliceView(data))), { tag: "End" } as Chain.Chain, (next3: Chain.Chain, _32: rs.u8): Chain.Chain => { + return { tag: "Link", _0: _32, _1: next3 } as Chain.Chain; + }); + const ids: rs.ByteVec = new rs.ByteVec(); + Chain.ids$generics_Linked(chain, ids); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(ids), f, rs.u8Debug)]).v); + const defaulted: Defaulted.Defaulted | undefined = rs.iterFold(rs.iterSlice(rs.byteSliceView(data)), undefined as Defaulted.Defaulted | undefined, (next4: Defaulted.Defaulted | undefined, _35: rs.u8): Defaulted.Defaulted | undefined => { + return new Defaulted.Defaulted(_35, option_map$0983ug4(next4, (a02: Defaulted.Defaulted): Defaulted.Defaulted => { + return a02; + }) as rs.OptionOf); + }); + const ids2: rs.ByteVec = new rs.ByteVec(); + let at2: Defaulted.Defaulted | undefined = defaulted; + while (at2 !== undefined) { + const next2: Defaulted.Defaulted = at2; + rs.byteVecPush(ids2, next2.id); + at2 = option_asDeref$1z13rqi(next2.next); + } + const node: Node.Node = new Node.Node(data.length & 0xff, option_map$1htvaju(rs.byteSliceFirst(data), (_2: rs.u8): Node.Node => { + return new Node.Node(new Node.Node(_2, undefined), undefined); + })); + const held2: rs.u8 | undefined = option_map$1es1113(node.next, (n: Node.Node): rs.u8 => { + return n.item.item; + }); + const _91: rs.Fmt = (f: rs.Formatter) => rs.fmtList(rs.byteVecView(ids2), f, rs.u8Debug); + const arg = node.item; + const args22 = [_91, (f: rs.Formatter) => rs.u8Display(arg, f), (f: rs.Formatter) => rs.fmtOption(held2, f, rs.u8Debug)]; + put(out, rs.fmtFormat([args22[0], " ", args22[1], " ", args22[2]]).v); + const uninit: Uninit.Uninit = { slot: new generics_Slot.Slot(option_map$1yjmt5m(rs.byteSliceFirst(data), (_22: rs.u8): rs.u8 => { + return _22; + }) as rs.OptionOf) }; + const part = uninit.slot.value !== undefined; + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtBool(part, f)]).v); + const holder: Holder.Holder = Holder.new(data.length & 0xff, option_unwrapOr$1fr498u(rs.byteSliceFirst(data), 0)); + const held3: [rs.u8, rs.u8 | undefined] | undefined = option_map$14wqhyc(holder.get.holder$Get(), (h: Holder.Holder): [rs.u8, rs.u8 | undefined] => { + const _09: [rs.u8, rs.u8 | undefined] = [h.id, h.get.get$Get() as rs.u8 | undefined]; + h[Symbol.dispose](); + return _09; + }); + const _132: rs.u8 | undefined = holder.get.get$Get() as rs.u8 | undefined; + const arg2 = holder.id; + const args24 = [(f: rs.Formatter) => rs.u8Display(arg2, f), (f: rs.Formatter) => rs.fmtOption(_132, f, rs.u8Debug), (f: rs.Formatter) => rs.fmtOption(held3, f, (value: [rs.u8, rs.u8 | undefined], f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(value[0], f), (f: rs.Formatter) => rs.fmtOption(value[1], f, rs.u8Debug)], f))]; + put(out, rs.fmtFormat([args24[0], " ", args24[1], " ", args24[2]]).v); + const _143: rs.u8 | undefined = rs.byteSliceFirst(data); + const twig: Twig.Twig = new Twig.Twig(undefined, { tag: "Item", _0: 5 } as Grove.Grove); + if (_143 === undefined) { + grove = { tag: "Item", _0: data.length & 0xff } as Grove.Grove; + } else { + const b2: rs.u8 = _143; + grove = { tag: "Branch", _0: new Twig.Twig(thenSome$0epplxd(rs.u8Rem(b2, 2) === 0, twig), b2) } as Grove.Grove; + } + const _155: rs.u8 | undefined = rs.byteSliceLast(data); + const shoot: Shoot.Shoot = new Shoot.Shoot(undefined, { tag: "Item", _0: 6 } as Copse.Copse); + if (_155 === undefined) { + copse = { tag: "Item", _0: 0 } as Copse.Copse; + } else { + const b3: rs.u8 = _155; + copse = { tag: "Branch", _0: new Shoot.Shoot(thenSome$0czqe00(rs.u8Rem(b3, 2) === 1, shoot), ~b3 & 0xff) } as Copse.Copse; + } + const _165: Grove.Grove = grove; + if (_165.tag === "Branch") { + grown = [_165._0.item, option_map$1i2swnz(_165._0.next, (t: Twig.Twig): boolean => { + if (t.item.tag === "Item") { + if (t.item._0 === 5) { + return true; + } + } + return false; + })] as [rs.u8, boolean | undefined]; + } else { + grown = [_165._0, undefined] as [rs.u8, boolean | undefined]; + } + const _175: Copse.Copse = copse; + if (_175.tag === "Item") { + sown = [_175._0, undefined] as [rs.u8, boolean | undefined]; + } else { + sown = [_175._0.item, option_map$1avgfgw(_175._0.next, (s: Shoot.Shoot): boolean => { + if (s.item.tag === "Item") { + if (s.item._0 === 6) { + return true; + } + } + return false; + })] as [rs.u8, boolean | undefined]; + } + const args25 = [(f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(grown[0], f), (f: rs.Formatter) => rs.fmtOption(grown[1], f, rs.fmtBool)], f), (f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(sown[0], f), (f: rs.Formatter) => rs.fmtOption(sown[1], f, rs.fmtBool)], f)]; + put(out, rs.fmtFormat([args25[0], " ", args25[1]]).v); + const under: Layer.Layer, boolean, rs.u8> = new Layer.Layer(true, undefined); + const layer: Layer.Layer = new Layer.Layer(((option_unwrapOr$1fr498u(rs.byteSliceFirst(data), 0) as rs.u16) << 4) & 0xffff, thenSome$0bd8znh(rs.usizeRem(data.length, 2) === 1, under)); + const count: rs.u8 | undefined = option_map$04m4r6n(option_andThen$0jij6xn(rs.iterFold(rs.iterSlice(rs.byteSliceView(data)), undefined as Counted.Counted | undefined, (next5: Counted.Counted | undefined, _311: rs.u8): Counted.Counted | undefined => { + return new Counted.Counted(_311, option_map$0xoixq7(next5, (a03: Counted.Counted): Counted.Counted => { + return a03; + }) as rs.OptionOf); + }), (c: Counted.Counted): Counted.Counted | undefined => { + return c.next; + }), (c2: Counted.Counted): rs.u8 => { + return c2.id; + }); + const _228: [boolean, boolean] | undefined = option_map$1a3j889(layer.under, (u: Layer.Layer, boolean, rs.u8>): [boolean, boolean] => { + return [u.item, u.under !== undefined] as [boolean, boolean]; + }); + const arg3 = layer.item; + const args26 = [(f: rs.Formatter) => rs.u16Display(arg3, f), (f: rs.Formatter) => rs.fmtOption(_228, f, (value: [boolean, boolean], f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.fmtBool(value[0], f), (f: rs.Formatter) => rs.fmtBool(value[1], f)], f)), (f: rs.Formatter) => rs.fmtOption(count, f, rs.u8Debug)]; + put(out, rs.fmtFormat([args26[0], " ", args26[1], " ", args26[2]]).v); + const wide: generics_Wide.Wide = generics_Wide.new$u8(data.length & 0xff); + const _250: boolean = wide.next === undefined; + const arg4 = wide.a0; + const _253: rs.Fmt = (f: rs.Formatter) => rs.u8Display(arg4, f); + const arg5 = wide.a129; + const args27 = [_253, (f: rs.Formatter) => rs.u8Display(arg5, f), (f: rs.Formatter) => rs.fmtBool(_250, f)]; + put(out, rs.fmtFormat([args27[0], " ", args27[1], " ", args27[2]]).v); + const made: Sibling.Sibling, rs.u8, rs.u8> = new Sibling.Sibling(7, undefined); + const sibling: Sibling.Sibling = new Sibling.Sibling(((option_unwrapOr$1fr498u(rs.byteSliceLast(data), 0) as rs.u16) << 3) & 0xffff, thenSome$0rdxccx(rs.usizeRem(data.length, 3) === 0, made)); + const _281: [rs.u8, boolean] | undefined = option_map$0e9v36n(sibling.next, (s2: Sibling.Sibling, rs.u8, rs.u8>): [rs.u8, boolean] => { + return [s2.item, s2.next === undefined] as [rs.u8, boolean]; + }); + const arg6 = sibling.item; + const args28 = [(f: rs.Formatter) => rs.u16Display(arg6, f), (f: rs.Formatter) => rs.fmtOption(_281, f, (value: [rs.u8, boolean], f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(value[0], f), (f: rs.Formatter) => rs.fmtBool(value[1], f)], f))]; + put(out, rs.fmtFormat([args28[0], " ", args28[1]]).v); + let ping: Ping.Ping = new Ping.Ping(238, undefined as rs.OptionOf); + const iter2: rs.Iter<[rs.usize, rs.u8]> = rs.iterEnumerate(rs.iterSlice(rs.byteSliceView(data))); + while (true) { + const _294: [rs.usize, rs.u8] | rs.Done = iter2.next(); + if (_294 === rs.DONE) { + break; + } + const i: rs.usize = _294[0]; + const b4: rs.u8 = _294[1]; + if (rs.usizeRem(i, 3) === 0) { + _302 = { tag: "Miss" } as Pong.Pong; + } else { + _302 = { tag: "Hit", _0: ~b4 & 0xff, _1: ping } as Pong.Pong; + } + ping = new Ping.Ping(b4, _302 as rs.OptionOf); + } + const ids3: rs.ByteVec = new rs.ByteVec(); + Ping.ids$generics_Rally(ping, ids3); + put(out, rs.fmtFormat([(f: rs.Formatter) => rs.fmtList(rs.byteVecView(ids3), f, rs.u8Debug)]).v); + const below: Forked.Forked = new Forked.Forked(23, undefined as rs.OptionOf, new Forked.Forked(24, option_map$1olalbb(rs.byteSliceFirst(data), (_23: rs.u8): Forked.Forked => { + return new Forked.Forked(_23, undefined as rs.OptionOf, undefined as rs.OptionOf); + }) as rs.OptionOf, option_map$0xpm57l(rs.byteSliceLast(data), (_25: rs.u8): Ticked.Ticked => { + return tick(~_25 & 0xff); + }) as rs.OptionOf) as rs.OptionOf); + const fork: Forked.Forked = new Forked.Forked(0, undefined as rs.OptionOf, undefined as rs.OptionOf); + if (rs.usizeRem(data.length, 2) === 0) { + const _342: Forked.Forked | undefined = new Forked.Forked(1, undefined as rs.OptionOf, undefined as rs.OptionOf); + rs.drop(fork.left); + fork.left = _342; + } + const ids4: [rs.u8, rs.u8 | undefined, rs.u8] = [fork.id, option_map$1747o3c(fork.left, (f: Forked.Forked): rs.u8 => { + return f.id; + }), below.id]; + const right: [rs.u8, rs.u8 | undefined, rs.u8 | undefined] | undefined = option_map$1mvacy3(below.right, (f2: Forked.Forked): [rs.u8, rs.u8 | undefined, rs.u8 | undefined] => { + return [f2.id, option_map$1ug09xc(f2.left, (f3: Forked.Forked): rs.u8 => { + return f3.id; + }), option_map$1ub01y7(f2.right, (t2: Ticked.Ticked): rs.u8 => { + return t2.id; + })] as [rs.u8, rs.u8 | undefined, rs.u8 | undefined]; + }); + const args30 = [(f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(ids4[0], f), (f: rs.Formatter) => rs.fmtOption(ids4[1], f, rs.u8Debug), (f: rs.Formatter) => rs.u8Debug(ids4[2], f)], f), (f: rs.Formatter) => rs.fmtOption(right, f, (value: [rs.u8, rs.u8 | undefined, rs.u8 | undefined], f: rs.Formatter) => rs.fmtTuple([(f: rs.Formatter) => rs.u8Debug(value[0], f), (f: rs.Formatter) => rs.fmtOption(value[1], f, rs.u8Debug), (f: rs.Formatter) => rs.fmtOption(value[2], f, rs.u8Debug)], f))]; + put(out, rs.fmtFormat([args30[0], " ", args30[1]]).v); + below[Symbol.dispose](); + fork[Symbol.dispose](); + const _378: rs.RefCell = rs.refCellBorrow(log.value); + rs.iterExtendBytes(out, rs.iterSlice(rs.byteSliceView(rs.byteVecSlice(_378.value))), undefined, true); + rs.refRelease(_378); + holder[Symbol.dispose](); + log[Symbol.dispose](); +} + //# sourceMappingURL=generics.ts.map diff --git a/ts/fixtures/lang/shapes/expected/lib.ts b/ts/fixtures/lang/shapes/expected/lib.ts index 4900e09af..d32cdc7dc 100644 --- a/ts/fixtures/lang/shapes/expected/lib.ts +++ b/ts/fixtures/lang/shapes/expected/lib.ts @@ -2,11 +2,15 @@ import * as rs from "./rs.ts"; import { ints, strings, derived, written, counts, rounding, panics, wrapped, collections, enums, iters, adaptors, writes, objects, sources, sets, calls, cells, searches } from "./fmt.ts"; -import { methods, runs, units } from "./generics.ts"; +import { methods, runs, units, projections, projectedCycles, projectedSelves } from "./generics.ts"; import type * as Either from "./generics.Either.ts"; import * as Fixed from "./generics.Fixed.ts"; +import * as Getter from "./generics.Getter.ts"; +import type * as Holder from "./generics.Holder.ts"; +import type * as Pile from "./generics.Pile.ts"; import type * as Run from "./generics.Run.ts"; import type * as Ticked from "./generics.Ticked.ts"; +import type * as Ticks from "./generics.Ticks.ts"; import * as Wrap from "./generics.Wrap.ts"; import { copies, order, discriminants, loops, patterns, uninhabited, closures, library, flows } from "./shapes.ts"; import type * as shapes_Gauge from "./shapes.Gauge.ts"; @@ -137,6 +141,17 @@ export function copy$tuple2_u8_u8(v: [rs.u8, rs.u8]): [rs.u8, rs.u8] { return [v[0], v[1]]; } +export function drop$generics_Pile_generics_Ticks(_1: Pile.Pile): void { + if (_1.tag !== "Empty") { + if (_1.tag === "Full") { + _1._0[Symbol.dispose](); + } else { + _1.item[Symbol.dispose](); + drop$generics_Pile_generics_Ticks(_1.next); + } + } +} + export function drop$generics_Run_generics_Ticked(_1: Run.Run): void { if (_1.tag === "Listed") { rs.dropVec(_1._0 as rs.Vec); @@ -145,6 +160,22 @@ export function drop$generics_Run_generics_Ticked(_1: Run.Run): v } } +export class of$generics_Getter { + v: Getter.Getter; + + constructor(v: Getter.Getter) { + this.v = v; + } + + get$Get(): rs.OptionOf { + return Getter.get$generics_Get_u8(this.v) as rs.OptionOf; + } + + holder$Get(): Holder.Holder | undefined { + return Getter.holder$generics_Get_u8(this.v); + } +} + export class of$u8 { v: rs.u8; @@ -220,6 +251,12 @@ export function cases(): rs.Vec<[string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.By searches(data27, out28); }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["generics::units", (_238: rs.u8, data28: rs.ByteSlice, out29: rs.ByteVec): undefined => { units(data28, out29); + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["generics::projections", (_239: rs.u8, data29: rs.ByteSlice, out30: rs.ByteVec): undefined => { + projections(data29, out30); + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["generics::projected_cycles", (_240: rs.u8, data30: rs.ByteSlice, out31: rs.ByteVec): undefined => { + projectedCycles(data30, out31); + }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined], ["generics::projected_selves", (_241: rs.u8, data31: rs.ByteSlice, out32: rs.ByteVec): undefined => { + projectedSelves(data31, out32); }] as [string, (a0: rs.u8, a1: rs.ByteSlice, a2: rs.ByteVec) => undefined]]); } diff --git a/ts/fixtures/lang/shapes/expected/shapes.ts b/ts/fixtures/lang/shapes/expected/shapes.ts index 358fe7c80..2ff0e920f 100644 --- a/ts/fixtures/lang/shapes/expected/shapes.ts +++ b/ts/fixtures/lang/shapes/expected/shapes.ts @@ -23,7 +23,7 @@ import type * as Parts from "./shapes.Parts.ts"; import * as Point from "./shapes.Point.ts"; import * as Shape from "./shapes.Shape.ts"; import type * as Signed from "./shapes.Signed.ts"; -import type * as Slot from "./shapes.Slot.ts"; +import type * as shapes_Slot from "./shapes.Slot.ts"; import * as Track from "./shapes.Track.ts"; import * as Void from "./shapes.Void.ts"; import type * as shapes_Wide from "./shapes.Wide.ts"; @@ -1435,7 +1435,7 @@ export function payloads(_dataData: Uint8Array, _dataStart: number, dataLen: num } const part2: rs.u8 | undefined = parity(rs.u8WrappingAdd(n, 1)); const err2: rs.u8 | undefined = part2 === undefined ? out$u8.err as rs.u8 : undefined; - const slot: Slot.Slot = { res: (err2 !== undefined ? rs.Err(err2 as rs.u8) : rs.Ok(part2 as rs.u8)) as rs.Result }; + const slot: shapes_Slot.Slot = { res: (err2 !== undefined ? rs.Err(err2 as rs.u8) : rs.Ok(part2 as rs.u8)) as rs.Result }; if (!slot.res.ok) { const _33: rs.u8 = rs.u8WrappingSub(slot.res.error, 4); slot.res = { ok: false, error: _33 }; diff --git a/ts/fixtures/lang/shapes/src/generics.rs b/ts/fixtures/lang/shapes/src/generics.rs index 442327807..0b2214719 100644 --- a/ts/fixtures/lang/shapes/src/generics.rs +++ b/ts/fixtures/lang/shapes/src/generics.rs @@ -461,3 +461,1001 @@ pub fn units(data: &[u8], out: &mut Vec) { parked_at!(data, out, [Poll::Pending, Poll::Ready(1u8)]); parked_at!(data, out, [3u8, 4]); } + +/// What a fixed buffer holds, as smallvec's `Array` names its arrays' items. +pub trait Store { + type Item; + const LEN: usize; +} + +impl Store for [T; N] { + type Item = T; + const LEN: usize = N; +} + +/// A store of flags, whose items are no array's. +struct Flags; + +impl Store for Flags { + type Item = bool; + const LEN: usize = 8; +} + +/// A drain over a store's items, as smallvec's `Drain` holds `::Item`s: +/// directly, in an `Option`, whose `None` each instance decides, and through a slice's +/// iterator. +struct Drained<'a, S: Store> { + last: Option, + iter: std::slice::Iter<'a, S::Item>, + first: S::Item, +} + +impl<'a, S: Store> Drained<'a, S> +where + S::Item: Copy, +{ + fn new(first: S::Item, items: &'a [S::Item]) -> Self { + Self { + last: None, + iter: items.iter(), + first, + } + } + + fn next(&mut self) -> Option { + let item = *self.iter.next()?; + self.last = Some(item); + Some(item) + } +} + +/// A [`Drained`] in another generic type, which names the projection only through it. +struct Batch<'a, S: Store> { + drain: Drained<'a, S>, + taken: u8, +} + +impl Batch<'_, S> +where + S::Item: Copy, +{ + fn take(&mut self) -> Option { + let item = self.drain.next()?; + self.taken = self.taken.wrapping_add(1); + Some(item) + } +} + +/// A std iterator's items, which only its `Iterator` impl names, beside the same +/// projection named again; a parameter named for an associated type, so each projection's +/// name is numbered past it. +struct Ahead { + iter: std::iter::Peekable, + seen: Vec, + stored: Option, +} + +impl Ahead +where + I::Item: Copy + PartialEq, +{ + /// Takes each item that repeats the one before it. + fn repeats(&mut self) -> usize { + while let Some(item) = self.iter.next() { + if self.iter.peek() == Some(&item) { + self.seen.push(item); + } + } + self.seen.len() + } +} + +/// A projection in an enum's variants, and in a type that holds itself. +enum Pile { + Empty, + Full(S::Item), + Linked { item: S::Item, next: Box> }, +} + +impl Pile +where + S::Item: Copy, +{ + fn push(self, item: S::Item) -> Self { + match self { + Pile::Empty => Pile::Full(item), + next => Pile::Linked { + item, + next: Box::new(next), + }, + } + } + + fn items(&self, out: &mut Vec) { + match self { + Pile::Empty => {} + Pile::Full(item) => out.push(*item), + Pile::Linked { item, next } => { + out.push(*item); + next.items(out); + } + } + } +} + +/// A projection from a projection, which is one parameter whole. +struct Deep +where + S::Item: Store, +{ + inner: Option<::Item>, + len: usize, +} + +impl Deep +where + S::Item: Store, +{ + fn new(inner: Option<::Item>) -> Self { + Self { + inner, + len: S::LEN * ::LEN, + } + } +} + +/// A store of [`Ticked`]s, which drops nothing itself. +struct Ticks; + +impl Store for Ticks { + type Item = Ticked; + const LEN: usize = 1; +} + +/// Items that drop beside the store that names them, which drops nothing, so only the +/// items' type decides whether and how each instance drops. +struct Kept { + item: S::Item, + store: S, + rest: Vec, + maybe: Option, +} + +/// A store that lends [`Ticked`]s, whose items drop nothing. +struct Lent<'a>(std::marker::PhantomData<&'a ()>); + +impl<'a> Store for Lent<'a> { + type Item = &'a Ticked; + const LEN: usize = 1; +} + +/// A store of what translation types no other way, which only a `PhantomData` names. +struct Paths; + +impl Store for Paths { + type Item = std::path::PathBuf; + const LEN: usize = 0; +} + +/// A projection that only a `PhantomData` holds, which types nothing, in an `Option` too. +struct Marked { + marker: std::marker::PhantomData, + maybe: std::marker::PhantomData>, + count: u8, +} + +/// [`Drained`] and [`Batch`] of `$store`, of the items `$item` makes of each byte. +macro_rules! drained_at { + ($data:expr, $out:expr, $store:ty, $item:expr) => {{ + let items: Vec<<$store as Store>::Item> = $data.iter().map($item).collect(); + let mut drain = Drained::<$store>::new($item(&0x5a), &items); + let mut count = 0usize; + while drain.next().is_some() { + count += 1; + } + let mut batch = Batch { + drain: Drained::<$store>::new($item(&1), &items[items.len() / 2..]), + taken: 0, + }; + let half = batch.take(); + put( + $out, + &format!( + "{:?} {:?} {count} {} {half:?} {:?} {}", + drain.last, + drain.first, + <$store>::LEN, + batch.drain.last, + batch.taken + ), + ); + }}; +} + +/// Generic types whose fields are typed by an associated type of their parameters, at +/// arrays of bytes, of `u16`s, of `()`, whose `None` is `rs.None`, and of `Option`s, +/// and at a store that is no array. +pub fn projections(data: &[u8], out: &mut Vec) { + drained_at!(data, out, [u8; 4], |b: &u8| *b); + drained_at!(data, out, [u16; 2], |b: &u8| u16::from(*b) * 257); + drained_at!(data, out, [(); 3], |_: &u8| ()); + drained_at!(data, out, [Option; 1], |b: &u8| (b % 3 != 0).then_some(*b)); + drained_at!(data, out, Flags, |b: &u8| b & 1 != 0); + + let mut ahead = Ahead:: { + iter: data.iter().peekable(), + seen: Vec::new(), + stored: data.first().map(|b| b & 2 != 0), + }; + let repeats = ahead.repeats(); + put(out, &format!("{repeats} {:?} {:?}", ahead.seen, ahead.stored)); + let mut ahead = Ahead::<[u16; 1], _> { + iter: data.iter().map(|b| b % 4).peekable(), + seen: Vec::new(), + stored: data.last().map(|&b| u16::from(b)), + }; + let repeats = ahead.repeats(); + put(out, &format!("{repeats} {:?} {:?}", ahead.seen, ahead.stored)); + + let mut pile = Pile::<[u8; 2]>::Empty; + let mut flags = Pile::::Empty; + for &b in data { + pile = pile.push(b); + flags = flags.push(b > 0x7f); + } + let (mut bytes, mut bits) = (Vec::new(), Vec::new()); + pile.items(&mut bytes); + flags.items(&mut bits); + put(out, &format!("{bytes:?} {bits:?}")); + + let deep = Deep::<[[u8; 2]; 3]>::new(data.first().copied()); + let units = Deep::<[[(); 2]; 4]>::new(data.get(1).map(|_| ())); + put( + out, + &format!("{:?} {} {:?} {}", deep.inner, deep.len, units.inner, units.len), + ); + + let log = Rc::new(RefCell::new(Vec::new())); + let tick = |id: u8| Ticked { id, log: log.clone() }; + for &b in data { + let kept = Kept:: { + item: tick(b), + store: Ticks, + rest: vec![tick(b ^ 1), tick(b ^ 2)], + maybe: (b % 2 == 0).then(|| tick(b ^ 3)), + }; + drop(kept); + let mut ticks = Pile::::Empty; + for id in 0..b % 3 { + ticks = Pile::Linked { + item: tick(id), + next: Box::new(ticks), + }; + } + log.borrow_mut().push(0xfe); + drop(ticks); + let kept = Kept::<[u8; 1]> { + item: b, + store: [b], + rest: vec![b], + maybe: None, + }; + log.borrow_mut().extend([kept.item, kept.store[0], kept.rest[0]]); + // What lends its items drops none of them, behind an `Rc` too. + let owner = tick(b ^ 4); + let lent = Rc::new(Kept::> { + item: &owner, + store: Lent(std::marker::PhantomData), + rest: vec![&owner], + maybe: (b % 2 == 1).then_some(&owner), + }); + log.borrow_mut().push(lent.item.id); + drop(lent); + log.borrow_mut().push(0xfd); + drop(owner); + } + let marked = Marked:: { + marker: std::marker::PhantomData, + maybe: std::marker::PhantomData, + count: data.len() as u8, + }; + let bytes = Marked::<[u8; 2]> { + marker: std::marker::PhantomData, + maybe: std::marker::PhantomData, + count: !marked.count, + }; + log.borrow_mut().extend([marked.count, bytes.count]); + out.extend(log.borrow().iter()); +} + +/// One branch of a [`Tree`], whose projection only the tree's other type names, typed with +/// it, so each learns its projections from the other. +struct Branch { + item: S::Item, + below: Option>>, +} + +/// Branches that each may hold a tree again. +struct Tree { + branches: Vec>, +} + +impl Tree +where + S::Item: Copy, +{ + fn items(&self, out: &mut Vec) { + for branch in &self.branches { + out.push(branch.item); + if let Some(below) = &branch.below { + below.items(out); + } + } + } +} + +/// Two types typed with each other, each naming a projection the other doesn't, so each +/// takes both, in the order it named them. +enum Even { + End, + Next(S::Item, Box>), +} + +struct Odd { + seen: Option, + next: Even, +} + +impl Even +where + S::Item: Copy + std::fmt::Debug, + I::Item: Copy + std::fmt::Debug, +{ + fn walk(&self, out: &mut String) { + if let Even::Next(item, odd) = self { + out.push_str(&format!("{item:?} {:?} ", odd.seen)); + odd.next.walk(out); + } + } +} + +/// A type that holds itself with its parameters swapped, so its projections at the inner +/// instance are its own in the other order. +struct Swap { + item: A::Item, + next: Option>>, +} + +impl Swap +where + A::Item: std::fmt::Debug, + B::Item: std::fmt::Debug, +{ + fn show(&self, out: &mut String) { + out.push_str(&format!("{:?} ", self.item)); + if let Some(next) = &self.next { + next.show(out); + } + } +} + +/// A projection beside an `Option` of it only a `PhantomData` holds, which types nothing, so +/// no instance is refused for what that `Option` would erase to. +struct Ghost { + item: S::Item, + marker: std::marker::PhantomData>, +} + +/// Types typed with themselves, or with each other, that name projections. +pub fn projected_cycles(data: &[u8], out: &mut Vec) { + let tree = data + .chunks(2) + .fold(Tree::<[u8; 1]> { branches: Vec::new() }, |below, chunk| Tree { + branches: chunk + .iter() + .map(|&item| Branch { item, below: None }) + .chain([Branch { + item: 0xff, + below: Some(Box::new(below)), + }]) + .collect(), + }); + let mut items = Vec::new(); + tree.items(&mut items); + put(out, &format!("{items:?}")); + + let mut seen = data.iter().map(|b| b % 5); + let mut even = Even::>::End; + for &b in data.iter().rev() { + even = Even::Next( + b & 1 != 0, + Box::new(Odd { + seen: seen.next(), + next: even, + }), + ); + } + let mut walked = String::new(); + even.walk(&mut walked); + put(out, &walked); + + let mut swap = None::>>; + for (i, &b) in data.iter().enumerate().rev() { + let inner = Swap:: { + item: b > 0x40, + next: swap.take(), + }; + if i % 2 == 0 { + swap = Some(Box::new(Swap { + item: u16::from(b) << 4, + next: Some(Box::new(inner)), + })); + } + } + let mut shown = String::new(); + if let Some(swap) = &swap { + swap.show(&mut shown); + } + put(out, &shown); + + let ghost = Ghost::<[Option<()>; 2]> { + item: data.first().map(|_| ()), + marker: std::marker::PhantomData, + }; + put(out, &format!("{:?}", ghost.item)); +} + +/// What a source yields, named by an associated type. +trait Source { + type Item; +} + +/// What a source holds next, which TypeScript names through an alias where the item is it +/// again. +struct Carried { + tick: Ticked, + next: Option>, +} + +/// A source whose items hold it again. +struct Looped; + +impl Source for Looped { + type Item = Carried; +} + +/// An enum of what a source holds next, whose alias at an instance whose items are it again +/// spells out its union. +enum Chain { + End, + Link(u8, Box), +} + +/// A source whose items chain it again. +struct Linked; + +impl Source for Linked { + type Item = Chain; +} + +impl Chain { + fn ids(&self, out: &mut Vec) { + if let Chain::Link(id, next) = self { + out.push(*id); + next.ids(out); + } + } +} + +/// What a source holds next, whose source defaults to the one whose items are it again, +/// so its alias is named by the default too. +struct Defaulted { + id: u8, + next: Option>, +} + +/// The default source of a [`Defaulted`]. +struct Back; + +impl Source for Back { + type Item = Defaulted; +} + +/// A node holding the node at [`Head`], typed while its own definition is, whose item is the +/// node at [`Tail`], whose item ends the chain. +struct Node { + item: S::Item, + next: Option>>, +} + +/// The source of the node a [`Node`] holds. +struct Head; + +impl Source for Head { + type Item = Node; +} + +/// The last source of a [`Node`] chain. +struct Tail; + +impl Source for Tail { + type Item = u8; +} + +/// A grove's branch, or its source's item, its branch typed first: typing [`Twig`] names +/// `Grove` while the grove's own definition, still being typed, has yet to name its +/// item, so the twig completes with the grove. +enum Grove { + Branch(Twig), + Item(S::Item), +} + +/// A twig lending the twig at [`Sprout`], whose item is a grove, and its source's item. +struct Twig { + next: Option<&'static Twig>, + item: S::Item, +} + +/// The source of a [`Twig`]'s next. +struct Sprout; + +impl Source for Sprout { + type Item = Grove; +} + +/// A [`Grove`] with its item typed first. +enum Copse { + Item(S::Item), + Branch(Shoot), +} + +/// A [`Twig`] of a [`Copse`]. +struct Shoot { + next: Option<&'static Shoot>, + item: S::Item, +} + +/// The source of a [`Shoot`]'s next. +struct Seed; + +impl Source for Seed { + type Item = Copse; +} + +/// An `Option` of a type parameter. +struct Slot { + value: Option, +} + +/// A [`Slot`] of a `MaybeUninit` of its own parameter, which at a byte is `0` rather than +/// `undefined`, as that slot's instance is. +struct Uninit { + slot: Slot>, +} + +/// A getter of its parameter, and of the type holding it, which its object's type names +/// while that type's definition is still being typed. +trait Get { + fn get(&self) -> Option; + fn holder(&self) -> Option; +} + +/// A type holding a getter whose methods return it. +struct Holder { + id: u8, + get: Box>, +} + +impl Holder { + /// A holder of a getter of `b`, whose type is typed before its getter's object is. + fn new(id: u8, b: u8) -> Self { + Self { + id, + get: Box::new(Getter(b)), + } + } +} + +/// A getter of a byte, holding half of it again past `0x80`. +struct Getter(u8); + +impl Get for Getter { + fn get(&self) -> Option { + (self.0 % 3 != 0).then_some(self.0) + } + + fn holder(&self) -> Option { + (self.0 > 0x80).then(|| Holder::new(self.0 / 2, self.0 / 2)) + } +} + +/// A layered source's item, and the item of the layer peeled off it. +trait Layered { + type Item; + type Other; +} + +/// A layer lending the one under it, peeled, whose item is a projection its own definition +/// names only once that instance is filled in. +struct Layer { + item: S::Item, + under: Option<&'static Layer>>, +} + +/// A source with a layer peeled off. +struct Peel(S); + +impl Layered for Peel { + type Item = S::Other; + type Other = u8; +} + +/// The outermost layer. +struct Top; + +impl Layered for Top { + type Item = u16; + type Other = bool; +} + +/// What a source at a depth holds next, an instance only of its const parameter. +struct Counted +where + Depth: Source, +{ + id: u8, + next: Option as Source>::Item>>, +} + +impl Source for Depth<0> { + type Item = Counted<0>; +} + +/// A trait of more associated types than the crate's recursion limit, a struct with a field +/// of each that lends itself again, and its instance at `u8`, which translate as any +/// projections do, however many. +macro_rules! broad { + ($($assoc:ident $field:ident),* $(,)?) => { + trait Broad { + $(type $assoc;)* + } + + impl Broad for u8 { + $(type $assoc = u8;)* + } + + struct Wide { + $($field: S::$assoc,)* + next: Option<&'static Wide>, + } + + impl Wide { + fn new(n: u8) -> Self { + Self { + $($field: n,)* + next: None, + } + } + } + }; +} + +broad!( + A0 a0, A1 a1, A2 a2, A3 a3, A4 a4, A5 a5, A6 a6, A7 a7, A8 a8, A9 a9, A10 a10, A11 a11, A12 + a12, A13 a13, A14 a14, A15 a15, A16 a16, A17 a17, A18 a18, A19 a19, A20 a20, A21 a21, A22 + a22, A23 a23, A24 a24, A25 a25, A26 a26, A27 a27, A28 a28, A29 a29, A30 a30, A31 a31, A32 + a32, A33 a33, A34 a34, A35 a35, A36 a36, A37 a37, A38 a38, A39 a39, A40 a40, A41 a41, A42 + a42, A43 a43, A44 a44, A45 a45, A46 a46, A47 a47, A48 a48, A49 a49, A50 a50, A51 a51, A52 + a52, A53 a53, A54 a54, A55 a55, A56 a56, A57 a57, A58 a58, A59 a59, A60 a60, A61 a61, A62 + a62, A63 a63, A64 a64, A65 a65, A66 a66, A67 a67, A68 a68, A69 a69, A70 a70, A71 a71, A72 + a72, A73 a73, A74 a74, A75 a75, A76 a76, A77 a77, A78 a78, A79 a79, A80 a80, A81 a81, A82 + a82, A83 a83, A84 a84, A85 a85, A86 a86, A87 a87, A88 a88, A89 a89, A90 a90, A91 a91, A92 + a92, A93 a93, A94 a94, A95 a95, A96 a96, A97 a97, A98 a98, A99 a99, A100 a100, A101 a101, + A102 a102, A103 a103, A104 a104, A105 a105, A106 a106, A107 a107, A108 a108, A109 a109, A110 + a110, A111 a111, A112 a112, A113 a113, A114 a114, A115 a115, A116 a116, A117 a117, A118 + a118, A119 a119, A120 a120, A121 a121, A122 a122, A123 a123, A124 a124, A125 a125, A126 + a126, A127 a127, A128 a128, A129 a129 +); + +/// A source's item, and what it makes of any type. +trait Makes { + type Item; + type Made; +} + +impl Makes for u8 { + type Item = u16; + type Made = u8; +} + +/// A source made once more, whose item is what its source makes of what it makes of 130 +/// types: more projections than the crate's recursion limit, side by side, but only two deep. +struct Remade(S); + +macro_rules! siblings { + ($($n:literal),* $(,)?) => { + impl Makes for Remade { + type Item = S::Made<($(S::Made<[(); $n]>,)*)>; + type Made = u8; + } + }; +} + +siblings!( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, + 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, + 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, + 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129 +); + +/// A source's item, lending the same at a source made once more, whose item is a projection +/// of 130 sibling projections, which settles at its second. +struct Sibling { + item: S::Item, + next: Option<&'static Sibling>>, +} + +/// Two types a source names, each holding the other. +trait Duo { + type Ping; + type Pong; +} + +/// What holds a [`Duo`]'s pong. +struct Ping { + id: u8, + pong: Option>, +} + +/// What holds a [`Duo`]'s ping, or misses. +enum Pong { + Miss, + Hit(u8, Box), +} + +/// A duo of its own ping and pong. +struct Rally; + +impl Duo for Rally { + type Ping = Ping; + type Pong = Pong; +} + +impl Ping { + fn ids(&self, out: &mut Vec) { + out.push(self.id); + if let Some(pong) = &self.pong + && let Pong::Hit(id, ping) = &**pong + { + out.push(*id); + ping.ids(out); + } + } +} + +/// Two projections, each naming the next instance down to the last. +trait Fork { + type Left; + type Right; +} + +/// A fork of what its source's projections both are. +struct Forked { + id: u8, + left: Option>, + right: Option>, +} + +/// The source at a depth. +struct Depth; + +/// Each depth's projections, the next depth's [`Forked`]. +macro_rules! forks { + ($($depth:literal => $next:literal),* $(,)?) => {$( + impl Fork for Depth<$depth> { + type Left = Forked>; + type Right = Forked>; + } + )*}; +} + +forks!( + 0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5, 5 => 6, 6 => 7, 7 => 8, 8 => 9, 9 => 10, 10 => 11, + 11 => 12, 12 => 13, 13 => 14, 14 => 15, 15 => 16, 16 => 17, 17 => 18, 18 => 19, 19 => 20, + 20 => 21, 21 => 22, 22 => 23, 23 => 24, +); + +/// The last depth, whose left is the first's fork again and whose right drops. +impl Fork for Depth<24> { + type Left = Forked>; + type Right = Ticked; +} + +/// Types whose projections hold their instances again, directly or through each other, as +/// structs and enums, and a type whose two projections each name the next of 25 instances, +/// the last holding the first again, which an alias per instance names once rather than +/// once per path. +pub fn projected_selves(data: &[u8], out: &mut Vec) { + let log = Rc::new(RefCell::new(Vec::new())); + let tick = |id: u8| Ticked { id, log: log.clone() }; + let mut held = None::>; + for &b in data { + held = Some(Carried { + tick: tick(b), + next: held.map(Box::new), + }); + } + let mut depth = 0; + let mut at = held.as_ref(); + while let Some(next) = at { + depth += 1; + at = next.next.as_deref(); + } + log.borrow_mut().push(depth); + drop(held); + + let chain = data + .iter() + .rev() + .fold(Chain::::End, |next, &b| Chain::Link(b, Box::new(next))); + let mut ids = Vec::new(); + chain.ids(&mut ids); + put(out, &format!("{ids:?}")); + + let defaulted = data.iter().fold(None::, |next, &b| { + Some(Defaulted { + id: b, + next: next.map(Box::new), + }) + }); + let mut ids = Vec::new(); + let mut at = defaulted.as_ref(); + while let Some(next) = at { + ids.push(next.id); + at = next.next.as_deref(); + } + let node = Node:: { + item: data.len() as u8, + next: data.first().map(|&b| { + Box::new(Node:: { + item: Node { item: b, next: None }, + next: None, + }) + }), + }; + let held = node.next.as_ref().map(|n| n.item.item); + put(out, &format!("{ids:?} {} {held:?}", node.item)); + + let uninit = Uninit:: { + slot: Slot { + value: data.first().map(|&b| std::mem::MaybeUninit::new(b)), + }, + }; + put(out, &format!("{}", uninit.slot.value.is_some())); + + let holder = Holder::new(data.len() as u8, data.first().copied().unwrap_or(0)); + let held = holder.get.holder().map(|h| (h.id, h.get.get())); + put(out, &format!("{} {:?} {held:?}", holder.id, holder.get.get())); + + let twig: &'static Twig = &Twig { + next: None, + item: Grove::Item(5), + }; + let grove = match data.first() { + Some(&b) => Grove::::Branch(Twig { + next: (b % 2 == 0).then_some(twig), + item: b, + }), + None => Grove::Item(data.len() as u8), + }; + let shoot: &'static Shoot = &Shoot { + next: None, + item: Copse::Item(6), + }; + let copse = match data.last() { + Some(&b) => Copse::::Branch(Shoot { + next: (b % 2 == 1).then_some(shoot), + item: !b, + }), + None => Copse::Item(0), + }; + let grown = match &grove { + Grove::Branch(twig) => (twig.item, twig.next.map(|t| matches!(t.item, Grove::Item(5)))), + Grove::Item(item) => (*item, None), + }; + let sown = match &copse { + Copse::Branch(shoot) => (shoot.item, shoot.next.map(|s| matches!(s.item, Copse::Item(6)))), + Copse::Item(item) => (*item, None), + }; + put(out, &format!("{grown:?} {sown:?}")); + + let under: &'static Layer> = &Layer { + item: true, + under: None, + }; + let layer = Layer:: { + item: u16::from(data.first().copied().unwrap_or(0)) << 4, + under: (data.len() % 2 == 1).then_some(under), + }; + let counted = data.iter().fold(None::>, |next, &b| { + Some(Counted { + id: b, + next: next.map(Box::new), + }) + }); + let count = counted.as_ref().and_then(|c| c.next.as_ref()).map(|c| c.id); + put( + out, + &format!( + "{} {:?} {count:?}", + layer.item, + layer.under.map(|u| (u.item, u.under.is_some())) + ), + ); + + let wide = Wide::new(data.len() as u8); + put(out, &format!("{} {} {}", wide.a0, wide.a129, wide.next.is_none())); + let made: &'static Sibling> = &Sibling { item: 7, next: None }; + let sibling = Sibling:: { + item: u16::from(data.last().copied().unwrap_or(0)) << 3, + next: (data.len() % 3 == 0).then_some(made), + }; + put( + out, + &format!( + "{} {:?}", + sibling.item, + sibling.next.map(|s| (s.item, s.next.is_none())) + ), + ); + + let mut ping = Ping:: { id: 0xee, pong: None }; + for (i, &b) in data.iter().enumerate() { + ping = Ping { + id: b, + pong: Some(Box::new(match i % 3 { + 0 => Pong::Miss, + _ => Pong::Hit(!b, Box::new(ping)), + })), + }; + } + let mut ids = Vec::new(); + ping.ids(&mut ids); + put(out, &format!("{ids:?}")); + + let last = Forked::> { + id: 24, + left: data.first().map(|&b| { + Box::new(Forked { + id: b, + left: None, + right: None, + }) + }), + right: data.last().map(|&b| Box::new(tick(!b))), + }; + let below = Forked::> { + id: 23, + left: None, + right: Some(Box::new(last)), + }; + let mut fork = Forked::> { + id: 0, + left: None, + right: None, + }; + if data.len() % 2 == 0 { + fork.left = Some(Box::new(Forked { + id: 1, + left: None, + right: None, + })); + } + let ids = (fork.id, fork.left.as_ref().map(|f| f.id), below.id); + let right = (below.right.as_ref()).map(|f| (f.id, f.left.as_ref().map(|f| f.id), f.right.as_ref().map(|t| t.id))); + put(out, &format!("{ids:?} {right:?}")); + drop(below); + drop(fork); + out.extend(log.borrow().iter()); +} diff --git a/ts/fixtures/lang/shapes/src/lib.rs b/ts/fixtures/lang/shapes/src/lib.rs index d3eb97926..d76df0b96 100644 --- a/ts/fixtures/lang/shapes/src/lib.rs +++ b/ts/fixtures/lang/shapes/src/lib.rs @@ -56,5 +56,12 @@ fn cases() -> Vec<(&'static str, Case)> { ("fmt::cells", |_, data, out| fmt::cells(data, out)), ("fmt::searches", |_, data, out| fmt::searches(data, out)), ("generics::units", |_, data, out| generics::units(data, out)), + ("generics::projections", |_, data, out| generics::projections(data, out)), + ("generics::projected_cycles", |_, data, out| { + generics::projected_cycles(data, out) + }), + ("generics::projected_selves", |_, data, out| { + generics::projected_selves(data, out) + }), ] } diff --git a/ts/fixtures/reject/census.txt b/ts/fixtures/reject/census.txt index 38de56363..1348aba69 100644 --- a/ts/fixtures/reject/census.txt +++ b/ts/fixtures/reject/census.txt @@ -292,8 +292,14 @@ fixtures/reject/src/strs.rs:str_bytes_mut+2:13: `core::str::::get_unch fixtures/reject/src/strs.rs:str_from_bytes_mut+1:20: `std::str::from_utf8_mut` with a mutable reference to a value JS copies, which its mapping would copy fixtures/reject/src/values.rs:Beside+0:1: union `values::Beside`, whose fields overlap in `u32` and `f32`, which JS keeps apart fixtures/reject/src/values.rs:Bits+0:1: union `values::Bits`, whose fields overlap in `u32` and `f64`, which JS keeps apart +fixtures/reject/src/values.rs:Grown+0:1: `values::Grown` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit fixtures/reject/src/values.rs:HoldsByte+1:2: `values::ByteAnd` is not supported: its field `value` is `Option>`, typed `std::mem::MaybeUninit | rs.None`, whose `None` would be `undefined` as `Option>` +fixtures/reject/src/values.rs:Links+0:1: dropping `values::Links>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` is not supported: what its glue drops through, by its projections, nests past the crate's recursion limit fixtures/reject/src/values.rs:Mixed+0:1: union `values::Mixed`, whose fields overlap in `u32` and `f32`, which JS keeps apart +fixtures/reject/src/values.rs:Nested+0:1: `values::Nested` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit +fixtures/reject/src/values.rs:Over+1:2: `values::Lent>` is not supported yet: a projection of its parameters is a type whose arguments hold `values::Lent>` again, so its TypeScript type arguments would never end +fixtures/reject/src/values.rs:Sprawl+0:1: `values::Sprawl` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit +fixtures/reject/src/values.rs:Spread+0:1: `values::Spread` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit fixtures/reject/src/values.rs:addr_parsed+0:32: unsupported type `std::net::AddrParseError` from another crate fixtures/reject/src/values.rs:addr_parsed+0:32: unsupported type `std::net::Ipv4Addr` from another crate fixtures/reject/src/values.rs:addr_parsed+1:4: unsupported call to `core::str::::parse::` @@ -307,12 +313,27 @@ fixtures/reject/src/values.rs:generic_nested+1:6: `values::Maybe>` is not supported: its `None` and `Some` would both be `rs.None` fixtures/reject/src/values.rs:generic_uninit+1:2: `values::Maybe>` is not supported: its field `value` is `std::option::Option`, typed `rs.OptionOf`, which decides by TypeScript's type of `std::mem::MaybeUninit` otherwise than `std::option::Option>` erases fixtures/reject/src/values.rs:generic_uninit_byte+1:2: `values::MaybeByte` is not supported: its field `value` is `Option>`, typed `std::mem::MaybeUninit | rs.None`, whose `None` would be `undefined` as `Option>` +fixtures/reject/src/values.rs:generic_uninit_byte_open+1:2: `values::ByteAnd` is not supported: its field `value` is `Option>`, typed `std::mem::MaybeUninit | rs.None`, whose `None` would be `undefined` as `Option>` fixtures/reject/src/values.rs:lists+1:4: `std::collections::LinkedList::::retain` with a mutable reference to a value JS copies, which its mapping would copy fixtures/reject/src/values.rs:manual_impls+2:2: unsupported call to ` as std::fmt::Debug>::fmt` fixtures/reject/src/values.rs:manual_impls+2:25: unsupported call to ` as std::cmp::PartialEq>::eq` fixtures/reject/src/values.rs:manual_impls+2:34: a constant of type `std::mem::ManuallyDrop` fixtures/reject/src/values.rs:nested+0:15: `Option>>` is not supported: its `None` and `Some` would both be `rs.None` fixtures/reject/src/values.rs:nested+1:2: `Option>>` is not supported: its `None` and `Some` would both be `rs.None` +fixtures/reject/src/values.rs:projected_deep+0:23: `values::Links>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` is not supported: its projections' values nest instances past the crate's recursion limit +fixtures/reject/src/values.rs:projected_flow+0:23: `values::Flowing` is not supported: its field `flow` is `std::ops::ControlFlow<::Break, u8>`, typed as a result that breaks with `::Break`, which `std::ops::ControlFlow, u8>` is not, as it breaks with what `?` makes +fixtures/reject/src/values.rs:projected_fork+0:38: `values::Fork>` is not supported: its projections' values nest instances past the crate's recursion limit +fixtures/reject/src/values.rs:projected_fork+1:7: `values::Fork>` is not supported: its projections' values nest instances past the crate's recursion limit, in `core::bool::::then_some` +fixtures/reject/src/values.rs:projected_fork+1:17: `values::Fork>` is not supported: its projections' values nest instances past the crate's recursion limit +fixtures/reject/src/values.rs:projected_fork+1:23: `values::Fork>` is not supported: its projections' values nest instances past the crate's recursion limit, in `std::option::Option::>::flatten` +fixtures/reject/src/values.rs:projected_future+0:25: `values::Awaiting` is not supported: its field `future` holds a future of `std::task::Poll`, which can be `rs.Pending`, as the future's own `Pending` is +fixtures/reject/src/values.rs:projected_future+0:52: `values::Awaiting` is not supported: its field `future` holds a future of `std::task::Poll`, which can be `rs.Pending`, as the future's own `Pending` is +fixtures/reject/src/values.rs:projected_nested+1:6: `values::Projected<()>` is not supported: its field `value` is `std::option::Option>`: `Option>` is not supported: its `None` and `Some` would both be `rs.None` +fixtures/reject/src/values.rs:projected_nested+1:52: `Option>` is not supported: its `None` and `Some` would both be `rs.None` +fixtures/reject/src/values.rs:projected_outside+0:26: `values::Projected<()>` is not supported: its field `value` is `std::option::Option>`: `Option>` is not supported: its `None` and `Some` would both be `rs.None` +fixtures/reject/src/values.rs:projected_spread+1:6: `values::Spread>` is not supported: its projections' values nest instances past the crate's recursion limit +fixtures/reject/src/values.rs:projected_uninit+1:2: `values::Projected` is not supported: its field `value` is `std::option::Option<::Held>`, typed `rs.OptionOf<::Held>`, which decides by TypeScript's type of `std::mem::MaybeUninit` otherwise than `std::option::Option>` erases +fixtures/reject/src/values.rs:projected_uninit_slot+0:30: `values::Slot>` is not supported: its field `value` is `std::option::Option`, typed `rs.OptionOf`, which decides by TypeScript's type of `std::mem::MaybeUninit` otherwise than `std::option::Option>` erases fixtures/reject/src/values.rs:units_compared+2:15: a raw pointer to a place of `()`, which has no address of its own fixtures/reject/src/values.rs:units_compared+2:29: a raw pointer to a place of `()`, which has no address of its own fixtures/reject/src/values.rs:units_compared+2:70: comparing pointers to `places::Bare`, which has no bytes and so no address of its own diff --git a/ts/fixtures/reject/expected.txt b/ts/fixtures/reject/expected.txt index a8d466b37..0322a77c5 100644 --- a/ts/fixtures/reject/expected.txt +++ b/ts/fixtures/reject/expected.txt @@ -286,7 +286,13 @@ fixtures/reject/src/strs.rs:cow_made+2:53: constructing `std::borrow::Cow<'_, st fixtures/reject/src/strs.rs:str_bytes_mut+1:13: unsupported call to `core::str::::as_bytes_mut` fixtures/reject/src/strs.rs:str_bytes_mut+2:13: `core::str::::get_unchecked_mut` with a mutable reference to a value JS copies, which its mapping would copy fixtures/reject/src/strs.rs:str_from_bytes_mut+1:20: `std::str::from_utf8_mut` with a mutable reference to a value JS copies, which its mapping would copy +fixtures/reject/src/values.rs:Grown+0:1: `values::Grown` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit fixtures/reject/src/values.rs:HoldsByte+1:2: `values::ByteAnd` is not supported: its field `value` is `Option>`, typed `std::mem::MaybeUninit | rs.None`, whose `None` would be `undefined` as `Option>` +fixtures/reject/src/values.rs:Links+0:1: dropping `values::Links>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` is not supported: what its glue drops through, by its projections, nests past the crate's recursion limit +fixtures/reject/src/values.rs:Nested+0:1: `values::Nested` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit +fixtures/reject/src/values.rs:Over+1:2: `values::Lent>` is not supported yet: a projection of its parameters is a type whose arguments hold `values::Lent>` again, so its TypeScript type arguments would never end +fixtures/reject/src/values.rs:Sprawl+0:1: `values::Sprawl` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit +fixtures/reject/src/values.rs:Spread+0:1: `values::Spread` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit fixtures/reject/src/values.rs:addr_parsed+0:32: unsupported type `std::net::AddrParseError` from another crate fixtures/reject/src/values.rs:addr_parsed+0:32: unsupported type `std::net::Ipv4Addr` from another crate fixtures/reject/src/values.rs:addr_parsed+1:4: unsupported call to `core::str::::parse::` @@ -301,6 +307,7 @@ fixtures/reject/src/values.rs:generic_nested+1:6: `values::Maybe>` is not supported: its `None` and `Some` would both be `rs.None` fixtures/reject/src/values.rs:generic_uninit+1:2: `values::Maybe>` is not supported: its field `value` is `std::option::Option`, typed `rs.OptionOf`, which decides by TypeScript's type of `std::mem::MaybeUninit` otherwise than `std::option::Option>` erases fixtures/reject/src/values.rs:generic_uninit_byte+1:2: `values::MaybeByte` is not supported: its field `value` is `Option>`, typed `std::mem::MaybeUninit | rs.None`, whose `None` would be `undefined` as `Option>` +fixtures/reject/src/values.rs:generic_uninit_byte_open+1:2: `values::ByteAnd` is not supported: its field `value` is `Option>`, typed `std::mem::MaybeUninit | rs.None`, whose `None` would be `undefined` as `Option>` fixtures/reject/src/values.rs:lists+1:4: `std::collections::LinkedList::::retain` with a mutable reference to a value JS copies, which its mapping would copy fixtures/reject/src/values.rs:manual_impls+2:11: unsupported call to ` as std::fmt::Debug>::fmt` fixtures/reject/src/values.rs:manual_impls+2:25: unsupported call to ` as std::cmp::PartialEq>::eq` @@ -308,6 +315,20 @@ fixtures/reject/src/values.rs:manual_impls+2:34: a constant of type `std::mem::M fixtures/reject/src/values.rs:mixed_byte+0:19: union `values::Mixed`, whose fields overlap in `u32` and `f32`, which JS keeps apart fixtures/reject/src/values.rs:nested+0:15: `Option>>` is not supported: its `None` and `Some` would both be `rs.None` fixtures/reject/src/values.rs:nested+1:2: `Option>>` is not supported: its `None` and `Some` would both be `rs.None` +fixtures/reject/src/values.rs:projected_deep+0:23: `values::Links>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` is not supported: its projections' values nest instances past the crate's recursion limit +fixtures/reject/src/values.rs:projected_flow+0:23: `values::Flowing` is not supported: its field `flow` is `std::ops::ControlFlow<::Break, u8>`, typed as a result that breaks with `::Break`, which `std::ops::ControlFlow, u8>` is not, as it breaks with what `?` makes +fixtures/reject/src/values.rs:projected_fork+0:38: `values::Fork>` is not supported: its projections' values nest instances past the crate's recursion limit +fixtures/reject/src/values.rs:projected_fork+1:7: `values::Fork>` is not supported: its projections' values nest instances past the crate's recursion limit, in `core::bool::::then_some` +fixtures/reject/src/values.rs:projected_fork+1:17: `values::Fork>` is not supported: its projections' values nest instances past the crate's recursion limit +fixtures/reject/src/values.rs:projected_fork+1:23: `values::Fork>` is not supported: its projections' values nest instances past the crate's recursion limit, in `std::option::Option::>::flatten` +fixtures/reject/src/values.rs:projected_future+0:25: `values::Awaiting` is not supported: its field `future` holds a future of `std::task::Poll`, which can be `rs.Pending`, as the future's own `Pending` is +fixtures/reject/src/values.rs:projected_future+0:52: `values::Awaiting` is not supported: its field `future` holds a future of `std::task::Poll`, which can be `rs.Pending`, as the future's own `Pending` is +fixtures/reject/src/values.rs:projected_nested+1:6: `values::Projected<()>` is not supported: its field `value` is `std::option::Option>`: `Option>` is not supported: its `None` and `Some` would both be `rs.None` +fixtures/reject/src/values.rs:projected_nested+1:52: `Option>` is not supported: its `None` and `Some` would both be `rs.None` +fixtures/reject/src/values.rs:projected_outside+0:26: `values::Projected<()>` is not supported: its field `value` is `std::option::Option>`: `Option>` is not supported: its `None` and `Some` would both be `rs.None` +fixtures/reject/src/values.rs:projected_spread+1:6: `values::Spread>` is not supported: its projections' values nest instances past the crate's recursion limit +fixtures/reject/src/values.rs:projected_uninit+1:2: `values::Projected` is not supported: its field `value` is `std::option::Option<::Held>`, typed `rs.OptionOf<::Held>`, which decides by TypeScript's type of `std::mem::MaybeUninit` otherwise than `std::option::Option>` erases +fixtures/reject/src/values.rs:projected_uninit_slot+0:30: `values::Slot>` is not supported: its field `value` is `std::option::Option`, typed `rs.OptionOf`, which decides by TypeScript's type of `std::mem::MaybeUninit` otherwise than `std::option::Option>` erases fixtures/reject/src/values.rs:units_compared+2:15: a raw pointer to a place of `()`, which has no address of its own fixtures/reject/src/values.rs:units_compared+2:29: a raw pointer to a place of `()`, which has no address of its own fixtures/reject/src/values.rs:units_compared+2:70: comparing pointers to `places::Bare`, which has no bytes and so no address of its own diff --git a/ts/fixtures/reject/src/values.rs b/ts/fixtures/reject/src/values.rs index 8ffa3a8e0..2612efa76 100644 --- a/ts/fixtures/reject/src/values.rs +++ b/ts/fixtures/reject/src/values.rs @@ -70,6 +70,333 @@ pub fn generic_uninit_byte_open(b: u8) -> bool { .is_some() } +/// What a type holds, named by an associated type. +pub trait Holds { + type Held; +} + +impl Holds for u32 { + type Held = std::mem::MaybeUninit; +} + +impl Holds for () { + type Held = Option<()>; +} + +/// A generic type's `Option` of a projection is an `rs.OptionOf` of it too, which each +/// instance resolves as [`Maybe`]'s. +pub struct Projected { + pub value: Option, +} + +/// Its `MaybeUninit`, whose `None` `rs.OptionOf` would make `undefined`. +pub fn projected_uninit(value: u32) -> bool { + Projected:: { + value: Some(std::mem::MaybeUninit::new(value)), + } + .value + .is_some() +} + +/// Its `Option<()>`, whose `None` and `Some(None)` would both be `rs.None`. +pub fn projected_nested(unit: bool) -> bool { + let projected: Projected<()> = Projected { value: None }; + drop(projected); + unit +} + +/// A [`Projected`] held by another generic type at its own parameter. +pub struct Outside { + pub inside: Projected, +} + +/// `Outside<()>` holds `Projected<()>`'s `Option<()>`, whose `None` and `Some(None)` would +/// both be `rs.None`, though it never names `Projected<()>`. +pub fn projected_outside(outside: &Outside<()>) -> u8 { + match outside.inside.value { + None => 0, + Some(None) => 1, + Some(Some(())) => 2, + } +} + +/// An `Option` of a type parameter. +pub struct Slot { + pub value: Option, +} + +/// A [`Slot`] of a `MaybeUninit` of its own parameter, checked as that slot's instance is. +pub struct Uninit { + pub slot: Slot>, +} + +/// `Uninit` holds `Slot>`, whose `rs.OptionOf` would make `None` +/// `undefined`. +pub fn projected_uninit_slot(uninit: &Uninit) -> bool { + uninit.slot.value.is_some() +} + +/// What a flow breaks with, named by an associated type. +pub trait Breaks { + type Break; +} + +impl Breaks for u8 { + type Break = Option; +} + +/// A `ControlFlow` breaking with a projection, typed as an `rs.Result` of it. +pub struct Flowing { + pub flow: std::ops::ControlFlow, +} + +/// `Flowing` breaks with an `Option`, a `ControlFlow` typed as an `Option`. +pub fn projected_flow(flowing: &Flowing) -> bool { + flowing.flow.is_continue() +} + +/// What a future outputs, named by an associated type. +pub trait Outputs { + type Output; +} + +impl Outputs for u8 { + type Output = std::task::Poll; +} + +/// A future of a projection. +pub struct Awaiting { + pub future: std::pin::Pin>>, +} + +/// `Awaiting`'s future outputs a `Poll`, which can be the future's own `rs.Pending`. +pub fn projected_future(awaiting: Awaiting) -> Awaiting { + awaiting +} + +/// What a source yields, named by an associated type. +pub trait Source { + type Item; +} + +/// What a source lends next, which drops nothing itself. +pub struct Lent { + pub next: Option<&'static S::Item>, +} + +/// A source whose items lend it again. +pub struct Lends; + +impl Source for Lends { + type Item = Lent; +} + +/// Dropping an `Rc` of `Lent` asks whether its glue is inert, through its projection, +/// which ends rather than overflow; it translates, as nothing names the instance's type. +pub fn projected_inert(deep: bool) -> bool { + let lent = std::rc::Rc::new(Lent:: { next: None }); + drop(lent); + deep +} + +/// A source wrapped once, whose items lend it again at any `T`. +pub struct Relent(pub T); + +impl Source for Relent { + type Item = Lent>; +} + +/// A generic type holding an instance over its own parameter whose projection holds that +/// instance again, which no alias names, as an alias names only instances without type +/// parameters. +pub struct Over { + pub held: Option<&'static Lent>>, +} + +/// `Over`'s definition would hold `Lent>` without end. +pub fn projected_over(deep: bool) -> bool { + let over = Over:: { held: None }; + over.held.is_none() && deep +} + +/// What a source lends next, beside what it owns, so it drops. +pub struct Owning { + pub next: Option<&'static S::Item>, + pub owned: std::rc::Rc<()>, +} + +/// A source whose items own it again. +pub struct Owns; + +impl Source for Owns { + type Item = Owning; +} + +/// Dropping an `Rc` of `Owning` asks whether its glue is shared, through its projection, +/// which ends rather than overflow; it translates, as nothing names the instance's type. +pub fn projected_disposable(deep: bool) -> bool { + let owning = std::rc::Rc::new(Owning:: { + next: None, + owned: std::rc::Rc::new(()), + }); + drop(owning); + deep +} + +/// A source wrapped once more. +pub struct Wrapped(pub T); + +impl Source for Wrapped { + type Item = Spread>>; +} + +/// A type that holds itself at a wrapped source, whose item is it at a source wrapped again. +pub struct Spread { + pub item: Option<&'static S::Item>, + pub next: Option<&'static Spread>>, +} + +/// `Spread` would name an instance at each wrapping. +pub fn projected_spread(deep: bool) -> bool { + let spread: Spread> = Spread { item: None, next: None }; + spread.next.is_none() && deep +} + +/// Two types a source names. +pub trait Duo { + type Ping; + type Pong; +} + +/// A source widened once more. +pub struct Widen(pub T); + +impl Source for Widen { + type Item = Sprawl>>; +} + +/// A type holding an instance of itself without type parameters, typed while its own +/// definition is, whose item is it at a source widened again. +pub struct Sprawl { + pub item: Option<&'static S::Item>, + pub wide: Option<&'static Sprawl>>, +} + +/// `Sprawl`'s definition would name an instance at each widening. +pub fn projected_sprawl(deep: bool) -> bool { + let sprawl: Sprawl> = Sprawl { item: None, wide: None }; + sprawl.wide.is_none() && deep +} + +/// What a duo's ping and pong both are at a wrapped duo: the same type at one wrapped again. +pub struct Fork { + pub ping: Option<&'static D::Ping>, + pub pong: Option<&'static D::Pong>, +} + +impl Duo for Wrapped { + type Ping = Fork>>; + type Pong = Fork>>; +} + +/// `Fork>` names ever deeper instances twice over at each level. +pub fn projected_fork(deep: bool) -> Option<&'static Fork>> { + deep.then_some(None).flatten() +} + +/// The end of a [`Links`], which drops. +pub struct Loud; + +impl Drop for Loud { + fn drop(&mut self) {} +} + +/// The source past the last link. +pub struct Zero; + +impl Source for Zero { + type Item = &'static Loud; +} + +/// One link more than its source. +pub struct Succ(pub T); + +impl Source for Succ { + type Item = &'static Links; +} + +/// A link lending the next, down to a [`Loud`]. +pub struct Links { + pub item: S::Item, +} + +/// Ten links more. +type Ten = Succ>>>>>>>>>; + +/// A chain of 140 links, which ends, but past the recursion limit. +pub type Deep = Ten>>>>>>>>>>>>>; + +/// Dropping a shared chain drops none of what it lends. +pub fn projected_deep(chain: std::rc::Rc>) { + drop(chain); +} + +/// A chain of types, each naming the next. +pub trait Chain { + type Item; + type Next: Chain; +} + +/// A type that holds itself at its parameter's next, whose projections at each are new. +pub struct Nested { + pub item: C::Item, + pub next: Option>>, +} + +impl Chain for u8 { + type Item = u8; + type Next = u8; +} + +/// `Nested` would need a projection argument for every link of the chain. +pub fn projected_chain(item: u8) -> u8 { + let nested: Nested = Nested { item, next: None }; + nested.item +} + +/// A source's item, and what it makes of any type. +pub trait Gathers { + type Item; + type Many; +} + +impl Gathers for u8 { + type Item = u8; + type Many = T; +} + +/// A source gathered once more, whose item and what it makes are what its source makes, +/// gathered once more. +pub struct Gather(pub S); + +impl Gathers for Gather { + type Item = S::Many; + type Many = S::Many>; +} + +/// A type that holds itself at a gathered source, whose item is a projection at a type +/// argument gathered once more at each, one projection deep. +pub struct Grown { + pub item: S::Item, + pub next: Option<&'static Grown>>, +} + +/// `Grown`'s definition would name a new projection at each gathering. +pub fn projected_grown(item: u8) -> u8 { + let grown: Grown = Grown { item, next: None }; + grown.item +} + /// Parsing an address is not translated yet. pub fn addr_parsed(s: &str) -> Result { s.parse() diff --git a/ts/fixtures/reject/ts.toml b/ts/fixtures/reject/ts.toml index 349e707a4..e71d6f272 100644 --- a/ts/fixtures/reject/ts.toml +++ b/ts/fixtures/reject/ts.toml @@ -216,6 +216,21 @@ roots = [ "values::manual_impls", "values::mixed_byte", "values::nested", + "values::projected_chain", + "values::projected_deep", + "values::projected_disposable", + "values::projected_flow", + "values::projected_fork", + "values::projected_future", + "values::projected_grown", + "values::projected_inert", + "values::projected_nested", + "values::projected_outside", + "values::projected_over", + "values::projected_sprawl", + "values::projected_spread", + "values::projected_uninit", + "values::projected_uninit_slot", "values::units_compared", ] printable = ["config::Meters"] diff --git a/ts/src/lower/defined.rs b/ts/src/lower/defined.rs new file mode 100644 index 000000000..dad3123c4 --- /dev/null +++ b/ts/src/lower/defined.rs @@ -0,0 +1,695 @@ +//! What typing a generic type's definition named: the one account its instances, its drop +//! glue, and the check of its instances' `Option`s and `Poll`s read. +//! +//! A projection from a generic type's parameters that typing its fields names, such as +//! smallvec's `::Item`, becomes a TypeScript type parameter of its own, which +//! each instance gives what the projection is there. An instance without type parameters +//! that a projection argument holds is named by an alias, typed once. A type typed with itself, directly or +//! through others, names instances of a definition that is still being typed, whose +//! projections are not all known yet: those instances' projection arguments are filled in +//! once every definition typed with them is. + +use rustc_hir::def_id::DefId; +use rustc_middle::ty::{self, GenericArgsRef, Ty, TypeVisitableExt, TypingEnv}; +use rustc_span::Span; + +use super::{Adt, Translator}; +use crate::program::{SymKind, Symbol}; +use crate::ts::{Item, SymId, Type}; + +/// The account of one generic type's definition. +#[derive(Default)] +pub struct Defined<'tcx> { + /// Each projection from its type parameters its fields' types name, by the name of the + /// TypeScript type parameter it is, after its own. + pub projections: Vec<(Ty<'tcx>, String)>, + /// Each part its fields' types type that its instances decide, and those of each + /// instance in [`Self::held`], at that instance's arguments. + pub checks: Vec>, + /// What each of those checks: its type, what it decides, and its part and what that + /// holds, at its arguments. + checked: rustc_data_structures::fx::FxHashSet<(DefId, Decides, Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, + /// Each instance of the crate's generic types over its type parameters its fields' types + /// type. + held: Vec>, + /// While it is typed, the shallowest definition still being typed that it was typed + /// with, by its depth in [`Defining::typing`]; `None` once it is complete. + open: Option, +} + +/// A part of a generic type's definition, over a type parameter or a projection from one, +/// whose representation its instances decide. +#[derive(Clone)] +pub struct Decided<'tcx> { + /// The field whose type holds it. + pub field: DefId, + /// It, over the definition's own parameters. + pub part: Ty<'tcx>, + /// What an `Option` or a `Poll` holds, an `Option`-like `ControlFlow` continues with, any + /// other `ControlFlow` breaks with, or a future outputs. + pub inner: Ty<'tcx>, + /// TypeScript's type of `inner` in the definition. + pub defined: Type, + /// What its instances decide of it. + pub decides: Decides, +} + +/// What an instance decides of a [`Decided`] part. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum Decides { + /// An `Option`'s `None`, or that of a `ControlFlow` typed as one. + Option, + /// A `Poll`'s `Pending`. + Poll, + /// Whether a `ControlFlow` typed as an `rs.Result` of its break stays one, which an + /// `Option` or `Result` break makes otherwise. + Flow, + /// Whether a future's output can be `rs.Pending`, as the future's own `Pending` is. + Future, +} + +/// A [`Decided`] part of the definition of the crate's generic `adt`, at `args` over the +/// parameters of the definition that checks it: its own at its own parameters, or an +/// instance's it holds. +#[derive(Clone)] +pub struct Check<'tcx> { + pub adt: DefId, + pub decided: Decided<'tcx>, + pub args: GenericArgsRef<'tcx>, +} + +/// `args`, over a definition's parameters, at that definition's instance `at`. +pub fn instantiate_args<'tcx>( + tcx: ty::TyCtxt<'tcx>, + env: TypingEnv<'tcx>, + args: GenericArgsRef<'tcx>, + at: GenericArgsRef<'tcx>, +) -> GenericArgsRef<'tcx> { + let bound = ty::EarlyBinder::bind(tcx, args); + tcx.try_instantiate_and_normalize_erasing_regions(at, env, bound) + .unwrap_or_else(|_| bound.instantiate(tcx, at).skip_norm_wip()) +} + +/// The state of typing definitions. +#[derive(Default)] +pub struct Defining<'tcx> { + records: rustc_data_structures::fx::FxHashMap>, + /// The definitions being typed, innermost last. + typing: Vec, + /// Definitions typed, waiting on one shallower in [`Self::typing`] they were typed with. + members: Vec, + /// Instances of definitions still being typed, by the [`Type::Later`] each typed. + pending: Vec>, + /// How many projections and decided parts every record holds, which grows while + /// instances are filled. + recorded: usize, + /// The field of the definition being typed whose type is. + pub field: Option, + /// The instances being typed in the type expression being typed, which a definition + /// starts afresh. + pub(super) instancing: Vec>, + /// The TypeScript type of each instance typed in that type expression, which one span + /// refuses alike wherever in it, so a deep one is typed once. + pub(super) instanced: rustc_data_structures::fx::FxHashMap, Type>, + /// Whether that type expression nested past the crate's recursion limit, which is + /// refused, so nothing else in it is typed. + pub(super) too_deep: bool, + /// The instances whose drop glue is being classified, by what it drops through. + pub(super) glue_open: Vec>, + /// The shallowest of [`Self::glue_open`] the classification under way rested on. + pub(super) glue_rests: usize, + /// Each classification of an instance's glue, once it rests on none still under way. + pub(super) glue_known: rustc_data_structures::fx::FxHashMap<(Ty<'tcx>, super::drop::Asked), bool>, + /// Each that holds if the one under way it rested on, by its depth there, does. + pub(super) glue_resting: rustc_data_structures::fx::FxHashMap<(Ty<'tcx>, super::drop::Asked), usize>, + /// Those, in the order they were classified. + pub(super) glue_order: Vec<(Ty<'tcx>, super::drop::Asked)>, + /// How deep in projection arguments the type being typed is. + pub(super) projecting: usize, + /// The alias naming each instance without type parameters a projection argument held. + aliases: rustc_data_structures::fx::FxHashMap, SymId>, + /// The aliases of enum instances, by the enum, whose union each spells out at its + /// instance, as TypeScript refuses an alias that names itself through a generic alias. + enum_aliases: Vec<(SymId, SymId)>, +} + +struct Typing { + adt: DefId, + members: usize, + pending: usize, +} + +/// A definition typed, and the type of each of its fields there, which may hold +/// [`Type::Later`]s until its cycle completes. +struct Member { + adt: DefId, + item: usize, + fields: Vec<(DefId, Type)>, + span: Span, +} + +struct Pending<'tcx> { + adt: DefId, + args: GenericArgsRef<'tcx>, + /// The definition typing it, and the field whose type did. + at: Option<(DefId, TypingEnv<'tcx>)>, + field: Option, + span: Span, + /// Its projection arguments as last filled in. + filled: Option>, +} + +impl<'tcx> Translator<'_, 'tcx> { + /// The record of the crate's generic `adt`, defining it if it isn't yet. + pub fn defined(&mut self, adt: DefId) -> &Defined<'tcx> { + if !self.defining_state.records.contains_key(&adt) { + let tcx = self.tcx; + self.adt(tcx.adt_def(adt), tcx.def_span(adt)); + } + &self.defining_state.records[&adt] + } + + /// Run `f` outside the definition being typed and the type expression in it, as for + /// another definition, or a trait object's, whose types are over its own parameters. + pub(super) fn outside_definition(&mut self, f: impl FnOnce(&mut Self) -> R) -> R { + let defining = self.defining.take(); + let state = &mut self.defining_state; + let field = state.field.take(); + let instancing = std::mem::take(&mut state.instancing); + let instanced = std::mem::take(&mut state.instanced); + let too_deep = std::mem::take(&mut state.too_deep); + let projecting = std::mem::take(&mut state.projecting); + let r = f(self); + self.defining = defining; + let state = &mut self.defining_state; + (state.field, state.instancing, state.instanced) = (field, instancing, instanced); + (state.too_deep, state.projecting) = (too_deep, projecting); + r + } + + /// Start typing the definition of `adt`. + pub(super) fn start_definition(&mut self, adt: DefId) { + let state = &mut self.defining_state; + state.records.insert( + adt, + Defined { + open: Some(state.typing.len()), + ..Default::default() + }, + ); + state.typing.push(Typing { + adt, + members: state.members.len(), + pending: state.pending.len(), + }); + } + + /// Finish typing the definition of `adt`, whose item is `item` and whose fields typed as + /// `fields`: complete it, with every definition typed with it, unless it was typed with + /// one shallower that is still being typed. + pub(super) fn finish_definition(&mut self, adt: DefId, item: usize, fields: Vec<(DefId, Type)>, span: Span) { + let state = &mut self.defining_state; + let depth = state.typing.len() - 1; + state.members.push(Member { + adt, + item, + fields, + span, + }); + let low = state.records[&adt].open.expect("an open definition"); + if low == depth && self.complete(depth) { + self.defining_state.typing.pop(); + return; + } + let state = &mut self.defining_state; + let low = state.records[&adt].open.expect("an open definition"); + state.typing.pop(); + let parent = state.typing.len() - 1; + state.lower_typing(parent, low); + } + + /// The TypeScript parameter a projection `ty` from type parameters is in the definition + /// being typed, recording it while that definition is open. + pub(super) fn projection_param(&mut self, ty: Ty<'tcx>) -> Option { + let (adt, _) = self.defining?; + let ty::Alias(_, alias) = ty.kind() else { + return None; + }; + let item = alias.kind.try_to_projection()?; + if !ty.has_param() { + return None; + } + let tcx = self.tcx; + let record = self.defining_state.records.get_mut(&adt)?; + if let Some((_, name)) = record.projections.iter().find(|(p, _)| *p == ty) { + return Some(Type::Param(name.clone())); + } + record.open?; + // Named for its associated type, numbered past any name it would shadow. + let taken: Vec = own_params(tcx, adt) + .chain(record.projections.iter().map(|(_, name)| name.clone())) + .collect(); + let base = tcx.item_name(item).to_string(); + let name = (1..) + .map(|n| match n { + 1 => base.clone(), + n => format!("{base}{n}"), + }) + .find(|name| !taken.contains(name)) + .unwrap(); + record.projections.push((ty, name.clone())); + self.defining_state.recorded += 1; + Some(Type::Param(name)) + } + + /// Note that the definition being typed typed `part`, of `inner`, typed `defined`, for + /// the check of its instances, if they decide it. + pub(super) fn note_decided(&mut self, part: Ty<'tcx>, inner: Ty<'tcx>, defined: &Type, decides: Decides) { + let (Some((adt, _)), Some(field)) = (self.defining, self.defining_state.field) else { + return; + }; + let depends = match decides { + Decides::Flow => inner.has_param(), + _ => self.erases_to(inner).param, + }; + if !depends { + return; + } + let identity = ty::GenericArgs::identity_for_item(self.tcx, adt); + self.add_check( + adt, + Check { + adt, + decided: Decided { + field, + part, + inner, + defined: defined.clone(), + decides, + }, + args: identity, + }, + ); + } + + /// Add `check` to the record of the open definition of `adt` unless one checks the same. + fn add_check(&mut self, adt: DefId, check: Check<'tcx>) { + let tcx = self.tcx; + let env = TypingEnv::post_analysis(tcx, adt); + let d = &check.decided; + let part = super::copy::instantiate(tcx, env, d.part, check.args); + let inner = super::copy::instantiate(tcx, env, d.inner, check.args); + let key = (check.adt, d.decides, d.part, part, inner); + let Some(record) = self.defining_state.records.get_mut(&adt) else { + return; + }; + if record.open.is_some() && record.checked.insert(key) { + record.checks.push(check); + self.defining_state.recorded += 1; + } + } + + /// Note that the definition being typed typed `instance`, an instance of the crate's + /// generic type, so it checks the parts that instance's definition decided too. One in a + /// projection argument is not: an instance of the definition types it at its own + /// arguments, which checks it there. + pub(super) fn note_held(&mut self, instance: Ty<'tcx>) { + let (Some((adt, _)), Some(_)) = (self.defining, self.defining_state.field) else { + return; + }; + if !instance.has_param() || self.defining_state.projecting > 0 { + return; + } + let Some(record) = self.defining_state.records.get_mut(&adt) else { + return; + }; + if record.open.is_some() && !record.held.contains(&instance) { + record.held.push(instance); + } + } + + /// The projection arguments of an instance of the crate's generic `adt` with `args`, a + /// definition still being typed, as a [`Type::Later`] filled in once it is complete. + pub(super) fn later_projections(&mut self, adt: DefId, args: GenericArgsRef<'tcx>, span: Span) -> Option { + let state = &mut self.defining_state; + let low = state.records.get(&adt)?.open?; + // Whatever types it is typed with it. + if let Some(top) = state.typing.len().checked_sub(1) { + state.lower_typing(top, low); + } + // Typed by the same definition before, so filling either in can't name it again + // without end. + let at = self.defining.map(|(did, _)| did); + if at.is_some() + && let Some(id) = + (state.pending.iter()).position(|p| p.adt == adt && p.args == args && p.at.map(|(did, _)| did) == at) + { + return Some(Type::Later(id)); + } + state.pending.push(Pending { + adt, + args, + at: self.defining, + field: state.field, + span, + filled: None, + }); + Some(Type::Later(state.pending.len() - 1)) + } + + /// Whether an instance of the crate's generic `adt` may name projections: it names some, + /// or its definition is still being typed. + pub(super) fn may_project(&self, adt: DefId) -> bool { + (self.defining_state.records.get(&adt)).is_some_and(|r| r.open.is_some() || !r.projections.is_empty()) + } + + /// The alias naming `instance`, an instance of the crate's generic type `info` without + /// type parameters, which a projection argument holds: `Held$Looped` for `Held`, + /// whose module exports `type Held$Looped = Held`. Defined the first + /// time, and named while it is, so an instance its own projections hold again names it. + pub(super) fn instance_alias(&mut self, instance: Ty<'tcx>, info: &Adt, span: Span) -> Type { + if let Some(&alias) = self.defining_state.aliases.get(&instance) { + return Type::Sym(alias, Vec::new()); + } + let tcx = self.tcx; + let ty::Adt(adt, args) = *instance.kind() else { + unreachable!("an instance of a generic type") + }; + let did = adt.did(); + // Defaults included, so no alias is named as its type is. + let alias = self.program.sym(Symbol { + module: self.type_module(did), + base: tcx.item_name(did).to_string(), + suffix: super::names::args(tcx, args.as_slice()).collect::>().join("_"), + owner: None, + kind: SymKind::Union, + order: self.order(tcx.def_span(did)), + span: tcx.def_span(did), + instance: String::new(), + name: String::new(), + alias: None, + }); + self.defining_state.aliases.insert(instance, alias); + // Typed as anywhere else, outside the projection argument. + let projecting = std::mem::take(&mut self.defining_state.projecting); + let ty = self.instance_ty(instance, info, span); + self.defining_state.projecting = projecting; + // Refused past the recursion limit, as each use of it is again. + if self.defining_state.too_deep { + self.defining_state.aliases.remove(&instance); + return Type::Builtin("unknown"); + } + if adt.is_enum() { + self.defining_state.enum_aliases.push((alias, info.sym)); + } + self.program.items.push(Item::Union { + sym: alias, + params: Vec::new(), + ty, + doc: None, + }); + Type::Sym(alias, Vec::new()) + } + + /// Spell out each enum instance's alias as the enum's union at the instance, once every + /// definition is complete. + pub(super) fn expand_enum_aliases(&mut self) { + let items: rustc_data_structures::fx::FxHashMap = (self.program.items.iter().enumerate()) + .filter_map(|(i, item)| match item { + Item::Union { sym, .. } => Some((*sym, i)), + _ => None, + }) + .collect(); + for (alias, adt) in std::mem::take(&mut self.defining_state.enum_aliases) { + let Item::Union { params, ty: union, .. } = &self.program.items[items[&adt]] else { + unreachable!("an enum's union") + }; + let Item::Union { + ty: Type::Sym(_, args), .. + } = &self.program.items[items[&alias]] + else { + unreachable!("an alias of an enum instance") + }; + let expanded = union.subst(&|name| params.iter().position(|p| p == name).map(|i| args[i].clone())); + let Item::Union { ty, .. } = &mut self.program.items[items[&alias]] else { + unreachable!("an alias") + }; + *ty = expanded; + } + } + + /// Start typing `instance`, an instance of the crate's generic type, unless it is + /// typed already further out in the same type expression over type parameters, which no + /// alias names: a projection of its parameters is then a type whose arguments hold it + /// again, so its TypeScript type arguments would never end, which is refused. + pub(super) fn enter_instance(&mut self, instance: Ty<'tcx>, span: Span) -> bool { + let instancing = &self.defining_state.instancing; + if self.defining_state.too_deep { + return false; + } + let msg = match () { + _ if instance.has_param() && instancing.contains(&instance) => format!( + "`{instance}` is not supported yet: a projection of its parameters is a type whose arguments hold `{instance}` again, so its TypeScript type arguments would never end" + ), + // Named by the outermost, which the source wrote. + _ if instancing.len() > self.tcx.recursion_limit().0 => { + self.defining_state.too_deep = true; + format!( + "`{}` is not supported: its projections' values nest instances past the crate's recursion limit", + instancing[0] + ) + } + _ => { + self.defining_state.instancing.push(instance); + return true; + } + }; + self.err(span, msg); + false + } + + /// Finish typing the instance [`Self::enter_instance`] started, as `ty` if typed whole. + pub(super) fn leave_instance(&mut self, instance: Ty<'tcx>, ty: Option<&Type>) { + let state = &mut self.defining_state; + state.instancing.pop(); + match (state.instancing.is_empty(), ty) { + (true, _) => { + state.instanced.clear(); + state.too_deep = false; + } + (false, Some(ty)) => { + state.instanced.insert(instance, ty.clone()); + } + (false, None) => {} + } + } + + /// The TypeScript type of `instance` if the type expression being typed typed it already. + pub(super) fn instanced(&self, instance: Ty<'tcx>) -> Option { + self.defining_state.instanced.get(&instance).cloned() + } + + /// Complete the definition at `depth` in [`Defining::typing`] and every one typed with + /// it: fill in the projection arguments of the instances they typed, and take in what + /// each instance they hold decided, until no record grows, then close their records and + /// settle what reads them. Filling may name an instance of a definition further out + /// that is still being typed, which then completes them with its own, so this returns + /// whether they completed. + /// + /// Each round fills in what the round before named, so a finite layout settles in as + /// many rounds as its chain of instances and projections is long. A type that holds + /// itself at ever other arguments never settles, so, as rustc bounds its own recursion, + /// more rounds than the crate's recursion limit are refused at the definition. + fn complete(&mut self, depth: usize) -> bool { + let tcx = self.tcx; + let (members, pending) = { + let typing = &self.defining_state.typing[depth]; + (typing.members, typing.pending) + }; + let mut rounds = 0; + let settled = loop { + let recorded = self.defining_state.recorded; + let count = self.defining_state.pending.len(); + for i in pending..count { + self.fill_pending(i); + } + self.take_held(members); + if self.defining_state.recorded == recorded && self.defining_state.pending.len() == count { + break true; + } + rounds += 1; + if rounds > tcx.recursion_limit().0 { + break false; + } + }; + if !settled { + let state = &mut self.defining_state; + for p in &mut state.pending[pending..] { + p.filled = Some(vec![Type::Builtin("unknown"); state.records[&p.adt].projections.len()]); + } + // Refused, so nothing of its instances is checked: the checks it took in, of ever + // deeper instances, would each type one deeper again. + for member in &state.members[members..] { + state.records.get_mut(&member.adt).expect("a record").checks.clear(); + } + // The definition completing them all, which finished typing last. + let root = state.members.last().expect("the definition completing"); + let instance = Ty::new_adt( + tcx, + tcx.adt_def(root.adt), + ty::GenericArgs::identity_for_item(tcx, root.adt), + ); + let span = tcx.def_span(root.adt); + self.err( + span, + format!( + "`{instance}` is not supported: it holds itself at ever other arguments, whose projections name new instances or projections past the crate's recursion limit" + ), + ); + } + let root = self.defining_state.typing[depth].adt; + if self.defining_state.records[&root].open.is_some_and(|low| low < depth) { + return false; + } + let done: Vec = self.defining_state.members.drain(members..).collect(); + for member in &done { + let record = self.defining_state.records.get_mut(&member.adt).expect("a record"); + record.open = None; + } + // Each instance typed while open now has its projection arguments. + let filled: Vec> = (self.defining_state.pending[pending..].iter()) + .map(|p| p.filled.clone().unwrap_or_default()) + .collect(); + // One of a cycle further out, still being typed, is left for it. + let later = |id: usize| id.checked_sub(pending).map(|i| filled[i].clone()); + let mut endless = false; + // Wherever a type typed while they were open is kept: an item, such as an alias or a + // trait object's type, made then or before, and the methods objects hold. + if !filled.is_empty() { + for item in &mut self.program.items { + let tys: Vec<&mut Type> = match item { + Item::Struct { fields, .. } => fields.iter_mut().map(|f| &mut f.ty).collect(), + Item::Union { ty, .. } | Item::Value { ty, .. } => vec![ty], + Item::Function(_) => continue, + }; + for ty in tys { + endless |= ty.fill(&later).is_none(); + } + } + endless |= self.fill_objects(&later); + } + let mut members_done = Vec::with_capacity(done.len()); + for mut member in done { + for (_, ty) in &mut member.fields { + endless |= ty.fill(&later).is_none(); + } + // Its own parameters, then one per projection. + let names = (self.defining_state.records[&member.adt].projections.iter()).map(|(_, name)| name.clone()); + let item = &mut self.program.items[member.item]; + if let Item::Struct { params, .. } | Item::Union { params, .. } = item { + params.extend(names); + } + super::unnamed_params(item); + members_done.push(member); + } + // The definition completing them all, which finished typing last. + if endless && let Some(root) = members_done.last() { + self.err( + root.span, + "a type whose projection is, at its own parameters, a type that holds it again, so its TypeScript type arguments would never end", + ); + } + for member in &members_done { + for (field, ty) in &member.fields { + self.note_field(*field, ty); + } + } + // The checks of instances typed while their definitions were open. + let checks: Vec> = self.defining_state.pending.drain(pending..).collect(); + for check in checks { + let outer = std::mem::replace(&mut self.defining, check.at); + let adt = tcx.adt_def(check.adt); + if let Some(msg) = self.generic_erasure(adt, check.args, check.span) { + self.err(check.span, msg); + } + self.defining = outer; + } + for member in members_done { + let adt = tcx.adt_def(member.adt); + let info = self.adts[&member.adt].clone(); + self.drop_glue(adt, &info, member.span); + } + true + } + + /// Take into each definition from `members` on in [`Defining::members`] the checks of + /// each instance it holds, at that instance's arguments, so an instance of the + /// definition checks them as the instance it holds there would be: `Outer` holding + /// `Inner` checks `Inner`'s `Option` at `Outer`'s instances. + fn take_held(&mut self, members: usize) { + let tcx = self.tcx; + let adts: Vec = self.defining_state.members[members..].iter().map(|m| m.adt).collect(); + for adt in adts { + let env = TypingEnv::post_analysis(tcx, adt); + let held = self.defining_state.records[&adt].held.clone(); + for instance in held { + let ty::Adt(def, args) = *instance.kind() else { + unreachable!("an instance of a generic type") + }; + let Some(record) = self.defining_state.records.get(&def.did()) else { + continue; + }; + for check in record.checks.clone() { + let args = instantiate_args(tcx, env, check.args, args); + self.add_check(adt, Check { args, ..check }); + } + } + } + } + + /// Fill in the projection arguments of the instance `pending[i]` typed, from its + /// definition's projections so far. Filling them in may name more projections or + /// instances, which the next round of [`Self::complete`] fills in turn. + fn fill_pending(&mut self, i: usize) { + let p = &self.defining_state.pending[i]; + let projections: Vec> = (self.defining_state.records[&p.adt].projections.iter()) + .map(|(p, _)| *p) + .collect(); + if p.filled.as_ref().is_some_and(|f| f.len() == projections.len()) { + return; + } + let (args, at, field, span) = (p.args, p.at, p.field, p.span); + let env = at.map_or(self.typing_env(), |(_, env)| env); + let outer = std::mem::replace(&mut self.defining, at); + let outer_field = std::mem::replace(&mut self.defining_state.field, field); + self.defining_state.projecting += 1; + let tys: Vec = projections + .iter() + .map(|&p| { + let at = super::copy::instantiate(self.tcx, env, p, args); + self.ty(at, span) + }) + .collect(); + self.defining_state.projecting -= 1; + self.defining = outer; + self.defining_state.field = outer_field; + self.defining_state.pending[i].filled = Some(tys); + } +} + +impl Defining<'_> { + /// Note that the definition at `depth` in [`Self::typing`] was typed with the one at `low`. + fn lower_typing(&mut self, depth: usize, low: usize) { + let adt = self.typing[depth].adt; + if let Some(open) = &mut self.records.get_mut(&adt).expect("a record").open { + *open = (*open).min(low); + } + } +} + +/// The names of `adt`'s own type parameters. +fn own_params(tcx: ty::TyCtxt<'_>, adt: DefId) -> impl Iterator + '_ { + (tcx.generics_of(adt).own_params.iter()) + .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { .. })) + .map(|param| param.name.to_string()) +} diff --git a/ts/src/lower/drop.rs b/ts/src/lower/drop.rs index 5f3bf083c..63f43ddc1 100644 --- a/ts/src/lower/drop.rs +++ b/ts/src/lower/drop.rs @@ -15,6 +15,15 @@ use super::{Adt, AdtRepr, Translator}; use crate::program::{SymKind, Symbol}; use crate::ts::{self, Expr, Param, Stmt, StmtKind, Type}; +/// What [`Translator::glue_all`] asks of what an instance's glue drops through. +#[derive(Clone, Copy, PartialEq, Eq, Hash)] +pub enum Asked { + /// That JS sees none of it drop. + Inert, + /// That each drops through its own `[Symbol.dispose]`, giving glue where it needs it if so. + Disposable(bool), +} + impl<'a, 'tcx> Translator<'a, 'tcx> { /// Whether dropping a `ty` does something JS can see. pub fn drops(&mut self, ty: Ty<'tcx>) -> bool { @@ -125,8 +134,10 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { ty::Closure(..) | ty::CoroutineClosure(..) => { super::captured(ty).is_some_and(|tys| tys.iter().any(|t| self.drops(t))) } - // Whatever it was made of may drop. + // Whatever it was made of may drop, as may what a projection from a type + // parameter is at an instance. ty::Coroutine(..) | ty::Param(_) | ty::Dynamic(..) => true, + ty::Alias(..) => ty.has_param(), _ => false, }; self.drops_open.remove(&ty); @@ -201,7 +212,9 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { None | Some(Std::Peekable) if self.std_iter(ty) => self.closures_held(ty), Some(_) => false, None if self.shared_glue(*adt) => { - if !args.types().all(|t| self.disposable(t, glue)) { + if !self.glue_all(ty, *adt, args, Asked::Disposable(glue.is_some()), |t, held| { + t.disposable(held, glue) + }) { return false; } if let Some(span) = glue { @@ -214,11 +227,105 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { }, // A closure's `[Symbol.dispose]` drops what it owns, a `dyn Future`'s what it is, and // another trait object's what it wraps. - ty::Closure(..) | ty::CoroutineClosure(..) | ty::Coroutine(..) | ty::Param(_) | ty::Dynamic(..) => true, + ty::Closure(..) + | ty::CoroutineClosure(..) + | ty::Coroutine(..) + | ty::Param(_) + | ty::Alias(..) + | ty::Dynamic(..) => true, _ => false, } } + /// Whether `f`, which `asked` names, holds of everything [`Self::glue_held`] has `ty`, an + /// instance of `adt` with `args`, drop through. It holds of an instance already being + /// asked about, which a projection whose value holds the instance again reaches: what + /// the instance drops through there it drops through already. Each answer is kept, once + /// it no longer rests on an instance still being asked about, so an instance is asked + /// about once however many paths reach it. What nests past the crate's recursion limit + /// is refused. + fn glue_all( + &mut self, + ty: Ty<'tcx>, + adt: AdtDef<'tcx>, + args: ty::GenericArgsRef<'tcx>, + asked: Asked, + f: impl Fn(&mut Self, Ty<'tcx>) -> bool, + ) -> bool { + let key = (ty, asked); + let state = &mut self.defining_state; + if let Some(&all) = state.glue_known.get(&key) { + return all; + } + // What rests on the instances it rested on. + if let Some(&rests) = state.glue_resting.get(&key) { + state.glue_rests = state.glue_rests.min(rests); + return true; + } + if let Some(open) = state.glue_open.iter().position(|t| *t == ty) { + state.glue_rests = state.glue_rests.min(open); + return true; + } + if state.glue_open.len() > self.tcx.recursion_limit().0 { + // At the definition of the outermost, which it names. + let outer = state.glue_open[0]; + let span = match outer.kind() { + ty::Adt(outer, _) => self.tcx.def_span(outer.did()), + _ => self.tcx.def_span(adt.did()), + }; + self.err( + span, + format!( + "dropping `{outer}` is not supported: what its glue drops through, by its projections, nests past the crate's recursion limit" + ), + ); + return false; + } + let depth = state.glue_open.len(); + state.glue_open.push(ty); + let outer_rests = std::mem::replace(&mut state.glue_rests, usize::MAX); + let resting = state.glue_order.len(); + let all = self.glue_held(adt, args).into_iter().all(|held| f(self, held)); + let state = &mut self.defining_state; + state.glue_open.pop(); + let rests = std::mem::replace(&mut state.glue_rests, outer_rests); + match () { + // Still resting on one further out, whose answer decides it too. + _ if all && rests < depth => { + state.glue_rests = state.glue_rests.min(rests); + state.glue_resting.insert(key, rests); + state.glue_order.push(key); + } + _ => { + // Each answer that rested on it holds if it does. + for rested in state.glue_order.drain(resting..) { + state.glue_resting.remove(&rested); + if all { + state.glue_known.insert(rested, true); + } + } + state.glue_known.insert(key, all); + } + } + all + } + + /// What a generic struct's glue drops through, at an instance with `args`: each type + /// argument, and what each projection from them its fields name is there. + fn glue_held(&mut self, adt: AdtDef<'tcx>, args: ty::GenericArgsRef<'tcx>) -> Vec> { + let mut held: Vec> = args.types().collect(); + if self.crates.translates(adt.did()) { + let env = self.typing_env_pub(); + let projections: Vec> = self.defined(adt.did()).projections.iter().map(|(p, _)| *p).collect(); + held.extend( + projections + .into_iter() + .map(|p| super::copy::instantiate(self.tcx, env, p, args)), + ); + } + held + } + /// Whether every JS value of `ty`, a type that drops and is [`Self::disposable`], is an /// object with `[Symbol.dispose]`, which a drop calls directly rather than through /// `rs.drop`'s one megamorphic site. An `Option` may be `None`, and a type parameter, a @@ -392,7 +499,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { Some(Std::Context) => false, Some(_) => true, // Its glue, if an instance that drops gave it one, drops its type parameters' fields. - None if adt.is_struct() => args.types().all(|t| self.inert(t)), + None if adt.is_struct() => self.glue_all(ty, *adt, args, Asked::Inert, |t, held| t.inert(held)), None => true, }, _ => true, @@ -675,8 +782,12 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { // Only an instance whose parameters drop runs the glue, so none is a byte: a field // whose definition's type an instance decides is read as an array of them holds it. let glue = std::mem::replace(&mut self.glue, true); + // Its fields' types over its parameters, and the projections from them it names. + let identity = ty::GenericArgs::identity_for_item(tcx, adt.did()); + let env = ty::TypingEnv::post_analysis(tcx, adt.did()); + let defining = self.defining.replace((adt.did(), env)); for (field, &id) in adt.non_enum_variant().fields.iter().zip(fields) { - let ty = tcx.type_of(field.did).instantiate_identity().skip_norm_wip(); + let ty = super::copy::field_ty(tcx, env, field.did, identity); let read = match self.instanced_fields.contains_key(&field.did) { true => Expr::As(Box::new(Translator::read_field(Expr::This, id)), self.ty(ty, span)), false => Translator::read_field(Expr::This, id), @@ -686,6 +797,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { } } self.glue = glue; + self.defining = defining; let sym = self.program.sym(Symbol { module: self.module_of(adt.did()), base: "[Symbol.dispose]".into(), diff --git a/ts/src/lower/dynamic.rs b/ts/src/lower/dynamic.rs index 5138b7171..da2352f28 100644 --- a/ts/src/lower/dynamic.rs +++ b/ts/src/lower/dynamic.rs @@ -160,7 +160,8 @@ impl<'tcx> Translator<'_, 'tcx> { return None; }; if !self.objects.contains_key(&principal) { - self.define_object(principal, ty, span)?; + // Over the trait's own parameters, whatever definition is typing it. + self.outside_definition(|t| t.define_object(principal, ty, span))?; } let args = self.object_args(principal, ty, span); let sym = self.objects[&principal].sym; @@ -352,6 +353,11 @@ impl<'tcx> Translator<'_, 'tcx> { /// The object of `principal` holding its method `index` from now on: in its type, and in /// each class its objects wrap a value in. fn hold(&mut self, principal: DefId, index: usize, span: Span) { + self.outside_definition(|t| t.hold_method(principal, index, span)); + } + + /// [`Self::hold`], outside any definition being typed. + fn hold_method(&mut self, principal: DefId, index: usize, span: Span) { let tcx = self.tcx; let object = &self.objects[&principal]; let method = &object.methods[index]; @@ -402,6 +408,18 @@ impl<'tcx> Translator<'_, 'tcx> { } } + /// Fill in the [`Type::Later`]s of the methods objects hold, as [`Type::fill`] does, + /// returning whether one reaches itself. + pub(super) fn fill_objects(&mut self, later: &impl Fn(usize) -> Option>) -> bool { + let mut endless = false; + for object in self.objects.values_mut() { + for ty in object.methods.iter_mut().filter_map(|m| m.ty.as_mut()) { + endless |= ty.fill(later).is_none(); + } + } + endless + } + /// Whether an upcast from the trait object `from` to `to`, a made object, is cast to /// `to`'s type: a generic trait's, whose methods have a form only its arguments decide /// where `from`'s have another. diff --git a/ts/src/lower/iter.rs b/ts/src/lower/iter.rs index 08137630c..68773627d 100644 --- a/ts/src/lower/iter.rs +++ b/ts/src/lower/iter.rs @@ -44,7 +44,7 @@ impl<'tcx> Translator<'_, 'tcx> { let tcx = self.tcx; let (_, item) = trait_items(tcx)?; let projection = Ty::new_projection(tcx, ty::IsRigid::No, item, [ty]); - let env = self.defining.unwrap_or(self.typing_env_pub()); + let env = self.defining.map_or(self.typing_env_pub(), |(_, env)| env); tcx.try_normalize_erasing_regions(env, ty::Unnormalized::new_wip(projection)) .ok() } diff --git a/ts/src/lower/mir/decided.rs b/ts/src/lower/mir/decided.rs index 6ed916198..09296b3a4 100644 --- a/ts/src/lower/mir/decided.rs +++ b/ts/src/lower/mir/decided.rs @@ -1015,11 +1015,15 @@ fn union(a: &[u128], b: &[u128]) -> Vec { } /// Whether a value of `ty` can change what it points at: it is or holds a `&mut` or a -/// `*mut`, or hides what it holds. +/// `*mut`, or hides what it holds, as a type whose fields hold ever deeper instances, past +/// the crate's recursion limit, may. fn lends<'tcx>(tcx: TyCtxt<'tcx>, crates: &Crates<'tcx>, ty: Ty<'tcx>) -> bool { let mut seen = FxHashSet::default(); - let mut stack = vec![ty]; - while let Some(ty) = stack.pop() { + let mut stack = vec![(ty, 0)]; + while let Some((ty, depth)) = stack.pop() { + if depth > tcx.recursion_limit().0 { + return true; + } for t in ty.walk().filter_map(|arg| arg.as_type()) { match t.kind() { ty::Ref(_, _, ty::Mutability::Mut) @@ -1028,7 +1032,10 @@ fn lends<'tcx>(tcx: TyCtxt<'tcx>, crates: &Crates<'tcx>, ty: Ty<'tcx>) -> bool { | ty::Alias(..) | ty::Param(_) => return true, ty::Adt(adt, args) if crates.translates(adt.did()) && seen.insert(t) => { - stack.extend(adt.all_fields().map(|field| field.ty(tcx, args).skip_norm_wip())); + stack.extend( + adt.all_fields() + .map(|field| (field.ty(tcx, args).skip_norm_wip(), depth + 1)), + ); } _ => {} } diff --git a/ts/src/lower/mir/mod.rs b/ts/src/lower/mir/mod.rs index b474845ab..cffdde7e1 100644 --- a/ts/src/lower/mir/mod.rs +++ b/ts/src/lower/mir/mod.rs @@ -3654,10 +3654,13 @@ impl<'tcx> Translator<'_, 'tcx> { /// Whether `f` holds for any type a value of `ty` holds: its type arguments, which are /// what std's types hold, and the fields of the crate's own types, normalized in `env`. + /// Fields nested past the crate's recursion limit, as a type whose fields hold it at + /// ever deeper arguments nests them, may hold anything. pub(crate) fn reaches(&self, env: TypingEnv<'tcx>, ty: Ty<'tcx>, mut f: impl FnMut(Ty<'tcx>) -> bool) -> bool { + let limit = self.tcx.recursion_limit().0; let mut seen = FxHashSet::default(); - let mut stack = vec![ty]; - while let Some(ty) = stack.pop() { + let mut stack = vec![(ty, 0)]; + while let Some((ty, depth)) = stack.pop() { for t in ty.walk().filter_map(|arg| arg.as_type()) { if f(t) { return true; @@ -3666,7 +3669,13 @@ impl<'tcx> Translator<'_, 'tcx> { && self.own(adt.did()) && seen.insert(t) { - stack.extend(adt.all_fields().map(|field| field_ty(self.tcx, env, field.did, args))); + if depth >= limit { + return true; + } + stack.extend( + adt.all_fields() + .map(|field| (field_ty(self.tcx, env, field.did, args), depth + 1)), + ); } } } diff --git a/ts/src/lower/mod.rs b/ts/src/lower/mod.rs index b4e617248..91b8e4e42 100644 --- a/ts/src/lower/mod.rs +++ b/ts/src/lower/mod.rs @@ -15,6 +15,7 @@ mod caller; mod collections; mod consts; mod copy; +mod defined; mod drop; mod dynamic; mod float; @@ -66,6 +67,7 @@ pub fn translate<'tcx>(tcx: TyCtxt<'tcx>, config: &Config) -> Option { if t.failed { return None; } + t.expand_enum_aliases(); t.program.names = t.names(); t.program.mark_unread(); t.program.merge(); @@ -209,15 +211,17 @@ pub struct Translator<'a, 'tcx> { /// by that type, which an instance's value is cast to so TypeScript infers the /// instance's arguments from it rather than from the `None` or `Pending` it may be. decided_fields: rustc_data_structures::fx::FxHashMap, + /// What typing each generic type's definition named, and the definitions being typed. + pub(super) defining_state: defined::Defining<'tcx>, /// Source files by name, as indexes into `program.sources`. sources: rustc_data_structures::fx::FxHashMap>, failed: bool, /// Where trait bounds come from: none outside a census, which lowers some functions /// over their own type parameters. env: TypingEnv<'tcx>, - /// Where the bounds of a generic type's parameters come from while its fields lower, by - /// which an iterator's item type over them normalizes. - defining: Option>, + /// The generic type whose fields lower, and where the bounds of its parameters come + /// from, by which an iterator's item type over them normalizes. + defining: Option<(DefId, TypingEnv<'tcx>)>, /// Whether this is a census, which lowers some functions over their type parameters and /// writes nothing. census: bool, @@ -507,6 +511,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { overlays: Default::default(), instanced_fields: Default::default(), decided_fields: Default::default(), + defining_state: Default::default(), sources: Default::default(), failed: false, env: TypingEnv::fully_monomorphized(), @@ -1108,7 +1113,8 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { // Its fields' types are refused where they are written, whatever reached it. let held = std::mem::replace(&mut self.held, false); let glue = std::mem::replace(&mut self.glue, false); - let info = self.define(adt, span); + // A named type, so an instance its fields hold again ends there. + let info = self.outside_definition(|t| t.define(adt, span)); (self.held, self.glue) = (held, glue); info } @@ -1116,6 +1122,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { fn define(&mut self, adt: AdtDef<'tcx>, span: Span) -> Adt { let tcx = self.tcx; let did = adt.did(); + self.start_definition(did); let mut overlay = None; let repr = match () { _ if adt.is_struct() => { @@ -1186,6 +1193,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { } self.adts.insert(did, info.clone()); + // Its own, then one per projection typing its fields names, once they all are. let params: Vec = tcx .generics_of(did) .own_params @@ -1196,6 +1204,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { ty::GenericParamDefKind::Lifetime | ty::GenericParamDefKind::Const { .. } => None, }) .collect(); + let mut typed = Vec::new(); let item = match &info.repr { AdtRepr::Struct { ctor, fields } => { let variant = adt.non_enum_variant(); @@ -1204,12 +1213,16 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { let span = tcx.def_span(field.did); let doc = self.doc(field.did); match held { - StructField::Whole(id) => defined.push(ts::Field { - id, - ty: self.defined_field_ty(field, did, span), - doc, - init: ts::FieldInit::Ctor, - }), + StructField::Whole(id) => { + let ty = self.defined_field_ty(field, did, span); + typed.push((field.did, ty.clone())); + defined.push(ts::Field { + id, + ty, + doc, + init: ts::FieldInit::Ctor, + }); + } StructField::Slice(ids) => { let tys = [ Type::Builtin("Uint8Array"), @@ -1271,6 +1284,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { for (i, field) in v.fields.iter().enumerate() { let span = tcx.def_span(field.did); let ty = self.defined_field_ty(field, did, span); + typed.push((field.did, ty.clone())); fields.push((field_name(field.name.as_str(), i), ty)); } Type::Object(fields) @@ -1284,8 +1298,8 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { } } }; - self.program.items.push(unnamed_params(item)); - self.drop_glue(adt, &info, span); + self.program.items.push(item); + self.finish_definition(did, self.program.items.len() - 1, typed, span); info } @@ -1577,6 +1591,8 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { }, ty::Slice(elem) => self.slice_ty(*elem, span), ty::Param(param) => Type::Param(param.name.to_string()), + // A projection a generic type's fields name, which each instance decides. + ty::Alias(..) if let Some(param) = self.projection_param(ty) => param, ty::FnDef(def_id, args) => { let sig = self.sig(*def_id, args.skip_binder()); self.fn_ty(sig.inputs(), sig.output(), span) @@ -1721,7 +1737,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { if let Some(msg) = self.erasure_conflict(Ty::new_adt(tcx, adt, args)) { self.err(span, msg); } - self.option_ty(args.type_at(0), span) + self.option_ty(Ty::new_adt(tcx, adt, args), args.type_at(0), span) } library::Std::Result => Type::Rs( "Result", @@ -1827,7 +1843,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { if let Some(msg) = self.erasure_conflict(Ty::new_adt(tcx, adt, args)) { self.err(span, msg); } - self.poll_ty(args.type_at(0), span) + self.poll_ty(Ty::new_adt(tcx, adt, args), args.type_at(0), span) } library::Std::Pin => self.ty(args.type_at(0), span), library::Std::PollFn | library::Std::Pending => { @@ -1916,8 +1932,12 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { }; Type::Rs("Result", vec![self.ty(value, span), self.ty(residual.type_at(1), span)]) } - library::Flow::Option => self.option_ty(value, span), - library::Flow::Other => Type::Rs("Result", vec![self.ty(value, span), self.ty(residual, span)]), + library::Flow::Option => self.option_ty(Ty::new_adt(tcx, adt, args), value, span), + library::Flow::Other => { + let broken = self.ty(residual, span); + self.note_decided(Ty::new_adt(tcx, adt, args), residual, &broken, defined::Decides::Flow); + Type::Rs("Result", vec![self.ty(value, span), broken]) + } } } }; @@ -1943,16 +1963,102 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { return Type::Builtin("unknown"); } let info = self.adt(adt, span); + let instance = Ty::new_adt(tcx, adt, args); + // In a projection argument, named by an alias, so a type whose projections hold + // instances is typed once per instance, however many paths through them reach it, + // and one that holds itself again names its alias. + if self.defining_state.projecting > 0 + && !instance.has_param() + && args.iter().any(|arg| arg.as_region().is_none()) + && self.may_project(adt.did()) + { + return self.instance_alias(instance, &info, span); + } + self.instance_ty(instance, &info, span) + } + + /// The TypeScript type of `instance`, an instance of the crate's generic type `info`: + /// its type arguments, then what each of its projections is at them. + fn instance_ty(&mut self, instance: Ty<'tcx>, info: &Adt, span: Span) -> Type { + let ty::Adt(adt, args) = *instance.kind() else { + unreachable!("an instance of a generic type") + }; + self.note_held(instance); + // Of a definition still being typed, whose instances are checked once it is complete. + if let Some(later) = self.later_projections(adt.did(), args, span) { + let mut tys: Vec = args.types().map(|t| self.ty(t, span)).collect(); + tys.push(later); + return Type::Sym(info.sym, tys); + } + if let Some(ty) = self.instanced(instance) { + return ty; + } + // Its own arguments first: one that holds the instance again names a type that ends. + let mut tys: Vec = self + .own_args(adt.did(), args, span) + .into_iter() + .map(|(_, t)| t) + .collect(); + if !self.enter_instance(instance, span) { + return Type::Builtin("unknown"); + } if let Some(msg) = self.generic_erasure(adt, args, span) { self.err(span, msg); } - let args = args.types().map(|t| self.ty(t, span)).collect(); - Type::Sym(info.sym, args) + tys.extend(self.projection_args(adt.did(), args, span).into_iter().map(|(_, t)| t)); + // Past the recursion limit, refused already: what it typed is not kept. + if self.defining_state.too_deep { + self.leave_instance(instance, None); + return Type::Builtin("unknown"); + } + let ty = Type::Sym(info.sym, tys); + self.leave_instance(instance, Some(&ty)); + ty + } + + /// The TypeScript type arguments of an instance of the crate's generic `adt` with `args`, + /// by the name of the parameter each is: one per type parameter, then one per projection + /// typing its fields named, which is what the projection normalizes to at `args`. + fn instance_params(&mut self, adt: DefId, args: GenericArgsRef<'tcx>, span: Span) -> Vec<(String, Type)> { + let mut params = self.own_args(adt, args, span); + let instance = Ty::new_adt(self.tcx, self.tcx.adt_def(adt), args); + if !self.enter_instance(instance, span) { + return params; + } + let projections = self.projection_args(adt, args, span); + self.leave_instance(instance, None); + params.extend(projections); + params + } + + /// The TypeScript type of each type argument of an instance of `adt`, by its parameter. + fn own_args(&mut self, adt: DefId, args: GenericArgsRef<'tcx>, span: Span) -> Vec<(String, Type)> { + (self.tcx.generics_of(adt).own_params.iter()) + .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { .. })) + .map(|param| { + ( + param.name.to_string(), + self.ty(args.type_at(param.index as usize), span), + ) + }) + .collect() } - /// The TypeScript type of `field` in the definition of `adt`, over its own parameters, - /// noting a field that holds a form only an instance decides for - /// [`Self::held_field`]. + /// What each projection typing the crate's generic `adt`'s fields named normalizes to at + /// `args`, by its parameter. + fn projection_args(&mut self, adt: DefId, args: GenericArgsRef<'tcx>, span: Span) -> Vec<(String, Type)> { + let (projections, names): (Vec>, Vec) = self.defined(adt).projections.iter().cloned().unzip(); + let env = self.defining.map_or(self.typing_env(), |(_, env)| env); + let tcx = self.tcx; + self.defining_state.projecting += 1; + let args = (projections.into_iter().zip(names)) + .map(|(projection, name)| (name, self.ty(copy::instantiate(tcx, env, projection, args), span))) + .collect(); + self.defining_state.projecting -= 1; + args + } + + /// The TypeScript type of `field` in the definition of `adt`, over its own parameters. fn defined_field_ty(&mut self, field: &ty::FieldDef, adt: DefId, span: Span) -> Type { let tcx = self.tcx; // A projection it names, such as `::Hasher` of a known `S`, is the @@ -1960,17 +2066,24 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { let identity = ty::GenericArgs::identity_for_item(tcx, adt); let env = TypingEnv::post_analysis(tcx, adt); let ty = copy::field_ty(tcx, env, field.did, identity); - let outer = self.defining.replace(env); + let outer = self.defining.replace((adt, env)); + let outer_field = self.defining_state.field.replace(field.did); let ty = self.ty(ty, span); self.defining = outer; + self.defining_state.field = outer_field; + ty + } + + /// Note `field`'s type `ty` in its type's definition for [`Self::field_value`] and + /// [`Self::held_field`], once its definition is complete. + fn note_field(&mut self, field: DefId, ty: &Type) { if ty.any(&instanced) { self.instanced_fields - .insert(field.did, ty.takes(&instanced).then(|| ty.clone())); + .insert(field, ty.takes(&instanced).then(|| ty.clone())); } if ty.any(&|t| matches!(t, Type::Rs("OptionOf" | "PollOf", _))) { - self.decided_fields.insert(field.did, ty.clone()); + self.decided_fields.insert(field, ty.clone()); } - ty } /// `value`, for `field` of an instance of `adt` with `args`, cast to the field's type in @@ -1993,15 +2106,7 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { None => return value, }, }; - let params: Vec<(String, Type)> = (self.tcx.generics_of(adt).own_params.iter()) - .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { .. })) - .map(|param| { - ( - param.name.to_string(), - self.ty(args.type_at(param.index as usize), span), - ) - }) - .collect(); + let params = self.instance_params(adt, args, span); let at = defined.subst(&|name| params.iter().find(|(p, _)| p == name).map(|(_, t)| t.clone())); ts::Expr::As(Box::new(value), at) } @@ -2017,95 +2122,114 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { } /// Why an instance of the crate's generic `adt` with `args` can't hold its fields' values, - /// if it can't: an `Option` or a `Poll` over a type parameter whose `None` or `Pending` - /// this instance makes other than its definition types it, as an `rs.OptionOf` or - /// `rs.PollOf` decides by TypeScript's type of `T`, and otherwise by the definition's - /// own parameter, or which can't tell its values apart at all. + /// if it can't: a part its definition, or that of an instance it holds, types that this + /// instance represents otherwise (see [`defined::Decides`]), or that can't tell its values + /// apart at all. fn generic_erasure(&mut self, adt: AdtDef<'tcx>, args: GenericArgsRef<'tcx>, span: Span) -> Option { + let tcx = self.tcx; + let env = self.defining.map_or(self.typing_env(), |(_, env)| env); + // Each its definition typed, which leaves out what types nothing, such as a `PhantomData`. + let checks = self.defined(adt.did()).checks.clone(); + checks.into_iter().find_map(|check| { + let args = defined::instantiate_args(tcx, env, check.args, args); + self.decided_conflict(tcx.adt_def(check.adt), args, &check.decided, span) + }) + } + + /// Why the instance of the crate's generic `adt` with `args` represents `decided`, a part + /// its definition typed, otherwise than its definition does, if it does. + fn decided_conflict( + &mut self, + adt: AdtDef<'tcx>, + args: GenericArgsRef<'tcx>, + decided: &defined::Decided<'tcx>, + span: Span, + ) -> Option { let tcx = self.tcx; let ty = Ty::new_adt(tcx, adt, args); - for field in adt.all_fields() { - let generic = tcx.type_of(field.did).instantiate_identity().skip_norm_wip(); - for part in generic.walk().filter_map(|arg| arg.as_type()) { - let ty::Adt(wrapper, wrapper_args) = part.kind() else { - continue; - }; - let option = match library::Std::of(tcx, wrapper.did()) { - Some(library::Std::Option) => true, - Some(library::Std::Poll) => false, - _ => continue, - }; - let inner = wrapper_args.type_at(0); - let erased = self.erases_to(inner); - if !erased.param { - continue; - } - let held = ty::EarlyBinder::bind(tcx, part).instantiate(tcx, args).skip_norm_wip(); - if let Some(msg) = self.erasure_conflict(held) { - return Some(format!( - "`{ty}` is not supported: its field `{}` is `{held}`: {msg}", - field.name - )); - } - // Over a parameter of the instance's own, which its instances decide. - if held.has_param() { - continue; - } - let instance = ty::EarlyBinder::bind(tcx, inner).instantiate(tcx, args).skip_norm_wip(); - let at = self.erases_to(instance); - let defined = self.ty(inner, span); - let msg = match defined { - // What TypeScript's type of the parameter decides, which must be what the - // instance's erasure does. - Type::Param(_) if if option { !erased.undefined } else { !erased.pending } => { - let Some(param) = inner.walk().filter_map(|arg| arg.as_type()).find(|t| matches!(t.kind(), ty::Param(_))) else { - continue; - }; - let arg = ty::EarlyBinder::bind(tcx, param).instantiate(tcx, args).skip_norm_wip(); - let decided = self.ty(arg, span); - let (holds, alias) = match option { - true => (holds_undefined(&decided) == at.undefined, "OptionOf"), - false => (holds_pending(&decided) == at.pending, "PollOf"), - }; - (!holds).then(|| { - format!( - "`{ty}` is not supported: its field `{}` is `{part}`, typed `rs.{alias}<{inner}>`, which decides by TypeScript's type of `{arg}` otherwise than `{held}` erases", - field.name - ) - }) - } - _ if option && !erased.undefined => at.undefined.then(|| { - format!( - "`{ty}` is not supported: its field `{}` is `Option<{inner}>`, typed `{inner} | undefined`, whose `None` would be `rs.None` as `Option<{instance}>`", - field.name - ) - }), - _ if !option && !erased.pending => at.pending.then(|| { - format!( - "`{ty}` is not supported: its field `{}` is `Poll<{inner}>`, typed `rs.Poll<{inner}>`, whose `Pending` would be `rs.OuterPending` as `Poll<{instance}>`", - field.name - ) - }), - // A `MaybeUninit`, which can be `undefined` but for a byte. - _ if option => (!at.undefined).then(|| { - format!( - "`{ty}` is not supported: its field `{}` is `Option<{inner}>`, typed `{inner} | rs.None`, whose `None` would be `undefined` as `Option<{instance}>`", - field.name - ) - }), - _ => (!at.pending).then(|| { - format!( - "`{ty}` is not supported: its field `{}` is `Poll<{inner}>`, typed `{inner} | rs.OuterPending`, whose `Pending` would be `rs.Pending` as `Poll<{instance}>`", - field.name - ) - }), + let env = self.defining.map_or(self.typing_env(), |(_, env)| env); + let defined::Decided { + field, + part, + inner, + ref defined, + decides, + } = *decided; + let field = tcx.item_name(field); + let held = copy::instantiate(tcx, env, part, args); + let instance = copy::instantiate(tcx, env, inner, args); + if decides == defined::Decides::Future { + return self.erases_to(instance).pending.then(|| { + format!( + "`{ty}` is not supported: its field `{field}` holds a future of `{instance}`, which can be `rs.Pending`, as the future's own `Pending` is" + ) + }); + } + if let Some(msg) = self.erasure_conflict(held) { + return Some(format!( + "`{ty}` is not supported: its field `{field}` is `{held}`: {msg}" + )); + } + if decides == defined::Decides::Flow { + let (ty::Adt(_, at), ty::Adt(_, typed)) = (held.kind(), part.kind()) else { + return None; + }; + return (library::Flow::of(tcx, at) != library::Flow::of(tcx, typed)).then(|| { + format!( + "`{ty}` is not supported: its field `{field}` is `{part}`, typed as a result that breaks with `{inner}`, which `{held}` is not, as it breaks with what `?` makes" + ) + }); + } + // Over a parameter of the instance's own, which its instances decide. + if held.has_param() { + return None; + } + let option = decides == defined::Decides::Option; + let erased = self.erases_to(inner); + let at = self.erases_to(instance); + match defined { + // What TypeScript's type of the parameter decides, which must be what the + // instance's erasure does. + Type::Param(_) if if option { !erased.undefined } else { !erased.pending } => { + // The parameter, or the projection from one, that it types. + let param = (inner.walk().filter_map(|arg| arg.as_type())) + .find(|t| matches!(t.kind(), ty::Param(_) | ty::Alias(..)))?; + let arg = copy::instantiate(tcx, env, param, args); + self.defining_state.projecting += 1; + let decided = self.ty(arg, span); + self.defining_state.projecting -= 1; + let (holds, alias) = match option { + true => (holds_undefined(&decided) == at.undefined, "OptionOf"), + false => (holds_pending(&decided) == at.pending, "PollOf"), }; - if msg.is_some() { - return msg; - } + (!holds).then(|| { + format!( + "`{ty}` is not supported: its field `{field}` is `{part}`, typed `rs.{alias}<{inner}>`, which decides by TypeScript's type of `{arg}` otherwise than `{held}` erases" + ) + }) } + _ if option && !erased.undefined => at.undefined.then(|| { + format!( + "`{ty}` is not supported: its field `{field}` is `Option<{inner}>`, typed `{inner} | undefined`, whose `None` would be `rs.None` as `Option<{instance}>`" + ) + }), + _ if !option && !erased.pending => at.pending.then(|| { + format!( + "`{ty}` is not supported: its field `{field}` is `Poll<{inner}>`, typed `rs.Poll<{inner}>`, whose `Pending` would be `rs.OuterPending` as `Poll<{instance}>`" + ) + }), + // A `MaybeUninit`, which can be `undefined` but for a byte. + _ if option => (!at.undefined).then(|| { + format!( + "`{ty}` is not supported: its field `{field}` is `Option<{inner}>`, typed `{inner} | rs.None`, whose `None` would be `undefined` as `Option<{instance}>`" + ) + }), + _ => (!at.pending).then(|| { + format!( + "`{ty}` is not supported: its field `{field}` is `Poll<{inner}>`, typed `{inner} | rs.OuterPending`, whose `Pending` would be `rs.Pending` as `Poll<{instance}>`" + ) + }), } - None } /// The type of an iterator's items, which every iterator has. @@ -2122,8 +2246,10 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { /// The TypeScript type of an `Option`: `T | undefined`, or `T | rs.None` where /// `T` can already be `undefined`, and in a generic type's definition, of a type /// parameter, an `rs.OptionOf`, which is either as each instance's `T` decides. - fn option_ty(&mut self, inner: Ty<'tcx>, span: Span) -> Type { + /// `part` is the `Option`, or the `ControlFlow` that is one. + fn option_ty(&mut self, part: Ty<'tcx>, inner: Ty<'tcx>, span: Span) -> Type { let some = self.ty(inner, span); + self.note_decided(part, inner, &some, defined::Decides::Option); let erased = self.erases_to(inner); if matches!(some, Type::Param(_)) && !erased.undefined { return Type::Rs("OptionOf", vec![some]); @@ -2144,14 +2270,17 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { format!("a future of `{output}`, which can be `rs.Pending`, as the future's own `Pending` is"), ); } - Type::Rs("Future", vec![self.ty(output, span)]) + let ty = self.ty(output, span); + self.note_decided(output, output, &ty, defined::Decides::Future); + Type::Rs("Future", vec![ty]) } /// The TypeScript type of a `Poll`: `rs.Poll`, or `T | rs.OuterPending` where /// `T` can already be `rs.Pending`, and in a generic type's definition, of a type /// parameter, an `rs.PollOf`, which is either as each instance's `T` decides. - fn poll_ty(&mut self, inner: Ty<'tcx>, span: Span) -> Type { + fn poll_ty(&mut self, part: Ty<'tcx>, inner: Ty<'tcx>, span: Span) -> Type { let ready = self.ty(inner, span); + self.note_decided(part, inner, &ready, defined::Decides::Poll); if matches!(ready, Type::Param(_)) && !self.erases_to(inner).pending { return Type::Rs("PollOf", vec![ready]); } @@ -2201,6 +2330,10 @@ impl<'a, 'tcx> Translator<'a, 'tcx> { param: true, ..Erased::default() }, + ty::Alias(..) if ty.has_param() => Erased { + param: true, + ..Erased::default() + }, // An `rs.Place`, which is an object. ty::Ref(..) if self.place_pointee(ty).is_some() => Erased::default(), ty::Ref(_, inner, _) => self.erases_to(*inner), @@ -2501,18 +2634,17 @@ pub fn camel(name: &str) -> String { /// `item` with each type parameter its type never names marked unused, as TS wants of /// one only a `PhantomData` held. -fn unnamed_params(mut item: Item) -> Item { - let (params, types): (&mut Vec, Vec<&Type>) = match &mut item { +fn unnamed_params(item: &mut Item) { + let (params, types): (&mut Vec, Vec<&Type>) = match item { Item::Struct { params, fields, .. } => (params, fields.iter().map(|f| &f.ty).collect()), Item::Union { params, ty, .. } => (params, vec![&*ty]), - _ => return item, + _ => return, }; for param in params.iter_mut() { if !types.iter().any(|t| t.names(param)) { *param = format!("_{param}"); } } - item } /// A field's property name: `camelCase`, or `_0` for a tuple field. diff --git a/ts/src/lower/names.rs b/ts/src/lower/names.rs index a5c88d8cd..687a8c833 100644 --- a/ts/src/lower/names.rs +++ b/ts/src/lower/names.rs @@ -264,7 +264,7 @@ fn defined<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_args: &[GenericArg<'tcx>] } /// The type and const arguments of `args`, as a suffix spells them. -fn args<'tcx>(tcx: TyCtxt<'tcx>, args: &[GenericArg<'tcx>]) -> impl Iterator { +pub(super) fn args<'tcx>(tcx: TyCtxt<'tcx>, args: &[GenericArg<'tcx>]) -> impl Iterator { args.iter().filter_map(move |arg| match arg.kind() { ty::GenericArgKind::Type(t) => Some(ty(tcx, t)), ty::GenericArgKind::Const(c) => Some(konst(c)), diff --git a/ts/src/print.rs b/ts/src/print.rs index 62ac83ff9..9d794fb99 100644 --- a/ts/src/print.rs +++ b/ts/src/print.rs @@ -354,6 +354,7 @@ impl Refs { self.ty(program, ret); } Type::Object(fields) => fields.iter().for_each(|(_, t)| self.ty(program, t)), + Type::Later(_) => unreachable!("unfilled projection arguments"), } } @@ -1174,6 +1175,7 @@ impl Printer<'_> { .collect(); format!("{{ {} }}", parts.join("; ")) } + Type::Later(_) => unreachable!("unfilled projection arguments"), } } diff --git a/ts/src/ts.rs b/ts/src/ts.rs index 8fbe03678..37cb73843 100644 --- a/ts/src/ts.rs +++ b/ts/src/ts.rs @@ -690,6 +690,9 @@ pub enum Type { StrLit(String), /// An object type; a `Some` key is a class field. Object(Vec<(String, Type)>), + /// In a generic type's arguments, the projection arguments of an instance of a type + /// whose definition is still being typed, which [`Type::fill`] splices in once it is. + Later(usize), } impl Type { @@ -703,7 +706,7 @@ impl Type { pub fn takes(&self, f: &impl Fn(&Type) -> bool) -> bool { match self { Type::Func(params, ret) => params.iter().any(|t| t.any(f)) || ret.takes(f), - Type::Param(_) | Type::Builtin(_) | Type::StrLit(_) => false, + Type::Param(_) | Type::Builtin(_) | Type::StrLit(_) | Type::Later(_) => false, Type::Rs(_, tys) | Type::Sym(_, tys) if !f(self) => tys.iter().any(|t| t.any(f)), Type::Rs(_, tys) | Type::Sym(_, tys) | Type::Union(tys) | Type::Tuple(tys) => { tys.iter().any(|t| t.takes(f)) @@ -718,7 +721,7 @@ impl Type { let all = |tys: &[Type]| tys.iter().map(|t| t.subst(f)).collect(); match self { Type::Param(name) => f(name).unwrap_or_else(|| self.clone()), - Type::Builtin(_) | Type::StrLit(_) => self.clone(), + Type::Builtin(_) | Type::StrLit(_) | Type::Later(_) => self.clone(), Type::Rs(name, tys) => Type::Rs(name, all(tys)), Type::Sym(sym, tys) => Type::Sym(*sym, all(tys)), Type::Union(tys) => Type::Union(all(tys)), @@ -733,7 +736,7 @@ impl Type { pub fn any(&self, f: &impl Fn(&Type) -> bool) -> bool { f(self) || match self { - Type::Param(_) | Type::Builtin(_) | Type::StrLit(_) => false, + Type::Param(_) | Type::Builtin(_) | Type::StrLit(_) | Type::Later(_) => false, Type::Rs(_, tys) | Type::Sym(_, tys) | Type::Union(tys) | Type::Tuple(tys) => { tys.iter().any(|t| t.any(f)) } @@ -742,6 +745,53 @@ impl Type { Type::Object(fields) => fields.iter().any(|(_, t)| t.any(f)), } } + + /// It with each [`Type::Later`] replaced by the arguments `later` gives it, if it gives + /// any, or `None` if one reaches itself. + pub fn fill(&mut self, later: &impl Fn(usize) -> Option>) -> Option<()> { + self.fill_from(later, &mut Vec::new()) + } + + fn fill_from(&mut self, later: &impl Fn(usize) -> Option>, open: &mut Vec) -> Option<()> { + match self { + Type::Param(_) | Type::Builtin(_) | Type::StrLit(_) => Some(()), + Type::Later(_) => unreachable!("projection arguments outside a generic type's arguments"), + Type::Rs(_, tys) | Type::Union(tys) | Type::Tuple(tys) => { + tys.iter_mut().try_for_each(|t| t.fill_from(later, open)) + } + Type::Sym(_, tys) => { + let mut filled = Vec::with_capacity(tys.len()); + for mut t in std::mem::take(tys) { + let Type::Later(id) = t else { + t.fill_from(later, open)?; + filled.push(t); + continue; + }; + let Some(args) = later(id) else { + filled.push(t); + continue; + }; + if open.contains(&id) { + return None; + } + open.push(id); + for mut t in args { + t.fill_from(later, open)?; + filled.push(t); + } + open.pop(); + } + *tys = filled; + Some(()) + } + Type::Array(t) => t.fill_from(later, open), + Type::Func(tys, ret) => { + tys.iter_mut().try_for_each(|t| t.fill_from(later, open))?; + ret.fill_from(later, open) + } + Type::Object(fields) => fields.iter_mut().try_for_each(|(_, t)| t.fill_from(later, open)), + } + } } #[derive(Clone, Debug)]