mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-01 07:33:12 +08:00
Fail type checking when the generated IR field readers miss a field
fields.generated.ts reads IR nodes' fields by name, so a field ir.ts gains after the last `pnpm generate:ir-fields` is skipped by the walkers until someone regenerates the file; `--check` in CI reports it, but only on the run that looks. The generator now ends the file with type-level checks, one per node kind and per nested record the walkers enumerate: a field outside the list the file was generated from fails type checking with the field's name, and so does a field read as a scalar (no string, no object) that can now hold a string or an object. Fields the file reads already fail type checking when they are removed or change type. The checks are types only and emit no code.
This commit is contained in:
@@ -2069,3 +2069,252 @@ export function walkTypeFields(node: IrType, walker: IrFieldWalker, skipType: bo
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A field ir.ts declares that this file does not read. */
|
||||
type FieldsNotRead<T, Read extends PropertyKey> = Exclude<keyof T, Read>;
|
||||
/** The string or object values a field read as a scalar can hold. */
|
||||
type ValuesNotRead<T> = Extract<NonNullable<T>, string | object>;
|
||||
/** Fails type checking unless `T` is never: run `pnpm generate:ir-fields`. */
|
||||
type Unread<T extends never> = T;
|
||||
|
||||
/** Every walked object type's fields as ir.ts declared them when this file
|
||||
* was generated. */
|
||||
export type IrFieldsCurrent = [
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "arrIntrinsic" }>, "kind" | "method" | "receiver" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "arrayGet" }>, "kind" | "arr" | "index" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "arrayHas" }>, "kind" | "arr" | "index" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "arrayLit" }>, "kind" | "elems" | "spreads" | "capacity" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "arrayLit" }>["capacity"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "arrayNewLen" }>, "kind" | "length" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "arrayState" }>, "kind" | "arr" | "index" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "assignExpr" }>, "kind" | "localId" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "awaitExpr" }>, "kind" | "value" | "type" | "adopt" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "awaitExpr" }>["adopt"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "awaitUnionExpr" }>, "kind" | "value" | "promiseTag" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "awaitUnionExpr" }>["promiseTag"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "bin" }>, "kind" | "op" | "left" | "right" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "boolLit" }>, "kind" | "value" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "boolLit" }>["value"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "bytesIntrinsic" }>, "kind" | "method" | "receiver" | "args" | "type" | "loc" | "invalidNaN">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "bytesIntrinsic" }>["invalidNaN"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "bytesNew" }>, "kind" | "source" | "from" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "bytesNew" }>["from"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "call" }>, "kind" | "callee" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "callValue" }>, "kind" | "callee" | "receiver" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "caughtCheck" }>, "kind" | "value" | "className" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "caughtNarrow" }>, "kind" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "caughtTest" }>, "kind" | "value" | "test" | "className" | "negated" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "caughtTest" }>["negated"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "caughtToDyn" }>, "kind" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "chainRecv" }>, "kind" | "id" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "classRef" }>, "kind" | "className" | "captures" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "closure" }>, "kind" | "fnName" | "captures" | "adapts" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "closure" }>["adapts"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "downcast" }>, "kind" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynArrLit" }>, "kind" | "elems" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<NonNullable<Extract<NonNullable<Extract<IrExpr, { kind: "dynCall" }>["spreads"]>, readonly unknown[]>[number]>, object>, "arg" | "what">>,
|
||||
Unread<ValuesNotRead<Extract<NonNullable<Extract<NonNullable<Extract<IrExpr, { kind: "dynCall" }>["spreads"]>, readonly unknown[]>[number]>, object>["arg"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynCall" }>, "kind" | "callee" | "receiver" | "calleeName" | "calleeNameValue" | "args" | "spreads" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynCheck" }>, "kind" | "value" | "preserveRefs" | "adopt" | "exact" | "inferredSite" | "origin" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynCheck" }>["preserveRefs"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynCheck" }>["adopt"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynCheck" }>["exact"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynCheck" }>["origin"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynDestrCheck" }>, "kind" | "value" | "spelling" | "firstProp" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynFrom" }>, "kind" | "value" | "fnName" | "fnLength" | "liveRef" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynFrom" }>["fnLength"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynFrom" }>["liveRef"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynHasKey" }>, "kind" | "key" | "negated" | "value" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynHasKey" }>["negated"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynInvoke" }>, "kind" | "recv" | "method" | "calleeName" | "calleeNameValue" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynIterN" }>, "kind" | "value" | "count" | "notIterableMessage" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynIterN" }>["count"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynKeyGet" }>, "kind" | "key" | "optional" | "value" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynKeyGet" }>["optional"]>>,
|
||||
Unread<FieldsNotRead<Extract<NonNullable<Extract<NonNullable<Extract<IrExpr, { kind: "dynObjLit" }>["fields"]>, readonly unknown[]>[number]>, object>, "key" | "value">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynObjLit" }>, "kind" | "fields" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynScalarEq" }>, "kind" | "left" | "right" | "negated" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynScalarEq" }>["negated"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "dynTest" }>, "kind" | "test" | "bytesElem" | "negated" | "value" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "dynTest" }>["negated"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "ffiCall" }>, "kind" | "import" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "fieldAbsent" }>, "kind" | "unionId" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "fieldGet" }>, "kind" | "obj" | "className" | "field" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "fieldIncDec" }>, "kind" | "op" | "prefix" | "obj" | "className" | "field" | "fieldDyn" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "fieldIncDec" }>["prefix"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "fieldIncDec" }>["fieldDyn"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "genResume" }>, "kind" | "mode" | "gen" | "arg" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "incDec" }>, "kind" | "op" | "prefix" | "localId" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "incDec" }>["prefix"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "instanceOf" }>, "kind" | "value" | "className" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "instanceOfValue" }>, "kind" | "value" | "classValue" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "intrinsic" }>, "kind" | "name" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "jsonStringify" }>, "kind" | "value" | "indent" | "circular" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "jsonStringify" }>["circular"]>>,
|
||||
Unread<FieldsNotRead<Extract<NonNullable<Extract<IrExpr, { kind: "libCall" }>["assertOptions"]>, object>, "diff" | "skipPrototype">>,
|
||||
Unread<ValuesNotRead<Extract<NonNullable<Extract<IrExpr, { kind: "libCall" }>["assertOptions"]>, object>["skipPrototype"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "libCall" }>, "kind" | "fn" | "args" | "type" | "loc" | "prototypeIdentityOnly" | "realTimer" | "assertOptions">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "libCall" }>["prototypeIdentityOnly"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "libCall" }>["realTimer"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "logical" }>, "kind" | "op" | "left" | "right" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "mapIntrinsic" }>, "kind" | "method" | "receiver" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<NonNullable<Extract<NonNullable<Extract<IrExpr, { kind: "mapNew" }>["seed"]>, readonly unknown[]>[number]>, object>, "key" | "value">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "mapNew" }>, "kind" | "seed" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "moduleNsRef" }>, "kind" | "moduleId" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "new" }>, "kind" | "className" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "newPromise" }>, "kind" | "executor" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "newValue" }>, "kind" | "callee" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "nullish" }>, "kind" | "left" | "right" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "numLit" }>, "kind" | "value" | "spelling" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "numLit" }>["value"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "optChain" }>, "kind" | "id" | "receiver" | "body" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "orDefault" }>, "kind" | "left" | "right" | "retag" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "promiseVoidWiden" }>, "kind" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "promiseWithResolvers" }>, "kind" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<NonNullable<Extract<NonNullable<Extract<IrExpr, { kind: "recordClone" }>["overrides"]>, readonly unknown[]>[number]>, object>, "name" | "value">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "recordClone" }>, "kind" | "source" | "overrides" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "recordGet" }>, "kind" | "obj" | "shapeId" | "field" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "recordHas" }>, "kind" | "obj" | "shapeId" | "field" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "recordKeyGet" }>, "kind" | "obj" | "shapeId" | "key" | "overflowOnly" | "missNaN" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "recordKeyGet" }>["overflowOnly"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "recordKeyGet" }>["missNaN"]>>,
|
||||
Unread<FieldsNotRead<Extract<NonNullable<Extract<NonNullable<Extract<IrExpr, { kind: "recordLit" }>["fields"]>, readonly unknown[]>[number]>, object>, "name" | "value" | "overflow">>,
|
||||
Unread<ValuesNotRead<Extract<NonNullable<Extract<NonNullable<Extract<IrExpr, { kind: "recordLit" }>["fields"]>, readonly unknown[]>[number]>, object>["overflow"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "recordLit" }>, "kind" | "fields" | "nullProto" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "recordLit" }>["nullProto"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "recordNullProto" }>, "kind" | "obj" | "shapeId" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "recordOvfHas" }>, "kind" | "obj" | "shapeId" | "key" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "recordOvfKeys" }>, "kind" | "obj" | "shapeId" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "regexIntrinsic" }>, "kind" | "method" | "receiver" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "regexLit" }>, "kind" | "pattern" | "flags" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "selfRef" }>, "kind" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "seqExpr" }>, "kind" | "stmts" | "result" | "generatorDelegate" | "diverges" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "seqExpr" }>["generatorDelegate"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "seqExpr" }>["diverges"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "setIntrinsic" }>, "kind" | "method" | "receiver" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "setNew" }>, "kind" | "seed" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "strCmp" }>, "kind" | "op" | "left" | "right" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "strConcat" }>, "kind" | "left" | "right" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "strEq" }>, "kind" | "negated" | "left" | "right" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "strEq" }>["negated"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "strIntrinsic" }>, "kind" | "method" | "receiver" | "args" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "strLit" }>, "kind" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "templateStrings" }>, "kind" | "key" | "cooked" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "ternary" }>, "kind" | "cond" | "then" | "else_" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "toBool" }>, "kind" | "operand" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "toString" }>, "kind" | "operand" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unary" }>, "kind" | "op" | "operand" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unionDisc" }>, "kind" | "unionId" | "field" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unionEq" }>, "kind" | "unionId" | "negated" | "sameValue" | "left" | "right" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "unionEq" }>["negated"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "unionEq" }>["sameValue"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unionFuncEq" }>, "kind" | "unionId" | "tag" | "union" | "func" | "negated" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "unionFuncEq" }>["tag"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "unionFuncEq" }>["negated"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unionIsTag" }>, "kind" | "unionId" | "tag" | "negated" | "value" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "unionIsTag" }>["tag"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "unionIsTag" }>["negated"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unionKeyGet" }>, "kind" | "unionId" | "key" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unionNarrow" }>, "kind" | "unionId" | "tag" | "value" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "unionNarrow" }>["tag"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unionRetype" }>, "kind" | "fromId" | "unionId" | "tags" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unionWrap" }>, "kind" | "unionId" | "tag" | "value" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "unionWrap" }>["tag"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "unitLit" }>, "kind" | "unit" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "upcast" }>, "kind" | "value" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "varRef" }>, "kind" | "localId" | "type" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "virtualCall" }>, "kind" | "className" | "method" | "args" | "type" | "loc" | "targets">>,
|
||||
Unread<FieldsNotRead<Extract<NonNullable<Extract<IrExpr, { kind: "yieldExpr" }>["captureCompletion"]>, object>, "returnType">>,
|
||||
Unread<FieldsNotRead<Extract<IrExpr, { kind: "yieldExpr" }>, "kind" | "value" | "awaited" | "delegated" | "captureCompletion" | "type" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "yieldExpr" }>["awaited"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrExpr, { kind: "yieldExpr" }>["delegated"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "arrayDelete" }>, "kind" | "arr" | "index" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "arraySet" }>, "kind" | "arr" | "index" | "value" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "arraySetLength" }>, "kind" | "arr" | "length" | "loc" | "pop" | "reserve">>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "arraySetLength" }>["pop"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "arraySetLength" }>["reserve"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "arraySetUndefined" }>, "kind" | "arr" | "index" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "assign" }>, "kind" | "localId" | "value" | "initializes" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "assign" }>["initializes"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "block" }>, "kind" | "body" | "labels" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "break" }>, "kind" | "label" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "bytesSet" }>, "kind" | "arr" | "index" | "value" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "continue" }>, "kind" | "label" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "doWhile" }>, "kind" | "body" | "cond" | "labels" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "exprStmt" }>, "kind" | "expr" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "fieldSet" }>, "kind" | "obj" | "className" | "field" | "value" | "sloppy" | "define" | "attributesChecked" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "fieldSet" }>["sloppy"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "fieldSet" }>["define"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "fieldSet" }>["attributesChecked"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "for" }>, "kind" | "init" | "cond" | "update" | "body" | "labels" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "forOf" }>, "kind" | "localId" | "iterable" | "body" | "labels" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "if" }>, "kind" | "cond" | "then" | "else_" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "recordKeyDelete" }>, "kind" | "obj" | "shapeId" | "key" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "recordKeySet" }>, "kind" | "obj" | "shapeId" | "key" | "value" | "overflowOnly" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "recordKeySet" }>["overflowOnly"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "recordSet" }>, "kind" | "obj" | "shapeId" | "field" | "value" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "rethrow" }>, "kind" | "localId" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "return" }>, "kind" | "value" | "awaited" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "return" }>["awaited"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "runtimeFence" }>, "kind" | "code" | "message" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<NonNullable<Extract<NonNullable<Extract<IrStmt, { kind: "switch" }>["cases"]>, readonly unknown[]>[number]>, object>, "test" | "body">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "switch" }>, "kind" | "disc" | "cases" | "labels" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "throw" }>, "kind" | "value" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "tryCatch" }>, "kind" | "tryBody" | "catchBody" | "catchLocalId" | "finallyBody" | "suppressFinallyErrors" | "dropFinallyErrors" | "loc">>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "tryCatch" }>["suppressFinallyErrors"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrStmt, { kind: "tryCatch" }>["dropFinallyErrors"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "varDecl" }>, "kind" | "localId" | "init" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrStmt, { kind: "while" }>, "kind" | "cond" | "body" | "labels" | "loc">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "array" }>, "kind" | "elem" | "optionalElements">>,
|
||||
Unread<ValuesNotRead<Extract<IrType, { kind: "array" }>["optionalElements"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "bigint" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "bool" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "bytes" }>, "kind" | "elem">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "caught" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "child" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "childStream" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "childWriter" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "classval" }>, "kind" | "className">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "cryptoHash" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "cryptoHmac" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "date" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "dgramSocket" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "dir" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "dyn" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "f64" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "fileHandle" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "fsWatcher" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "func" }>, "kind" | "params" | "ret" | "rest" | "restAbi" | "argumentsAll">>,
|
||||
Unread<ValuesNotRead<Extract<IrType, { kind: "func" }>["rest"]>>,
|
||||
Unread<ValuesNotRead<Extract<IrType, { kind: "func" }>["argumentsAll"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "generator" }>, "kind" | "async" | "yieldT" | "retT" | "nextT">>,
|
||||
Unread<ValuesNotRead<Extract<IrType, { kind: "generator" }>["async"]>>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "http2Session" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "http2Stream" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "httpClientReq" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "httpReq" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "httpRes" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "jsval" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "map" }>, "kind" | "key" | "value">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "moduleNs" }>, "kind" | "moduleId">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "netServer" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "netSocket" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "nullT" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "object" }>, "kind" | "className">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "procStream" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "promise" }>, "kind" | "inner">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "record" }>, "kind" | "shapeId">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "regex" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "searchParams" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "secureCtx" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "set" }>, "kind" | "elem">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "spawnRes" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "stats" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "string" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "symbol" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "testCtx" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "undefinedT" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "union" }>, "kind" | "unionId">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "url" }>, "kind">>,
|
||||
Unread<FieldsNotRead<Extract<IrType, { kind: "void" }>, "kind">>,
|
||||
];
|
||||
|
||||
@@ -105,9 +105,23 @@ function irKind(type) {
|
||||
}
|
||||
|
||||
let temp = 0;
|
||||
/** Lines that walk `expr` of `type`: strings to `walker.string`, IR nodes to
|
||||
* their walkers, arrays by element and other objects by field. */
|
||||
function walkLines(expr, type, indent, depth) {
|
||||
/** The fields each walked object type declares, for the type-level check at
|
||||
* the end of the file: `typeExpr` names the object type, `fields` every
|
||||
* field it had when the file was generated and `scalars` the fields that held
|
||||
* no string and no object then. */
|
||||
const checks = [];
|
||||
/** Records `property list` of `object` (named `typeExpr`) for the check. */
|
||||
function noteFields(typeExpr, properties, scalarNames) {
|
||||
checks.push({
|
||||
typeExpr,
|
||||
fields: properties.map((property) => property.name),
|
||||
scalars: scalarNames,
|
||||
});
|
||||
}
|
||||
/** Lines that walk `expr` of `type` (named `typeExpr` in the generated file):
|
||||
* strings to `walker.string`, IR nodes to their walkers, arrays by element and
|
||||
* other objects by field. */
|
||||
function walkLines(expr, type, typeExpr, indent, depth) {
|
||||
if (depth > 12) throw new Error(`field type nests too deep at ${expr}`);
|
||||
const parts = type.isUnion() ? type.types : [type];
|
||||
const present = parts.filter((part) => (part.flags & nullish) === 0);
|
||||
@@ -127,19 +141,28 @@ function walkLines(expr, type, indent, depth) {
|
||||
if (objects.length !== 1) throw new Error(`several array types at ${expr}`);
|
||||
const item = `item${temp++}`;
|
||||
body.push(`for (const ${item} of ${expr}) {`);
|
||||
body.push(...walkLines(item, checker.getTypeArguments(objects[0])[0], " ", depth + 1));
|
||||
const itemType = `Extract<NonNullable<${typeExpr}>, readonly unknown[]>[number]`;
|
||||
body.push(
|
||||
...walkLines(item, checker.getTypeArguments(objects[0])[0], itemType, " ", depth + 1),
|
||||
);
|
||||
body.push("}");
|
||||
} else if (kinds.has(null) && objects.length === 1) {
|
||||
for (const property of checker.getPropertiesOfType(objects[0])) {
|
||||
const recordType = `Extract<NonNullable<${typeExpr}>, object>`;
|
||||
const properties = checker.getPropertiesOfType(objects[0]);
|
||||
const scalarNames = [];
|
||||
for (const property of properties) {
|
||||
if (property.name === "loc") continue;
|
||||
const fieldType = checker.getTypeOfSymbol(property);
|
||||
const field = `${expr}.${property.name}`;
|
||||
const lines = walkLines(field, fieldType, "", depth + 1);
|
||||
const fieldTypeExpr = `${recordType}[${JSON.stringify(property.name)}]`;
|
||||
const lines = walkLines(field, fieldType, fieldTypeExpr, "", depth + 1);
|
||||
if (lines.length === 0) scalarNames.push(property.name);
|
||||
if (lines.length === 0) continue;
|
||||
if (property.name === "type")
|
||||
body.push("if (!skipType) {", ...lines.map((l) => ` ${l}`), "}");
|
||||
else body.push(...lines);
|
||||
}
|
||||
noteFields(recordType, properties, scalarNames);
|
||||
} else throw new Error(`mixed object types at ${expr}: ${checker.typeToString(type)}`);
|
||||
}
|
||||
let lines = body;
|
||||
@@ -193,20 +216,50 @@ for (const name of ["IrExpr", "IrStmt", "IrType"]) {
|
||||
}
|
||||
for (const [kind, member] of [...byKind].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))) {
|
||||
lines.push(` case ${JSON.stringify(kind)}: {`);
|
||||
const memberType = `Extract<${name}, { kind: ${JSON.stringify(kind)} }>`;
|
||||
const scalarNames = [];
|
||||
for (const property of member.getProperties()) {
|
||||
if (property.name === "loc") continue;
|
||||
const fieldType = checker.getTypeOfSymbol(property);
|
||||
const field = `node.${property.name}`;
|
||||
const walk = walkLines(field, fieldType, "", 0);
|
||||
const fieldTypeExpr = `${memberType}[${JSON.stringify(property.name)}]`;
|
||||
const walk = walkLines(field, fieldType, fieldTypeExpr, "", 0);
|
||||
if (walk.length === 0) scalarNames.push(property.name);
|
||||
if (walk.length === 0) continue;
|
||||
if (property.name === "type")
|
||||
lines.push(" if (!skipType) {", ...walk.map((l) => ` ${l}`), " }");
|
||||
else lines.push(...walk.map((l) => ` ${l}`));
|
||||
}
|
||||
lines.push(" return;", " }");
|
||||
noteFields(memberType, member.getProperties(), scalarNames);
|
||||
}
|
||||
lines.push(" }", "}", "");
|
||||
}
|
||||
|
||||
// Type checking fails below when ir.ts gives a walked object a field this
|
||||
// file does not know, or lets a field that held no string and no object hold
|
||||
// one before this file is regenerated.
|
||||
const quoted = (names) => names.map((name) => JSON.stringify(name)).join(" | ");
|
||||
lines.push(
|
||||
"/** A field ir.ts declares that this file does not read. */",
|
||||
"type FieldsNotRead<T, Read extends PropertyKey> = Exclude<keyof T, Read>;",
|
||||
"/** The string or object values a field read as a scalar can hold. */",
|
||||
"type ValuesNotRead<T> = Extract<NonNullable<T>, string | object>;",
|
||||
"/** Fails type checking unless `T` is never: run `pnpm generate:ir-fields`. */",
|
||||
"type Unread<T extends never> = T;",
|
||||
"",
|
||||
"/** Every walked object type's fields as ir.ts declared them when this file",
|
||||
" * was generated. */",
|
||||
"export type IrFieldsCurrent = [",
|
||||
);
|
||||
for (const { typeExpr, fields, scalars } of checks) {
|
||||
lines.push(
|
||||
` Unread<FieldsNotRead<${typeExpr}, ${fields.length > 0 ? quoted(fields) : "never"}>>,`,
|
||||
);
|
||||
for (const scalarName of scalars)
|
||||
lines.push(` Unread<ValuesNotRead<${typeExpr}[${JSON.stringify(scalarName)}]>>,`);
|
||||
}
|
||||
lines.push("];", "");
|
||||
const text = lines.join("\n");
|
||||
|
||||
if (process.argv.includes("--check")) {
|
||||
|
||||
Reference in New Issue
Block a user