Skip to content

Add getEffectiveConstructSignatures #27561

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 8 commits into from
Oct 15, 2018

Conversation

sandersn
Copy link
Member

@sandersn sandersn commented Oct 4, 2018

  • getEffectiveConstructSignatures gets construct signatures from type, and call signatures from constructor functions if there are no construct signatures.
  • getEffectiveConstructSignatureReturnType gets the "JS Class type" for constructor functions, and the return type of signatures for all other declarations.

This is a first step toward making constructor functions have construct signatures instead of call signatures, which will also contribute to fixing instantiation of generic constructor functions, which is basically broken right now.

Note that the baselines improve but, because of the previously mentioned generic problem, are still not correct. Construct signatures for constructor functions and generic constructor functions turns out to be an intertwined problem.

Specifically, a non-generic class that inherits from a generic constructor function now finds a signature, but can't yet instantiate it, so it just returns any for now. However, the constructor signature itself is correctly instantiated in the ad-hoc code in resolveNewExpression, so in the following example, the arguments are correctly checked but the resulting instance type is any:

/** @template T
 * @param {T} val
 */
function B(val) {
  this.val = val
}
/** @extends {B<number>} */
class C extends B {
}
new C() // error
new C('hi') // error

I'll fix this in a separate PR, which will probably be much bigger.

* getEffectiveConstructSignatures gets construct signatures from type, and
  call signatures from constructor functions if there are no construct
  signatures.
* getEffectiveConstructSignatureReturnType gets the "JS Class type" for
  constructor functions, and the return type of signatures for all other
  declarations.

This is a first step toward making constructor functions have construct
signatures instead of call signatures, which will also contribute to
fixing instantiation of generic constructor functions, which is basically
broken right now.

Note that the baselines *improve* but, because of the previously
mentioned generic problem, are still not correct. Construct signatures
for constructor functions and generic constructor functions turns out to
be an intertwined problem.
And, for now, return anyType for generic constructor functions used as
base types. Don't give an incorrect error based on the function's return
type, which is usually void.
@sandersn sandersn requested a review from weswigham October 4, 2018 22:48
@weswigham
Copy link
Member

Rather than adding another pair of getEffectiveX, in this case, could we not just add the construct signatures to the type directly in resolveAnonymousTypeMembers? We should just need to amend

                if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method)) {
                    type.callSignatures = getSignaturesOfSymbol(symbol);
                }

with

type.constructSignatures = filter(type.callSignatures, sig => isJSConstructor(sig.declaration));

and getReturnTypeOfSignature around

let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper!) :
                    signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
                    getReturnTypeFromAnnotation(signature.declaration!) ||
                    (nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));

with

let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper!) :
                    signature.unionSignatures ? getUnionType(map(signature.unionSignatures, getReturnTypeOfSignature), UnionReduction.Subtype) :
                    isJSConstructor(signature.declaration) ? getJSClassType(getSymbolOfNode(signature.declaration!)) :
                    getReturnTypeFromAnnotation(signature.declaration!) ||
                    (nodeIsMissing((<FunctionLikeDeclaration>signature.declaration).body) ? anyType : getReturnTypeFromBody(<FunctionLikeDeclaration>signature.declaration));

no?

@sandersn
Copy link
Member Author

The latter should definitely work, although I decided to favour @return {Type} over @constructor as a marker of the type.

The former might have odd effects through out the system, but it is where I want to go, so I'll try it out.

@sandersn
Copy link
Member Author

After testing: the results keep the improvements without changing baselines too much, so I think this is a good solution. Thanks @weswigham !

It doesn't work, and shouldn't in the future, because it's a runtime
error.
@sandersn sandersn merged commit c184184 into master Oct 15, 2018
@sandersn sandersn deleted the add-getEffectiveConstructSignatures branch October 15, 2018 19:48
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.

2 participants