Skip to content
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

Eliminate well known symbols as a concept in the checker and rely on unique symbols #42543

Merged
merged 7 commits into from
Feb 22, 2021

Conversation

weswigham
Copy link
Member

#24738, but for 2021 and not 2018.

The parts from the original PR description that still hold:

Interestingly, there is some fallout here in some odd places:

  • First of all, some small changes needed to occur to replicate old behavior. Right now, a computed name of type any produces a number index signature. With this change, we make a string index signature instead (it's more broad and closer to correct).
  • Lastly, some emit changes - specifically, where previously we'd elide Symbol.iterator when it appeared as a property name (and assume that the expression had no sideffects), now we retain and emit it (and potentially cache it), as we generally do not assume property access expressions are safe to elide or copy.

Fixes #24622

An important implementation note: As we discussed in person, Inside the checker, if we see members of the global SymbolConstructor of type symbol, we also assume you meant to say unique symbol. In this way, we retain compatibility with older libs or definition files (even as they update), which is how this can build (at all), given node is shimming Symbol.iterator as a symbol.

Fixes #24622
Fixes #27525
Fixes #31253
Fixes #21603
Fixes #37182
Fixes half of #36468 (indirect calls to Symbol() still do not produce fresh unique symbols like direct calls do - but that should be a separate change, IMO)

return append(concatenate(concatenate([container], additionalContainers), reexportContainers), objectLiteralContainer); // This order expresses a preference for the real container if it is in scope
}
// we potentially a symbol which is a member of the instance side of something - look for a variable in scope with the container's type
// which may be acting like a namespace
const firstVariableMatch = !(container.flags & getQualifiedLeftMeaning(meaning))
Copy link
Member Author

@weswigham weswigham Jan 29, 2021

Choose a reason for hiding this comment

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

I'll call this out since it's a new bit compared to the older PR. This bit and the following modify our symbol container lookup to prefer, eg, Symbol.iterator to SymbolConstructor.iterator when doing printback for where the specified SymbolFlags say the first is allowable. Now, this isn't specific to symbols or Symbol in any way - other dynamic names from namespace-ish things should work similarly, too! So ArrayConstructor, Int8ArrayConsturctor.... anything with the split namespace pattern the DOM uses a lot.

@@ -5104,8 +5119,9 @@ namespace ts {
}
}
}
context.enclosingDeclaration = saveEnclosingDeclaration;
context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] || saveEnclosingDeclaration;
Copy link
Member Author

Choose a reason for hiding this comment

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

If we don't set a specific enclosingDeclaration when serializing the name, in cases where we don't pass a contextual one (eg, error reporting), we'd print a name like [iterator] instead of [Symbol.iterator] (because symbol chain lookup bails entirely if there's no enclosing declaration provided). I think we much prefer the later, so now we actually specify an enclosing declaration for the name whenever we can.

Copy link
Member

Choose a reason for hiding this comment

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

What's an example where propertySymbol.declarations?.[0] is useful?

Copy link
Member Author

Choose a reason for hiding this comment

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

valueDeclaration is unset in two cases - one: when the symbol doesn't have a value meaning (as when it comes from an interface), two: when two value symbols merge and have differing value declarations. In both cases, we'd like a context node for the name here.

if (prop.escapedName === InternalSymbolName.Default) {
type = getLiteralType("default");
}
else {
const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration) as PropertyName;
type = name && getLiteralTypeFromPropertyName(name) || getLiteralType(symbolName(prop));
type = name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getLiteralType(symbolName(prop)) : undefined);
Copy link
Member Author

Choose a reason for hiding this comment

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

Perhaps confusingly, isKnownSymbol has almost nothing to do with well-known symbols, and actually just checks if the checker Symbol has a symbol-y name (eg, it's escapedName starts with __@). It's mostly gone, since we were, intent-wise, actually using it to proxy for well-known-symboly-ness in places; however a handful of select locations remain where we actually want to check for normal symbol-ness.

Copy link
Member

Choose a reason for hiding this comment

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

It won't be confusing once well-known symbols are gone as a concept, right? Seems fine to me.

@@ -25321,7 +25342,10 @@ namespace ts {
}

if (computedNameType && !(computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique)) {
if (isTypeAssignableTo(computedNameType, stringNumberSymbolType)) {
if (isTypeAny(computedNameType)) {
Copy link
Member Author

@weswigham weswigham Jan 29, 2021

Choose a reason for hiding this comment

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

Technically, I can push this change through without this change, if we'd prefer. However, that means when you write, eg

const obj = {
  [Symbol.whatever]: 0
};

obj would get a number index signature (since Symbol.whatever is going to be any from the error of it not existing), whereas with this it gets a string index signature (which, IMO, makes much more sense for an any computed name). It mostly only matters, in the context of unique symbols, for follow-on errors to nonexistant symbols which were previously "well known" and thus entirely unchecked (which now get an error, become any and thus produce an index signature of some kind).

Copy link
Member

Choose a reason for hiding this comment

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

From the comment here, it sounds like this mostly to cater to the "degenerate" case of Symbol.thingThatDoesNotExist which can happen in a loosely configured JavaScript project - is that the use-case you have in mind? And

That does loosen the behavior of this by quite a bit. I think I would be willing to go the opposite way and take a break on this behavior.

Copy link
Member Author

@weswigham weswigham Feb 13, 2021

Choose a reason for hiding this comment

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

You definitely don't wanna go the opposite way, because the numeric index signature we otherwise make makes very little sense, IMO. I actually think any producing a number index signature just feels a bit like a bug that we aught to fix.

Copy link
Member

Choose a reason for hiding this comment

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

I get that, but I think the any behavior is already pretty undesirable, and is exacerbated if you're not using --noUncheckedIndexedAccess.

Copy link
Member Author

Choose a reason for hiding this comment

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

???? That flag is about accessing keys and the types accessed keys are assigned, where here the issue is solely weather or not we make a key at all, and what slot that key should go in; that seems wholly unrelated to that flag.

Copy link
Member

@DanielRosenwasser DanielRosenwasser Feb 16, 2021

Choose a reason for hiding this comment

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

But

const s = {["str" as any]: "str"}

can now be indexed by a wider variety of nonsense that would never work either, like s["uh oh"]. You're allowing a much more optimistic type to be formed which you can't take back after the fact unless you add a new flag.

Copy link
Member

Choose a reason for hiding this comment

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

And in fact, I think that's why the numeric index signature was chosen - because at the time we also felt the behavior it supported was more desirable even if it wasn't good.

The point of the numeric index signature isn't to support indexing with numbers - it's to support indexing with any and still getting the appropriate type out. It's a hack, but it doesn't widen the net to every possible non-numeric property.

Copy link
Member Author

Choose a reason for hiding this comment

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

But the point of any is to "widen the net".

Copy link
Member

Choose a reason for hiding this comment

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

At best this isn't something we need to change with this feature. I don't find the "well known symbol that doesn't exist" thing to be a use-case that should fundamentally change what happens when you use any as a computed property key.

Copy link
Member Author

Choose a reason for hiding this comment

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

Alright 🤷‍♂️

function getPropertyNameForKnownSymbolName(symbolName: string): __String {
const ctorType = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false);
const uniqueType = ctorType && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName));
return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) : `__@${symbolName}` as __String;
Copy link
Member Author

Choose a reason for hiding this comment

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

The __@${symbolName} as __String; case is reachable in scenarios where our internals request a name for a symbol which doesn't exist in the lib. Eg, requesting Symbol.asyncIterator in a lib target where it doesn't exist. No construct can make a property symbol name in that format anymore (unique symbol names have the form __@desc@###), so it's guaranteed to result in an undefined result from getPropertyOfType, resulting in a noIterationTypes result (as you may expect when the core iteration protocol types are missing!).

Copy link
Member

Choose a reason for hiding this comment

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

Can you give a little more context on the significance? Are you saying this is handled well in the existing code, that other code needs to be careful, that there's a fundamental architectural issue, or that this now has a user-facing impact? (or all?)

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm saying that properties with a name like that can no longer be constructed, so when the proper name cannot be found, returning a name like that will always make a follow-up property lookup fail, which has the desired outcome.

@@ -269,8 +269,7 @@ namespace ts {
* any such locations
*/
export function isSimpleInlineableExpression(expression: Expression) {
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) ||
isWellKnownSymbolSyntactically(expression);
return !isIdentifier(expression) && isSimpleCopiableExpression(expression);
Copy link
Member Author

Choose a reason for hiding this comment

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

This change is pretty much single-handedly responsible for the .js emit changes in this PR. Symbol.iterator and it's ilk aren't "simple copyable expressions" since, technically, accessing it could produce side effects (like any other property access). Now... at some point, we added Identifiers to isSimpleCopiableExpression's domain (which isn't technically safe, since the identifier may get reassigned between the copied references), so maybe property accesses which only consist of Identifiers wouldn't be terribly unreasonable, either. 🤷

Copy link
Member

Choose a reason for hiding this comment

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

@rbuckton is probably the best judge of that.

@@ -5,7 +5,7 @@ interface SymbolConstructor {
* A method that returns the default iterator for an object. Called by the semantics of the
* for-of statement.
*/
readonly iterator: symbol;
readonly iterator: unique symbol;
Copy link
Member Author

Choose a reason for hiding this comment

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

Fun fact! I didn't actually need to make any of these lib changes to make the PR work, what with the compat code in place! But I've updated them anyway, so they serve as examples of what unique symbols really are to anyone reading the definitions.

Copy link
Member

Choose a reason for hiding this comment

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

Hm - and that won't conflict with a separate "polyfill" definition right? In other words, if someone separately declares it as

interface SymbolConstructor {
    readonly iterator: symbol;
}

and these merge, they won't end up conflicting, right?

Copy link
Member Author

Choose a reason for hiding this comment

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

Nope - and there's already a test to that effect on the diff.

@weswigham
Copy link
Member Author

@typescript-bot run dt
@typescript-bot perf test this
@typescript-bot user test this
@typescript-bot test this

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 29, 2021

Heya @weswigham, I've started to run the extended test suite on this PR at 4c808c4. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 29, 2021

Heya @weswigham, I've started to run the perf test suite on this PR at 4c808c4. You can monitor the build here.

Update: The results are in!

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 29, 2021

Heya @weswigham, I've started to run the parallelized community code test suite on this PR at 4c808c4. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

typescript-bot commented Jan 29, 2021

Heya @weswigham, I've started to run the parallelized Definitely Typed test suite on this PR at 4c808c4. You can monitor the build here.

@typescript-bot
Copy link
Collaborator

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

Here they are:

Comparison Report - master..42543

Metric master 42543 Delta Best Worst
Angular - node (v10.16.3, x64)
Memory used 346,476k (± 0.02%) 346,381k (± 0.02%) -95k (- 0.03%) 346,195k 346,557k
Parse Time 1.98s (± 0.63%) 1.99s (± 0.51%) +0.01s (+ 0.46%) 1.96s 2.01s
Bind Time 0.83s (± 0.54%) 0.82s (± 0.45%) -0.00s (- 0.36%) 0.82s 0.83s
Check Time 4.98s (± 0.69%) 4.99s (± 0.37%) +0.01s (+ 0.24%) 4.95s 5.04s
Emit Time 5.36s (± 0.64%) 5.35s (± 0.77%) -0.01s (- 0.13%) 5.25s 5.46s
Total Time 13.14s (± 0.53%) 13.15s (± 0.38%) +0.01s (+ 0.09%) 13.06s 13.28s
Compiler-Unions - node (v10.16.3, x64)
Memory used 214,889k (± 0.07%) 214,895k (± 0.07%) +6k (+ 0.00%) 214,329k 215,097k
Parse Time 0.80s (± 1.34%) 0.79s (± 0.38%) -0.00s (- 0.38%) 0.79s 0.80s
Bind Time 0.50s (± 0.73%) 0.50s (± 1.04%) +0.00s (+ 0.60%) 0.49s 0.51s
Check Time 10.67s (± 0.45%) 10.77s (± 1.20%) +0.10s (+ 0.96%) 10.54s 11.05s
Emit Time 2.34s (± 1.59%) 2.33s (± 0.80%) -0.01s (- 0.60%) 2.30s 2.38s
Total Time 14.30s (± 0.38%) 14.39s (± 0.91%) +0.09s (+ 0.65%) 14.18s 14.68s
Monaco - node (v10.16.3, x64)
Memory used 355,353k (± 0.03%) 355,384k (± 0.02%) +31k (+ 0.01%) 355,154k 355,471k
Parse Time 1.60s (± 0.28%) 1.62s (± 0.58%) +0.02s (+ 1.19%) 1.60s 1.64s
Bind Time 0.73s (± 0.89%) 0.73s (± 1.03%) -0.00s (- 0.14%) 0.71s 0.74s
Check Time 5.14s (± 0.40%) 5.16s (± 0.55%) +0.02s (+ 0.45%) 5.09s 5.22s
Emit Time 2.83s (± 0.57%) 2.84s (± 0.82%) +0.01s (+ 0.39%) 2.81s 2.92s
Total Time 10.30s (± 0.31%) 10.35s (± 0.36%) +0.05s (+ 0.50%) 10.25s 10.40s
TFS - node (v10.16.3, x64)
Memory used 308,165k (± 0.02%) 308,134k (± 0.03%) -31k (- 0.01%) 307,909k 308,314k
Parse Time 1.24s (± 0.65%) 1.24s (± 0.62%) +0.00s (+ 0.24%) 1.22s 1.25s
Bind Time 0.68s (± 1.32%) 0.68s (± 0.49%) +0.00s (+ 0.59%) 0.67s 0.69s
Check Time 4.62s (± 0.44%) 4.62s (± 0.51%) -0.00s (- 0.02%) 4.57s 4.68s
Emit Time 2.94s (± 1.06%) 2.95s (± 0.67%) +0.02s (+ 0.54%) 2.90s 2.99s
Total Time 9.47s (± 0.42%) 9.49s (± 0.38%) +0.03s (+ 0.26%) 9.43s 9.60s
material-ui - node (v10.16.3, x64)
Memory used 496,337k (± 0.02%) 496,372k (± 0.01%) +35k (+ 0.01%) 496,257k 496,512k
Parse Time 2.06s (± 0.61%) 2.06s (± 0.67%) 0.00s ( 0.00%) 2.04s 2.09s
Bind Time 0.66s (± 1.75%) 0.66s (± 1.97%) -0.00s (- 0.15%) 0.63s 0.68s
Check Time 14.03s (± 0.61%) 14.01s (± 0.85%) -0.03s (- 0.19%) 13.81s 14.32s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 16.76s (± 0.46%) 16.73s (± 0.78%) -0.03s (- 0.18%) 16.52s 17.07s
Angular - node (v12.1.0, x64)
Memory used 323,924k (± 0.10%) 324,057k (± 0.02%) +133k (+ 0.04%) 323,908k 324,199k
Parse Time 1.98s (± 0.71%) 1.99s (± 0.69%) +0.01s (+ 0.40%) 1.97s 2.03s
Bind Time 0.82s (± 1.15%) 0.80s (± 0.50%) -0.02s (- 1.96%) 0.79s 0.81s
Check Time 4.93s (± 0.84%) 4.92s (± 0.43%) -0.01s (- 0.16%) 4.87s 4.95s
Emit Time 5.52s (± 1.07%) 5.50s (± 0.32%) -0.02s (- 0.38%) 5.47s 5.54s
Total Time 13.23s (± 0.82%) 13.20s (± 0.32%) -0.03s (- 0.22%) 13.11s 13.29s
Compiler-Unions - node (v12.1.0, x64)
Memory used 200,388k (± 0.06%) 200,159k (± 0.09%) -230k (- 0.11%) 199,745k 200,517k
Parse Time 0.78s (± 0.64%) 0.78s (± 0.96%) +0.00s (+ 0.26%) 0.76s 0.80s
Bind Time 0.50s (± 0.60%) 0.51s (± 0.74%) +0.01s (+ 1.41%) 0.50s 0.51s
Check Time 9.89s (± 1.13%) 10.03s (± 0.58%) +0.13s (+ 1.35%) 9.81s 10.11s
Emit Time 2.37s (± 1.24%) 2.36s (± 1.46%) -0.01s (- 0.63%) 2.28s 2.42s
Total Time 13.54s (± 0.88%) 13.67s (± 0.60%) +0.13s (+ 0.97%) 13.39s 13.81s
Monaco - node (v12.1.0, x64)
Memory used 337,515k (± 0.02%) 337,572k (± 0.01%) +56k (+ 0.02%) 337,487k 337,669k
Parse Time 1.60s (± 0.70%) 1.60s (± 0.62%) +0.00s (+ 0.25%) 1.58s 1.62s
Bind Time 0.70s (± 0.57%) 0.70s (± 0.43%) -0.00s (- 0.43%) 0.69s 0.70s
Check Time 4.94s (± 0.47%) 4.94s (± 0.45%) -0.00s (- 0.06%) 4.88s 4.99s
Emit Time 2.86s (± 0.81%) 2.89s (± 0.66%) +0.03s (+ 0.91%) 2.85s 2.93s
Total Time 10.10s (± 0.42%) 10.13s (± 0.36%) +0.03s (+ 0.27%) 10.05s 10.24s
TFS - node (v12.1.0, x64)
Memory used 292,413k (± 0.02%) 292,421k (± 0.01%) +8k (+ 0.00%) 292,352k 292,534k
Parse Time 1.25s (± 0.53%) 1.26s (± 0.54%) +0.00s (+ 0.24%) 1.24s 1.27s
Bind Time 0.65s (± 0.75%) 0.65s (± 0.95%) -0.00s (- 0.46%) 0.64s 0.67s
Check Time 4.53s (± 0.52%) 4.52s (± 0.29%) -0.01s (- 0.13%) 4.50s 4.56s
Emit Time 2.95s (± 0.41%) 2.94s (± 0.91%) -0.01s (- 0.37%) 2.88s 2.98s
Total Time 9.38s (± 0.32%) 9.36s (± 0.39%) -0.02s (- 0.23%) 9.28s 9.45s
material-ui - node (v12.1.0, x64)
Memory used 473,103k (± 0.09%) 473,448k (± 0.06%) +345k (+ 0.07%) 472,382k 473,651k
Parse Time 2.07s (± 0.46%) 2.09s (± 0.56%) +0.02s (+ 0.92%) 2.07s 2.12s
Bind Time 0.64s (± 0.56%) 0.64s (± 0.73%) -0.00s (- 0.62%) 0.63s 0.65s
Check Time 12.65s (± 1.25%) 12.64s (± 1.01%) -0.00s (- 0.04%) 12.40s 12.98s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.36s (± 1.04%) 15.37s (± 0.86%) +0.01s (+ 0.06%) 15.10s 15.70s
Angular - node (v14.15.1, x64)
Memory used 322,736k (± 0.01%) 322,734k (± 0.01%) -2k (- 0.00%) 322,649k 322,805k
Parse Time 1.99s (± 0.58%) 2.00s (± 0.63%) +0.01s (+ 0.65%) 1.98s 2.03s
Bind Time 0.86s (± 0.43%) 0.86s (± 0.43%) -0.01s (- 1.16%) 0.85s 0.86s
Check Time 4.89s (± 0.33%) 4.88s (± 0.32%) -0.02s (- 0.39%) 4.83s 4.91s
Emit Time 5.55s (± 0.68%) 5.58s (± 0.59%) +0.03s (+ 0.47%) 5.52s 5.64s
Total Time 13.30s (± 0.37%) 13.31s (± 0.37%) +0.02s (+ 0.11%) 13.20s 13.40s
Compiler-Unions - node (v14.15.1, x64)
Memory used 200,755k (± 0.52%) 201,632k (± 0.68%) +878k (+ 0.44%) 199,009k 203,509k
Parse Time 0.82s (± 0.63%) 0.82s (± 0.68%) +0.00s (+ 0.37%) 0.81s 0.83s
Bind Time 0.53s (± 0.63%) 0.53s (± 0.76%) -0.00s (- 0.19%) 0.52s 0.54s
Check Time 9.77s (± 0.38%) 9.99s (± 0.80%) +0.22s (+ 2.28%) 9.82s 10.14s
Emit Time 2.34s (± 1.28%) 2.36s (± 1.81%) +0.02s (+ 0.68%) 2.30s 2.49s
Total Time 13.46s (± 0.34%) 13.70s (± 0.81%) +0.24s (+ 1.81%) 13.47s 13.89s
Monaco - node (v14.15.1, x64)
Memory used 336,859k (± 0.01%) 336,838k (± 0.01%) -21k (- 0.01%) 336,785k 336,901k
Parse Time 1.65s (± 0.81%) 1.65s (± 0.76%) -0.00s (- 0.30%) 1.63s 1.68s
Bind Time 0.73s (± 0.79%) 0.73s (± 0.88%) -0.00s (- 0.14%) 0.72s 0.75s
Check Time 4.85s (± 0.57%) 4.84s (± 0.31%) -0.01s (- 0.25%) 4.81s 4.88s
Emit Time 2.92s (± 0.17%) 2.93s (± 0.58%) +0.01s (+ 0.17%) 2.90s 2.97s
Total Time 10.16s (± 0.23%) 10.15s (± 0.25%) -0.02s (- 0.16%) 10.11s 10.21s
TFS - node (v14.15.1, x64)
Memory used 291,607k (± 0.00%) 291,608k (± 0.01%) +1k (+ 0.00%) 291,551k 291,669k
Parse Time 1.29s (± 0.73%) 1.30s (± 0.63%) +0.01s (+ 0.85%) 1.28s 1.32s
Bind Time 0.70s (± 0.71%) 0.69s (± 0.69%) -0.00s (- 0.43%) 0.68s 0.70s
Check Time 4.49s (± 0.53%) 4.51s (± 0.72%) +0.02s (+ 0.42%) 4.43s 4.59s
Emit Time 3.06s (± 0.74%) 3.07s (± 0.92%) +0.01s (+ 0.36%) 3.03s 3.14s
Total Time 9.54s (± 0.40%) 9.58s (± 0.46%) +0.04s (+ 0.39%) 9.48s 9.69s
material-ui - node (v14.15.1, x64)
Memory used 471,873k (± 0.06%) 471,719k (± 0.05%) -154k (- 0.03%) 471,108k 472,312k
Parse Time 2.13s (± 0.58%) 2.14s (± 0.80%) +0.00s (+ 0.14%) 2.10s 2.17s
Bind Time 0.70s (± 0.85%) 0.68s (± 0.53%) -0.02s (- 2.98%) 0.68s 0.69s
Check Time 12.81s (± 1.16%) 12.76s (± 0.75%) -0.05s (- 0.37%) 12.53s 12.97s
Emit Time 0.00s (± 0.00%) 0.00s (± 0.00%) 0.00s ( NaN%) 0.00s 0.00s
Total Time 15.64s (± 0.92%) 15.58s (± 0.67%) -0.06s (- 0.40%) 15.34s 15.81s
System
Machine Namets-ci-ubuntu
Platformlinux 4.4.0-198-generic
Architecturex64
Available Memory16 GB
Available Memory8 GB
CPUs4 × Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz
Hosts
  • node (v10.16.3, x64)
  • node (v12.1.0, x64)
  • node (v14.15.1, x64)
Scenarios
  • Angular - node (v10.16.3, x64)
  • Angular - node (v12.1.0, x64)
  • Angular - node (v14.15.1, x64)
  • Compiler-Unions - node (v10.16.3, x64)
  • Compiler-Unions - node (v12.1.0, x64)
  • Compiler-Unions - node (v14.15.1, x64)
  • Monaco - node (v10.16.3, x64)
  • Monaco - node (v12.1.0, x64)
  • Monaco - node (v14.15.1, x64)
  • TFS - node (v10.16.3, x64)
  • TFS - node (v12.1.0, x64)
  • TFS - node (v14.15.1, x64)
  • material-ui - node (v10.16.3, x64)
  • material-ui - node (v12.1.0, x64)
  • material-ui - node (v14.15.1, x64)
Benchmark Name Iterations
Current 42543 10
Baseline master 10

@rbuckton
Copy link
Member

I'm not sure if it will affect this PR or not, but I'm investigating changes to unique symbol to possibly add the same "freshness" concept we use for literal types in an effort to fix #32408 as well as to make our widening for unique symbol more consistent with other places where we widen.

@typescript-bot
Copy link
Collaborator

The user suite test run you requested has finished and failed. I've opened a PR with the baseline diff from master.

@weswigham
Copy link
Member Author

Nah, I don't think it'd affect this. Freshness is for types from "literals" (so, Symbol()) - Symbol.iterator and friends would all go on being the unfresh type.

@weswigham
Copy link
Member Author

weswigham commented Jan 29, 2021

Perf and user runs look fine. DT has two packages that look like some improvements, but I'll take a deeper look later. RWC has one project (a sample) with new errors because we reference es6+ symbols in the sample, but don't include the es6 lib (and prior to this we never checked that). So all in all tests look good.

src/compiler/checker.ts Show resolved Hide resolved
src/compiler/checker.ts Show resolved Hide resolved
@@ -5104,8 +5119,9 @@ namespace ts {
}
}
}
context.enclosingDeclaration = saveEnclosingDeclaration;
context.enclosingDeclaration = propertySymbol.valueDeclaration || propertySymbol.declarations?.[0] || saveEnclosingDeclaration;
Copy link
Member

Choose a reason for hiding this comment

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

What's an example where propertySymbol.declarations?.[0] is useful?

@@ -25321,7 +25342,10 @@ namespace ts {
}

if (computedNameType && !(computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique)) {
if (isTypeAssignableTo(computedNameType, stringNumberSymbolType)) {
if (isTypeAny(computedNameType)) {
Copy link
Member

Choose a reason for hiding this comment

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

From the comment here, it sounds like this mostly to cater to the "degenerate" case of Symbol.thingThatDoesNotExist which can happen in a loosely configured JavaScript project - is that the use-case you have in mind? And

That does loosen the behavior of this by quite a bit. I think I would be willing to go the opposite way and take a break on this behavior.

function getPropertyNameForKnownSymbolName(symbolName: string): __String {
const ctorType = getGlobalESSymbolConstructorSymbol(/*reportErrors*/ false);
const uniqueType = ctorType && getTypeOfPropertyOfType(getTypeOfSymbol(ctorType), escapeLeadingUnderscores(symbolName));
return uniqueType && isTypeUsableAsPropertyName(uniqueType) ? getPropertyNameFromType(uniqueType) : `__@${symbolName}` as __String;
Copy link
Member

Choose a reason for hiding this comment

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

Can you give a little more context on the significance? Are you saying this is handled well in the existing code, that other code needs to be careful, that there's a fundamental architectural issue, or that this now has a user-facing impact? (or all?)

@@ -269,8 +269,7 @@ namespace ts {
* any such locations
*/
export function isSimpleInlineableExpression(expression: Expression) {
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) ||
isWellKnownSymbolSyntactically(expression);
return !isIdentifier(expression) && isSimpleCopiableExpression(expression);
Copy link
Member

Choose a reason for hiding this comment

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

@rbuckton is probably the best judge of that.

Comment on lines 9 to -12
[Symbol.iterator]() { }
~~~~~~~~~~~~~~~
!!! error TS2471: A computed property name of the form 'Symbol.iterator' must be of type 'symbol'.
Copy link
Member

Choose a reason for hiding this comment

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

This used to be close to giving a good error. Do we have any strictness flag that disallows 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.

Nope? Pretty sure we allow computed named with completely arbitrary (key compatible) types and just infer an index signature.

Copy link
Member

@DanielRosenwasser DanielRosenwasser Feb 13, 2021

Choose a reason for hiding this comment

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

Yeah, but what do you want to do when you have a key of type any? I can't imagine why you'd want that behavior under --strict. But it sounds like a separate issue.

Copy link
Member Author

Choose a reason for hiding this comment

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

I mean, when Symbol isn't typed any, as in this test, we issue a lookup error...

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.

Some questions while I look at the rest of the tests

src/services/navigationBar.ts Outdated Show resolved Hide resolved
!!! error TS2495: Type 'StringIterator' is not an array type or a string type.
Copy link
Member

Choose a reason for hiding this comment

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

why did this change? Does the special-case code that generates this error need to be updated?

Copy link
Member Author

Choose a reason for hiding this comment

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

!!! error TS2585: 'Symbol' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the lib compiler option to es2015 or later.

The Symbol.iterator member no longer exists, because Symbol.iterator doesn't exist (this is an ES5 target project).

@@ -14,8 +14,8 @@ class C {
}

(new C)[Symbol.iterator](0) // Should error
Copy link
Member

Choose a reason for hiding this comment

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

This now gives an error type but doesn't show an error. That seems wrong to me, and seems similar to a complaint that @DanielRosenwasser had about an earlier test, but I can't tell if your explanation there applies to this test or not.

Here's what I see:

  1. Symbol.iterator exists, and has type symbol. Fine to use as a computed property name.
  2. That computed property name should, ideally, look up the property in the call expression and give the expected error.

Copy link
Member Author

@weswigham weswigham Feb 22, 2021

Choose a reason for hiding this comment

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

Symbol.iterator in this case comes from an anonymous type on a Symbol variable declaration, so the interop symbol -> unique symbol code path doesn't take effect. So the Symbol.iterator in the class body makes an index signature, and that index signature doesn't handle symbols because they never do, hence the failed lookup here. It's not a problem that arises in the real world, since in the real world, the lib defines the global Symbol type using the SymbolConstructor type which we apply interop logic to.

Copy link
Member

Choose a reason for hiding this comment

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

So....what is this test testing? Anything useful? Maybe it could be removed?

Copy link
Member Author

Choose a reason for hiding this comment

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

If/when we get proper symbol index signature support, its behavior should change, so I don't think it should be removed.

src/compiler/checker.ts Show resolved Hide resolved
src/compiler/checker.ts Show resolved Hide resolved
src/compiler/checker.ts Show resolved Hide resolved
src/compiler/checker.ts Show resolved Hide resolved
if (prop.escapedName === InternalSymbolName.Default) {
type = getLiteralType("default");
}
else {
const name = prop.valueDeclaration && getNameOfDeclaration(prop.valueDeclaration) as PropertyName;
type = name && getLiteralTypeFromPropertyName(name) || getLiteralType(symbolName(prop));
type = name && getLiteralTypeFromPropertyName(name) || (!isKnownSymbol(prop) ? getLiteralType(symbolName(prop)) : undefined);
Copy link
Member

Choose a reason for hiding this comment

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

It won't be confusing once well-known symbols are gone as a concept, right? Seems fine to me.

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; still need to figure out why es5for-oftypecheck10 stopped getting a special-cased error.

And maybe es5symbolproperty5 can be deleted? I couldn't tell.

@weswigham weswigham merged commit 87d10eb into microsoft:master Feb 22, 2021
sandersn pushed a commit to DefinitelyTyped/DefinitelyTyped that referenced this pull request Feb 24, 2021
kaznovac pushed a commit to kaznovac/DefinitelyTyped that referenced this pull request Mar 2, 2021
@coreh
Copy link

coreh commented Apr 14, 2021

Should Symbol.prototype also be affected by this change?

readonly prototype: Symbol;

Right now it's a Symbol and not a symbol, so it doesn't seem to get the unique symbol treatment.

Edit: Sorry! I just realized I got Symbol.species and Symbol.prototype mixed up. 😅 My question doesn't really make sense.

@ExE-Boss
Copy link
Contributor

ExE-Boss commented Apr 14, 2021

@coreh Symbol.prototype is the Symbol prototype object.

@coreh
Copy link

coreh commented Apr 14, 2021

Yeah... only after posting my comment I realized that I had gotten it mixed up with Symbol.species. Edited, thanks!

0b5vr added a commit to pixiv/three-vrm that referenced this pull request May 23, 2022
using `Object.freeze` on Quaternion makes the quaternion type imcompatible because of iterator

It seems to be a bug of TypeScript which is already fixed in the latest version
See: microsoft/TypeScript#42543
0b5vr added a commit to pixiv/three-vrm that referenced this pull request May 23, 2022
using `Object.freeze` on Quaternion makes the quaternion type imcompatible because of iterator

It seems to be a bug of TypeScript which is already fixed in the latest version
See: microsoft/TypeScript#42543
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Author: Team For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
7 participants