Skip to content

Instantiate this when used only in type parameter constraints #19655

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
merged 4 commits into from
Nov 15, 2017

Conversation

sandersn
Copy link
Member

@sandersn sandersn commented Nov 1, 2017

Check function type parameters for this references. Previously, when checking for this references, the compiler did not check type parameters. This caused it to miss some instantiations that were necessary.

Also some cleanup:

  1. Rename isIndependent* to is*FreeOfThisReference. 'Independent' was a one-off concept that was unique to Typescript (and isn't referenced in the spec), so I think the new name is friendlier to new readers.
  2. Use Array.every whenever possible, since Typescript added a dependency on ES5 since the code was first written.
  3. Switch to JSDoc so explanations show up nicely in editors.

Fixes #16930

Previously, when checking for this references, the compiler did not
check type parameters. This caused it to miss some instantiations that
were necessary.

Also some cleanup:
1. Rename isIndependent* to is*FreeOfThisReference. 'Independent' was a
one-off concept that was unique to Typescript (and isn't referenced in
the spec), so I think the new name is friendlier to new readers.
2. Use `Array.every` whenever possible, since Typescript added a
dependency on ES5 since the code was first written.
3. Switch to JSDoc so that it shows up nicely in editors.
Make sure that `this` gets instantiated when it's used as a constraint
of a type parameter, and nowhere else in a signature.
@sandersn sandersn requested review from ahejlsberg and a user November 1, 2017 16:21

class Test extends Base {
m() {
this.check(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.

previously the second this reference was not assignable to prop: TProp.

* to "this" in its body, if all base types are interfaces,
* and if none of the base interfaces have a "this" type.
*/
function isInterfaceFreeOfThisReference(symbol: Symbol): boolean {
Copy link
Member

Choose a reason for hiding this comment

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

isThislessInterface?

Copy link

@ghost ghost Nov 13, 2017

Choose a reason for hiding this comment

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

Or name it isInterfaceWithThisReference and don't negate it.

function isInterfaceWithThisReference(symbol: Symbol): boolean {
    return some(symbol.declarations, declaration =>
        isInterfaceDeclaration(declaration) && (
            !!(declaration.flags & NodeFlags.ContainsThis)
            || some(getInterfaceBaseTypeNodes(declaration), baseTypeReferencesThis)));
}
function baseTypeReferencesThis({ expression }: ExpressionWithTypeArguments): boolean {
    if (!isEntityNameExpression(expression)) {
        return false;
    }
    const baseSymbol = resolveEntityName(expression, SymbolFlags.Type, /*ignoreErrors*/ true);
    return !baseSymbol || !(baseSymbol.flags & SymbolFlags.Interface) || !!getDeclaredTypeOfClassOrInterface(baseSymbol).thisType;
}

* literal type, an array with an element type that is free of this references, or a type reference that is
* free of this references.
*/
function isTypeFreeOfThisReference(node: TypeNode): boolean {
Copy link

@ghost ghost Nov 13, 2017

Choose a reason for hiding this comment

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

I would negate all of these functions to make them xHasThisReference.

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'll try that in a separate PR. I'm afraid that if I introduce any bugs with further refactoring they'll only show up as performance regressions, and I want to isolate that from any required performance regressions that result from the additional instantiations here.

case SyntaxKind.TypeReference:
return isIndependentTypeReference(<TypeReferenceNode>node);
return isTypeReferenceFreeOfThisReference(<TypeReferenceNode>node);
Copy link

Choose a reason for hiding this comment

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

return some((node as TypeReferenceNode).typeArguments, typeHasThisReference);, doesn't really deserve its own function.

case SyntaxKind.TypeReference:
return isIndependentTypeReference(<TypeReferenceNode>node);
return isTypeReferenceFreeOfThisReference(<TypeReferenceNode>node);
}
return false;
Copy link

Choose a reason for hiding this comment

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

So all other types are presumed guilty? Could you try for a complete switch and Debug.fail() in the default case?

Copy link
Member Author

@sandersn sandersn Nov 14, 2017

Choose a reason for hiding this comment

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

In a word, yes. I'm doing Definitely Typed duty this week, so I ran tests on the assert until they all passed. I had to add all the type kinds except for MappedType.

There may be some efficiency we could pick up here by inspecting more types — union and intersection especially — but I think it's fine to have the default case fall through to a return false.

@sandersn sandersn merged commit 8a7b844 into master Nov 15, 2017
@ghost ghost deleted the instantiate-this-in-type-parameter-constraints branch November 15, 2017 15:06
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
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.

2 participants