Skip to content

Support some late-bound special property assignments #33220

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

weswigham
Copy link
Member

@weswigham weswigham commented Sep 3, 2019

Fixes #33129

In some of the projects I was looking over for declarations for js, our inability to recognize symbolically named members in JS was one of the big holes I still saw that blocked well-written JS from making good declarations.

This means you can now do, in TS:

export function foo() {}
foo.bar = 12;
const _private = Symbol();
foo[_private] = "ok";

const x: string = foo[_private];

and in JS:

const _sym = Symbol("_sym");
class MyClass {
    constructor() {
        this[_sym] = "ok";
    }

    method() {
        this[_sym] = "yep";
        const x = this[_sym];
    }
}

and the unique symbol typed implied members are well-typed.

Currently in TS, the declaration emit just silently strips away the late-bound function members. This is certainly worth revisiting and improving, I think, but would necessitate rewriting the function declaration into a const with a type annotation, rather than a function/namespace merge (since namespace members cannot have late bound names, syntactically...).

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

@rbuckton needs to give his opinion of how the late-binding works because I don't understand that well enough to know whether it's good.

return AssignmentDeclarationKind.None;
}

// TODO: Signed numeric literals?
Copy link
Member

Choose a reason for hiding this comment

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

Decide whether they're in or out and either remove the TODO or replace it with a warning that they are(n't) supported.

Copy link
Member Author

Choose a reason for hiding this comment

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

They should proooobably be in, but some checks are going to get way more complicated to support them.

Copy link
Member Author

Choose a reason for hiding this comment

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

replace it with a warning that they are(n't) supported.

That would be a strict degradation from today's behavior where A[+0] is simply an access on A's 0 - no we can't warn here; but I do think recognizing more than this is just an incremental enhancement.

Copy link
Member Author

@weswigham weswigham Sep 23, 2019

Choose a reason for hiding this comment

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

For reference to a similar area where incremental enhancements could be made, if you write

const x = {
    [+(0)]: 12
}

const n = x[1]

n is not an error, but if you write

const x = {
    [+0]: 12
}

const n = x[1]

it is, the only difference being a runtime non-affecting set of parenthesis.

Copy link
Member

Choose a reason for hiding this comment

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

yeah, a user warning isn't necessary, but a jsdoc warning instead of a TODO in the source is good enough.

Copy link
Member

@sandersn sandersn left a comment

Choose a reason for hiding this comment

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

Looks good once perf tests come back clean.

Also a couple of optional suggestions.

return AssignmentDeclarationKind.None;
}

// TODO: Signed numeric literals?
Copy link
Member

Choose a reason for hiding this comment

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

yeah, a user warning isn't necessary, but a jsdoc warning instead of a TODO in the source is good enough.


function addLateBoundAssignmentDeclarationToSymbol(node: BinaryExpression | DynamicNamedDeclaration, symbol: Symbol | undefined) {
if (symbol) {
const members = symbol.assignmentDeclarationMembers || (symbol.assignmentDeclarationMembers = createMap());
Copy link
Member

Choose a reason for hiding this comment

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

changing the shape of Symbol makes me think we should run the perf tests as a precaution.

@weswigham
Copy link
Member Author

@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 24, 2019

Heya @weswigham, I've started to run the perf test suite on this PR at a2e3797. You can monitor the build here. It should now contribute to this PR's status checks.

@weswigham
Copy link
Member Author

@typescript-bot perf test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Sep 24, 2019

Heya @weswigham, I've started to run the perf test suite on this PR at 489a01b. You can monitor the build here. It should now contribute to this PR's status checks.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

@weswigham
The results of the perf run you requested are in!

Here they are:

Comparison Report - master..33220

Metric master 33220 Delta Best Worst
Angular - node (v12.1.0, x64)
Memory used 331,799k (± 0.02%) 332,361k (± 0.03%) +562k (+ 0.17%) 332,114k 332,508k
Parse Time 1.57s (± 0.48%) 1.57s (± 0.57%) -0.00s (- 0.06%) 1.54s 1.58s
Bind Time 0.80s (± 0.37%) 0.81s (± 0.71%) +0.01s (+ 1.00%) 0.80s 0.83s
Check Time 4.37s (± 0.53%) 4.38s (± 0.37%) +0.01s (+ 0.21%) 4.35s 4.43s
Emit Time 5.28s (± 1.01%) 5.25s (± 0.51%) -0.02s (- 0.40%) 5.21s 5.32s
Total Time 12.02s (± 0.55%) 12.01s (± 0.25%) -0.01s (- 0.07%) 11.95s 12.07s
Monaco - node (v12.1.0, x64)
Memory used 346,910k (± 0.02%) 346,963k (± 0.01%) +53k (+ 0.02%) 346,879k 347,028k
Parse Time 1.22s (± 0.67%) 1.23s (± 0.80%) +0.01s (+ 0.66%) 1.21s 1.25s
Bind Time 0.69s (± 0.84%) 0.69s (± 0.65%) +0.00s (+ 0.15%) 0.68s 0.70s
Check Time 4.37s (± 0.49%) 4.39s (± 0.31%) +0.02s (+ 0.39%) 4.36s 4.42s
Emit Time 2.86s (± 0.71%) 2.89s (± 0.93%) +0.03s (+ 0.98%) 2.85s 2.96s
Total Time 9.13s (± 0.37%) 9.19s (± 0.30%) +0.06s (+ 0.68%) 9.14s 9.27s
TFS - node (v12.1.0, x64)
Memory used 303,634k (± 0.02%) 303,711k (± 0.02%) +76k (+ 0.03%) 303,611k 303,803k
Parse Time 0.95s (± 0.65%) 0.95s (± 0.79%) +0.00s (+ 0.32%) 0.94s 0.98s
Bind Time 0.63s (± 0.47%) 0.64s (± 0.53%) +0.01s (+ 0.79%) 0.63s 0.64s
Check Time 3.99s (± 0.54%) 4.00s (± 0.43%) +0.01s (+ 0.30%) 3.96s 4.05s
Emit Time 2.99s (± 1.05%) 2.96s (± 0.61%) -0.03s (- 0.90%) 2.94s 3.01s
Total Time 8.56s (± 0.50%) 8.55s (± 0.43%) -0.01s (- 0.08%) 8.51s 8.66s
Angular - node (v8.9.0, x64)
Memory used 350,390k (± 0.01%) 350,971k (± 0.02%) +581k (+ 0.17%) 350,814k 351,127k
Parse Time 2.10s (± 0.29%) 2.11s (± 0.26%) +0.01s (+ 0.33%) 2.10s 2.12s
Bind Time 0.84s (± 0.69%) 0.86s (± 0.80%) +0.01s (+ 1.42%) 0.84s 0.87s
Check Time 5.25s (± 0.51%) 5.26s (± 0.55%) +0.01s (+ 0.19%) 5.19s 5.33s
Emit Time 6.03s (± 0.95%) 6.00s (± 0.71%) -0.03s (- 0.43%) 5.92s 6.09s
Total Time 14.22s (± 0.43%) 14.22s (± 0.43%) +0.00s (+ 0.01%) 14.07s 14.38s
Monaco - node (v8.9.0, x64)
Memory used 364,624k (± 0.01%) 364,635k (± 0.01%) +11k (+ 0.00%) 364,473k 364,734k
Parse Time 1.57s (± 0.64%) 1.56s (± 0.58%) -0.01s (- 0.32%) 1.55s 1.59s
Bind Time 0.90s (± 0.76%) 0.89s (± 0.53%) -0.00s (- 0.33%) 0.88s 0.90s
Check Time 5.21s (± 0.43%) 5.25s (± 1.55%) +0.04s (+ 0.83%) 5.12s 5.52s
Emit Time 3.31s (± 0.85%) 3.22s (± 3.93%) -0.10s (- 2.99%) 2.95s 3.39s
Total Time 10.98s (± 0.35%) 10.92s (± 0.67%) -0.07s (- 0.60%) 10.72s 11.03s
TFS - node (v8.9.0, x64)
Memory used 319,890k (± 0.01%) 319,918k (± 0.01%) +28k (+ 0.01%) 319,832k 320,028k
Parse Time 1.26s (± 0.49%) 1.26s (± 0.60%) +0.00s (+ 0.24%) 1.25s 1.28s
Bind Time 0.71s (± 6.65%) 0.72s (± 7.03%) +0.01s (+ 0.99%) 0.66s 0.83s
Check Time 4.55s (± 1.37%) 4.57s (± 1.24%) +0.02s (+ 0.44%) 4.43s 4.67s
Emit Time 3.08s (± 0.57%) 3.07s (± 0.92%) -0.00s (- 0.16%) 2.98s 3.12s
Total Time 9.60s (± 0.25%) 9.63s (± 0.41%) +0.03s (+ 0.28%) 9.55s 9.73s
Angular - node (v8.9.0, x86)
Memory used 198,342k (± 0.03%) 198,670k (± 0.02%) +328k (+ 0.17%) 198,579k 198,792k
Parse Time 2.04s (± 0.49%) 2.03s (± 0.58%) -0.01s (- 0.39%) 2.01s 2.07s
Bind Time 0.97s (± 0.77%) 0.97s (± 0.87%) +0.00s (+ 0.21%) 0.96s 1.00s
Check Time 4.77s (± 0.73%) 4.75s (± 0.54%) -0.02s (- 0.44%) 4.69s 4.80s
Emit Time 5.68s (± 0.37%) 5.75s (± 1.29%) +0.07s (+ 1.29%) 5.60s 5.92s
Total Time 13.45s (± 0.32%) 13.50s (± 0.67%) +0.05s (+ 0.36%) 13.30s 13.69s
Monaco - node (v8.9.0, x86)
Memory used 203,773k (± 0.02%) 203,783k (± 0.02%) +10k (+ 0.00%) 203,735k 203,917k
Parse Time 1.62s (± 0.55%) 1.62s (± 0.80%) +0.00s (+ 0.06%) 1.59s 1.65s
Bind Time 0.71s (± 0.52%) 0.72s (± 1.03%) +0.01s (+ 1.12%) 0.71s 0.74s
Check Time 5.02s (± 0.45%) 5.09s (± 2.23%) +0.07s (+ 1.37%) 4.97s 5.41s
Emit Time 3.15s (± 0.53%) 3.05s (± 3.52%) -0.10s (- 3.08%) 2.77s 3.17s
Total Time 10.50s (± 0.26%) 10.48s (± 0.41%) -0.02s (- 0.21%) 10.39s 10.59s
TFS - node (v8.9.0, x86)
Memory used 179,714k (± 0.02%) 179,723k (± 0.02%) +9k (+ 0.00%) 179,667k 179,804k
Parse Time 1.31s (± 0.99%) 1.31s (± 0.56%) -0.01s (- 0.46%) 1.30s 1.33s
Bind Time 0.64s (± 1.07%) 0.64s (± 0.96%) +0.01s (+ 0.79%) 0.63s 0.66s
Check Time 4.38s (± 0.94%) 4.40s (± 0.78%) +0.02s (+ 0.50%) 4.34s 4.50s
Emit Time 2.87s (± 1.02%) 2.84s (± 0.69%) -0.04s (- 1.22%) 2.77s 2.87s
Total Time 9.20s (± 0.39%) 9.18s (± 0.37%) -0.01s (- 0.15%) 9.11s 9.26s
Angular - node (v9.0.0, x64)
Memory used 350,014k (± 0.01%) 350,589k (± 0.02%) +576k (+ 0.16%) 350,378k 350,726k
Parse Time 1.82s (± 0.49%) 1.83s (± 0.74%) +0.01s (+ 0.66%) 1.80s 1.85s
Bind Time 0.79s (± 0.63%) 0.79s (± 0.62%) +0.01s (+ 1.02%) 0.79s 0.81s
Check Time 5.01s (± 0.50%) 5.01s (± 0.57%) +0.00s (+ 0.02%) 4.96s 5.08s
Emit Time 5.79s (± 1.28%) 5.78s (± 1.50%) -0.01s (- 0.19%) 5.61s 6.00s
Total Time 13.40s (± 0.57%) 13.41s (± 0.75%) +0.01s (+ 0.08%) 13.21s 13.72s
Monaco - node (v9.0.0, x64)
Memory used 364,314k (± 0.02%) 364,342k (± 0.03%) +28k (+ 0.01%) 364,129k 364,541k
Parse Time 1.31s (± 0.42%) 1.31s (± 0.34%) 0.00s ( 0.00%) 1.30s 1.32s
Bind Time 0.85s (± 1.30%) 0.86s (± 1.29%) +0.01s (+ 0.82%) 0.84s 0.88s
Check Time 5.19s (± 1.72%) 5.19s (± 1.44%) +0.00s (+ 0.02%) 5.07s 5.34s
Emit Time 3.13s (± 5.57%) 3.17s (± 5.34%) +0.04s (+ 1.41%) 2.87s 3.39s
Total Time 10.48s (± 1.01%) 10.53s (± 1.09%) +0.05s (+ 0.47%) 10.31s 10.74s
TFS - node (v9.0.0, x64)
Memory used 319,516k (± 0.02%) 319,581k (± 0.01%) +66k (+ 0.02%) 319,537k 319,627k
Parse Time 1.03s (± 0.66%) 1.04s (± 0.70%) +0.01s (+ 0.68%) 1.03s 1.06s
Bind Time 0.63s (± 0.71%) 0.63s (± 0.57%) +0.00s (+ 0.32%) 0.63s 0.64s
Check Time 4.56s (± 0.63%) 4.58s (± 0.62%) +0.02s (+ 0.48%) 4.52s 4.65s
Emit Time 3.22s (± 0.79%) 3.23s (± 0.69%) +0.01s (+ 0.25%) 3.18s 3.28s
Total Time 9.44s (± 0.31%) 9.48s (± 0.45%) +0.04s (+ 0.43%) 9.40s 9.59s
Angular - node (v9.0.0, x86)
Memory used 198,478k (± 0.04%) 198,812k (± 0.04%) +334k (+ 0.17%) 198,674k 199,013k
Parse Time 1.73s (± 0.57%) 1.73s (± 0.61%) +0.00s (+ 0.12%) 1.71s 1.75s
Bind Time 0.91s (± 0.74%) 0.91s (± 0.52%) +0.00s (+ 0.33%) 0.90s 0.92s
Check Time 4.44s (± 0.40%) 4.45s (± 0.33%) +0.01s (+ 0.18%) 4.42s 4.50s
Emit Time 5.51s (± 0.65%) 5.54s (± 0.74%) +0.03s (+ 0.58%) 5.45s 5.65s
Total Time 12.59s (± 0.31%) 12.64s (± 0.45%) +0.05s (+ 0.37%) 12.53s 12.76s
Monaco - node (v9.0.0, x86)
Memory used 203,756k (± 0.03%) 203,774k (± 0.03%) +18k (+ 0.01%) 203,660k 203,943k
Parse Time 1.35s (± 0.93%) 1.34s (± 0.39%) -0.01s (- 0.89%) 1.33s 1.35s
Bind Time 0.66s (± 0.88%) 0.66s (± 0.72%) 0.00s ( 0.00%) 0.65s 0.67s
Check Time 4.86s (± 0.75%) 4.88s (± 0.61%) +0.02s (+ 0.37%) 4.82s 4.93s
Emit Time 3.09s (± 0.90%) 3.08s (± 1.11%) -0.01s (- 0.29%) 2.96s 3.14s
Total Time 9.96s (± 0.59%) 9.96s (± 0.37%) -0.00s (- 0.01%) 9.87s 10.04s
TFS - node (v9.0.0, x86)
Memory used 179,671k (± 0.01%) 179,723k (± 0.02%) +52k (+ 0.03%) 179,634k 179,809k
Parse Time 1.06s (± 1.00%) 1.07s (± 1.58%) +0.01s (+ 0.94%) 1.06s 1.14s
Bind Time 0.59s (± 1.35%) 0.60s (± 0.83%) +0.00s (+ 0.68%) 0.59s 0.61s
Check Time 4.29s (± 0.57%) 4.32s (± 0.47%) +0.02s (+ 0.54%) 4.27s 4.36s
Emit Time 2.79s (± 0.77%) 2.87s (± 2.55%) +0.07s (+ 2.69%) 2.78s 3.14s
Total Time 8.74s (± 0.55%) 8.85s (± 1.04%) +0.11s (+ 1.28%) 8.76s 9.21s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-161-generic
Architecturex64
Available Memory16 GB
Available Memory9 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v12.1.0, x64)
  • node (v8.9.0, x64)
  • node (v8.9.0, x86)
  • node (v9.0.0, x64)
  • node (v9.0.0, x86)
Scenarios
  • Angular - node (v12.1.0, x64)
  • Angular - node (v8.9.0, x64)
  • Angular - node (v8.9.0, x86)
  • Angular - node (v9.0.0, x64)
  • Angular - node (v9.0.0, x86)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v8.9.0, x64)
  • Monaco - node (v8.9.0, x86)
  • Monaco - node (v9.0.0, x64)
  • Monaco - node (v9.0.0, x86)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v8.9.0, x64)
  • TFS - node (v8.9.0, x86)
  • TFS - node (v9.0.0, x64)
  • TFS - node (v9.0.0, x86)
Benchmark Name Iterations
Current 33220 10
Baseline master 10

@weswigham
Copy link
Member Author

weswigham commented Sep 24, 2019

@sandersn the benchmark seems fine (which tbh is to be expected - this pattern doesn't occur anywhere in our perf test suite, so at no point is Symbol's shape changed in any of them).

@rbuckton would really love a review from you, too ❤️

return idText(name);
}
if (isNumericLiteral(name)) {
return "" + (+name.text);
Copy link
Member

Choose a reason for hiding this comment

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

🤔 I’m sure there’s a good reason for this

Copy link
Member Author

Choose a reason for hiding this comment

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

Assume name.text is 1e1 as a string. Convert to number, get out 10, convert back to string, have the string "10". This matters for indexing, since only the canonical representation is the stringy key name.

image

Copy link
Member Author

Choose a reason for hiding this comment

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

@rbuckton points out that the misleadingly named .text has already been canonicalized in the scanner, so this is unneeded 😛

@@ -814,7 +814,7 @@ namespace ts {

export type PropertyName = Identifier | StringLiteral | NumericLiteral | ComputedPropertyName;

export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | BindingPattern;
export type DeclarationName = Identifier | StringLiteralLike | NumericLiteral | ComputedPropertyName | ElementAccessExpression | BindingPattern;
Copy link
Contributor

Choose a reason for hiding this comment

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

navigationBar uses DeclarationName and getNameOfDeclaration. Is it affected by this change?

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmm, it uses nodeText on the name, which probably works fine for ComputedPropertyDeclarations, but probably falls a little short for ElementAccessExpressions. Can you point me to a test for computed property name tests for navigationBar? I'll (speculatively) build in the fix, but I'd like to add a test.

Copy link
Contributor

Choose a reason for hiding this comment

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

tests\cases\fourslash\navigationBarItemsSymbols1.ts

Copy link
Member

Choose a reason for hiding this comment

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

Copy link
Member Author

@weswigham weswigham Sep 27, 2019

Choose a reason for hiding this comment

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

So, turns out js assignment members aren't syntactically children, so they can't be in the nav bar (which only looks at syntax members). Additionally, the nav bar excludes dynamically named members, so on two fronts these shouldn't appear in the nav bar. I've added a test showing the behavior~

…ve fix to navigation bar, merge check and type for elem/property accesses
@weswigham weswigham requested a review from rbuckton September 27, 2019 01:38
@weswigham weswigham merged commit 2938168 into microsoft:master Sep 27, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

TS does not recognize constructor assignments of unique symbol properties in JS
5 participants