mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-29 07:04:09 +08:00
Keep missing runtime-key entries undefined in nested module-scope patterns
- The indexed-read prepass now visits nested object patterns with the nested element's own type. A module-scope binding from a missing runtime-key entry of a nested index-signature record (`const { limits: { [key]: limit } } = config`) holds undefined instead of throwing a TypeError, with or without a default for the nested source.
- Corpus 6492 adds both nested forms.
This commit is contained in:
@@ -5377,14 +5377,25 @@ export class Lowerer {
|
||||
/** `const { a, b } = table` over an index-signature record: a name that
|
||||
* is not a declared field reads the index signature and can be
|
||||
* missing. */
|
||||
const scanRecordPattern = (name: ts.ObjectBindingPattern, init: ts.Expression): boolean => {
|
||||
const sourceType = this.mapTypeOf(this.typeOf(init));
|
||||
const scanRecordPattern = (
|
||||
name: ts.ObjectBindingPattern,
|
||||
init: ts.Expression,
|
||||
sourceType: IrType | null = this.mapTypeOf(this.typeOf(init)),
|
||||
): boolean => {
|
||||
if (sourceType?.kind !== "record") return false;
|
||||
const shape = this.shapes.get(sourceType.shapeId);
|
||||
const indexValue = shape?.indexValue;
|
||||
if (!shape || shape.tuple || !indexValue || indexValue.kind === "dyn") return false;
|
||||
if (!shape || shape.tuple) return false;
|
||||
const indexValue = shape.indexValue;
|
||||
let changed = false;
|
||||
for (const el of name.elements.nodes) {
|
||||
// A nested pattern reads its element the same way
|
||||
// (`const { limits: { [key]: limit } } = config`).
|
||||
if (!el.dotDotDotToken && el.name !== undefined && ts.isObjectBindingPattern(el.name)) {
|
||||
if (scanRecordPattern(el.name, init, this.mapTypeOf(this.typeOf(el.name))))
|
||||
changed = true;
|
||||
continue;
|
||||
}
|
||||
if (!indexValue || indexValue.kind === "dyn") continue;
|
||||
if (el.dotDotDotToken || el.initializer || !ts.isIdentifier(el.name)) continue;
|
||||
const key = el.propertyName ?? el.name;
|
||||
// A computed key that folds to one name reads like that name; a
|
||||
|
||||
@@ -51,3 +51,14 @@ for (const resource of ["cpu", "memory", "disk"]) {
|
||||
const missingKey = process.argv.length > 99 ? "a" : "missing";
|
||||
const { [missingKey]: missingWeight } = weights;
|
||||
console.log(missingWeight, missingWeight === undefined);
|
||||
|
||||
// The same in a nested module-scope pattern, with and without a default
|
||||
// for the nested source.
|
||||
const nestedConfig = { limits: { cpu: 2 } as Record<string, number> };
|
||||
const {
|
||||
limits: { [missingKey]: nestedLimit },
|
||||
} = nestedConfig;
|
||||
const {
|
||||
limits: { [missingKey]: defaultedLimit } = {},
|
||||
} = nestedConfig;
|
||||
console.log(nestedLimit, defaultedLimit === undefined);
|
||||
|
||||
Reference in New Issue
Block a user