Skip to content

Fix decorator design:types emit for type variables.#25190

Merged
mhegazy merged 4 commits into
microsoft:masterfrom
mprobst:fix-generic-type-emit
Jun 26, 2018
Merged

Fix decorator design:types emit for type variables.#25190
mhegazy merged 4 commits into
microsoft:masterfrom
mprobst:fix-generic-type-emit

Conversation

@mprobst
Copy link
Copy Markdown
Contributor

@mprobst mprobst commented Jun 25, 2018

Fix decorator design:types emit for type variables.

Previously, TypeScript would resolve the reified types for the
design:types decorator emit in the regular currentScope. That scope
does not include class declaration bodies.

However when reifying types, class declarations do introduce a new scope
for any TypeVariables declared on them. Because TS resolved the
EntityName for such types against the parent scope (e.g. the source
file), not the class scope, TypeScript would either fail to resolve the type (giving TypeReferenceSerializationKind.Unknown), or
incorrectly resolve to a different, accidentally matching symbol in the outer scope (giving TypeWithConstructSignatureAndValue).

This would result in an emit referencing an undeclared symbol, or
mis-referencing the wrong symbol.

__metadata("design:type", typeof (_a = typeof TypeVariable !== "undefined" && TypeVariable) === "function" && _a || Object)
__metadata("design:type", TypeVariable)

This change special cases currentScope for
serializeTypeReferenceNode to use a class scope, if present. This
changes the emit for a TypeVariable back to Object:

__metadata("design:type", Object)

@mprobst
Copy link
Copy Markdown
Contributor Author

mprobst commented Jun 25, 2018

Let me know if this is remotely reasonable, or feel free to just take the tests and fix based on them.

/CC @weswigham touched the code last, I think.

@mprobst mprobst force-pushed the fix-generic-type-emit branch 2 times, most recently from 7322ffa to f817a9d Compare June 25, 2018 15:23
Previously, TypeScript would resolve the reified types for the
`design:types` decorator emit in the regular `currentScope`. That scope
does not include class declaration bodies.

However when reifying types, class declarations do introduce a new scope
for any `TypeVariable`s declared on them. Because TS resolved the
EntityName for such types against the parent scope (e.g. the source
file), not the class scope, TypeScript would either fail to resolve the type (giving `TypeReferenceSerializationKind.Unknown`), or
incorrectly resolve to a different, accidentally matching symbol in the outer scope (giving `TypeWithConstructSignatureAndValue`).

This would result in an emit referencing an undeclared symbol, or
mis-referencing the wrong symbol.

    __metadata("design:type", typeof (_a = typeof TypeVariable !== "undefined" && TypeVariable) === "function" && _a || Object)
    __metadata("design:type", TypeVariable)

This change special cases `currentScope` for
`serializeTypeReferenceNode` to use a class scope, if present. This
changes the emit for a `TypeVariable` back to `Object`:

    __metadata("design:type", Object)
@mprobst mprobst force-pushed the fix-generic-type-emit branch from f817a9d to 55c3ec3 Compare June 25, 2018 15:24
Comment thread src/compiler/transformers/ts.ts Outdated
// node might be a reference to type variable, which can be scoped to a class declaration, in addition to the regular
// TypeScript scopes. Walk up the AST to find the next class and use that as the lookup scope.
let scope: Node = node;
while (scope.parent && scope !== currentScope) {
Copy link
Copy Markdown
Member

@weswigham weswigham Jun 25, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't be using .parent in a transform, as a before transform can unset parent pointers (usually by replacing nodes). The correct scope should be captured, like currentScope, as the transform descends through the tree.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given how currentScope is used, I think it is acceptable simply to add the class body to the list of things captured by the transform as a possible currentScope, I believe, since it is just used for resolving names (like for this serialization) and checking if we're at the top level of a file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That was my first idea, too. That does however break variable merging in emit, i.e. it adds in a duplicated var declaration:

class C {
    constructor() {
        this.foo = 10;
    }
}
C.bar = 20;
var C;  // <-- ADDED
(function (C) {
    C.x = 10;
})(C || (C = {}));

I tried debugging, and got lost somewhere in merge declaration markers. plz send help ;-)

@mhegazy
Copy link
Copy Markdown
Contributor

mhegazy commented Jun 26, 2018

@mprobst a few failing baselines that need updating.

@mprobst
Copy link
Copy Markdown
Contributor Author

mprobst commented Jun 26, 2018

@mhegazy I think my change is incorrect, and the baselines should not be updated. Problem is I don't know how to fix correctly, I don't understand the merge declaration markers.

@weswigham
Copy link
Copy Markdown
Member

@mprobst I pushed a change to solve those problems, hope you don't mind!

@mprobst
Copy link
Copy Markdown
Contributor Author

mprobst commented Jun 26, 2018

Thanks @weswigham. As I said, feel free to take the tests and do whatever works :-)

Copy link
Copy Markdown
Member

@weswigham weswigham left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I am biased, so @mhegazy you should give it a brief once-over.

@mhegazy mhegazy merged commit b59824a into microsoft:master Jun 26, 2018
@mhegazy
Copy link
Copy Markdown
Contributor

mhegazy commented Jun 26, 2018

thanks!

@mprobst mprobst deleted the fix-generic-type-emit branch July 4, 2018 07:51
@microsoft microsoft locked as resolved and limited conversation to collaborators Oct 21, 2025
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants