Skip to content

Regression: 3.6 crashes if constructor parameters transformed  #33295

Closed
@evmar

Description

@evmar

TypeScript Version: 3.6.2, and typescript@3.7.0-dev.20190906

Search Terms:
isParameterPropertyDeclaration

Code

Briefly, if a transformer touches the parameters of a constructor via e.g. ts.updateParameter, then the new node loses its parent pointer, which produces the following backtrace once TS runs after the transformer. (The below is 3.6.2 to make the line numbers easier for you to match up, but it also repros on the head version.)

TypeError: Cannot read property 'kind' of undefined
    at isParameterPropertyDeclaration (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:13411:88)
    at Object.filter (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:469:31)
    at transformClassMembers (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70629:20)
    at createClassDeclarationHeadWithDecorators (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70591:27)
    at visitClassDeclaration (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70399:19)
    at visitTypeScript (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70247:28)
    at visitorWorker (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70041:24)
    at sourceElementVisitorWorker (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70066:28)
    at saveStateAndInvoke (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:69979:27)
    at sourceElementVisitor (/home/evanm/projects/ts/36/node_modules/typescript/lib/typescript.js:70051:20)

Here's an example transformer that provokes this crash. Note that it doesn't actually change anything in the AST, it just runs ts.updateParameter with a copy of the input array (using the ... spread) to force ts.updateParameter to not early exit.

function transformer(context: ts.TransformationContext): ts.Transformer<ts.SourceFile> {
  return (sf: ts.SourceFile) => {
    return ts.visitEachChild(sf, visit, context);
  };
  function visit(node: ts.Node): ts.VisitResult<ts.Node> {
    console.log(ts.SyntaxKind[node.kind]);
    switch (node.kind) {
      case ts.SyntaxKind.Constructor:
        const ctor = node as ts.ConstructorDeclaration;
        const params = ctor.parameters.map(param => ts.updateParameter(
          param,
          [...param.decorators!], param.modifiers,
          param.dotDotDotToken, param.name, param.questionToken,
          param.type, param.initializer));
        return ts.updateConstructor(ctor, ctor.decorators, ctor.modifiers,
                                    params, ctor.body);
      default:
        return ts.visitEachChild(node, visit, context);
    }
  }
}

Expected behavior:
This code succeeds under TS3.5.

Actual behavior:
This crashes in 3.6.

Playground Link:

Related Issues:

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugA bug in TypeScriptCrashFor flagging bugs which are compiler or service crashes or unclean exits, rather than bad outputDomain: TransformsRelates to the public transform API

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions