|
|
|
@@ -228,9 +228,9 @@ namespace ts {
|
|
|
|
|
isContextSensitive,
|
|
|
|
|
getFullyQualifiedName,
|
|
|
|
|
getResolvedSignature: (node, candidatesOutArray, agumentCount) =>
|
|
|
|
|
getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, /*isForSignatureHelp*/ false),
|
|
|
|
|
getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, CheckMode.Normal),
|
|
|
|
|
getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, agumentCount) =>
|
|
|
|
|
getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, /*isForSignatureHelp*/ true),
|
|
|
|
|
getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, CheckMode.IsForSignatureHelp),
|
|
|
|
|
getConstantValue: nodeIn => {
|
|
|
|
|
const node = getParseTreeNode(nodeIn, canHaveConstantValue);
|
|
|
|
|
return node ? getConstantValue(node) : undefined;
|
|
|
|
@@ -374,10 +374,10 @@ namespace ts {
|
|
|
|
|
getLocalTypeParametersOfClassOrInterfaceOrTypeAlias,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, isForSignatureHelp: boolean): Signature | undefined {
|
|
|
|
|
function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, checkMode: CheckMode): Signature | undefined {
|
|
|
|
|
const node = getParseTreeNode(nodeIn, isCallLikeExpression);
|
|
|
|
|
apparentArgumentCount = argumentCount;
|
|
|
|
|
const res = node ? getResolvedSignature(node, candidatesOutArray, isForSignatureHelp) : undefined;
|
|
|
|
|
const res = node ? getResolvedSignature(node, candidatesOutArray, checkMode) : undefined;
|
|
|
|
|
apparentArgumentCount = undefined;
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
@@ -688,10 +688,12 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const enum CheckMode {
|
|
|
|
|
Normal = 0, // Normal type checking
|
|
|
|
|
SkipContextSensitive = 1, // Skip context sensitive function expressions
|
|
|
|
|
Inferential = 2, // Inferential typing
|
|
|
|
|
Contextual = 3, // Normal type checking informed by a contextual type, therefore not cacheable
|
|
|
|
|
Normal = 0, // Normal type checking
|
|
|
|
|
Contextual = 1 << 0, // Explicitly assigned contextual type, therefore not cacheable
|
|
|
|
|
Inferential = 1 << 1, // Inferential typing
|
|
|
|
|
SkipContextSensitive = 1 << 2, // Skip context sensitive function expressions
|
|
|
|
|
SkipGenericFunctions = 1 << 3, // Skip single signature generic functions
|
|
|
|
|
IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const enum CallbackCheck {
|
|
|
|
@@ -3981,7 +3983,7 @@ namespace ts {
|
|
|
|
|
context.flags &= ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic
|
|
|
|
|
const shouldUseGeneratedName =
|
|
|
|
|
context.flags & NodeBuilderFlags.GenerateNamesForShadowedTypeParams &&
|
|
|
|
|
type.symbol.declarations[0] &&
|
|
|
|
|
type.symbol.declarations && type.symbol.declarations[0] &&
|
|
|
|
|
isTypeParameterDeclaration(type.symbol.declarations[0]) &&
|
|
|
|
|
typeParameterShadowsNameInScope(type, context);
|
|
|
|
|
const name = shouldUseGeneratedName
|
|
|
|
@@ -8373,9 +8375,23 @@ namespace ts {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean): Signature {
|
|
|
|
|
return getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript));
|
|
|
|
|
function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: ReadonlyArray<TypeParameter>): Signature {
|
|
|
|
|
const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript));
|
|
|
|
|
if (inferredTypeParameters) {
|
|
|
|
|
const returnSignature = getSingleCallSignature(getReturnTypeOfSignature(instantiatedSignature));
|
|
|
|
|
if (returnSignature) {
|
|
|
|
|
const newReturnSignature = cloneSignature(returnSignature);
|
|
|
|
|
newReturnSignature.typeParameters = inferredTypeParameters;
|
|
|
|
|
newReturnSignature.target = returnSignature.target;
|
|
|
|
|
newReturnSignature.mapper = returnSignature.mapper;
|
|
|
|
|
const newInstantiatedSignature = cloneSignature(instantiatedSignature);
|
|
|
|
|
newInstantiatedSignature.resolvedReturnType = getOrCreateTypeFromSignature(newReturnSignature);
|
|
|
|
|
return newInstantiatedSignature;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return instantiatedSignature;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getSignatureInstantiationWithoutFillingInTypeArguments(signature: Signature, typeArguments: ReadonlyArray<Type> | undefined): Signature {
|
|
|
|
|
const instantiations = signature.instantiations || (signature.instantiations = createMap<Signature>());
|
|
|
|
|
const id = getTypeListId(typeArguments);
|
|
|
|
@@ -8389,6 +8405,7 @@ namespace ts {
|
|
|
|
|
function createSignatureInstantiation(signature: Signature, typeArguments: ReadonlyArray<Type> | undefined): Signature {
|
|
|
|
|
return instantiateSignature(signature, createSignatureTypeMapper(signature, typeArguments), /*eraseTypeParameters*/ true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createSignatureTypeMapper(signature: Signature, typeArguments: ReadonlyArray<Type> | undefined): TypeMapper {
|
|
|
|
|
return createTypeMapper(signature.typeParameters!, typeArguments);
|
|
|
|
|
}
|
|
|
|
@@ -8790,7 +8807,7 @@ namespace ts {
|
|
|
|
|
|
|
|
|
|
function getTypeReferenceTypeWorker(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type | undefined {
|
|
|
|
|
if (symbol.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
|
|
|
|
|
if (symbol.valueDeclaration && isBinaryExpression(symbol.valueDeclaration.parent)) {
|
|
|
|
|
if (symbol.valueDeclaration && symbol.valueDeclaration.parent && isBinaryExpression(symbol.valueDeclaration.parent)) {
|
|
|
|
|
const jsdocType = getJSDocTypeReference(node, symbol, typeArguments);
|
|
|
|
|
if (jsdocType) {
|
|
|
|
|
return jsdocType;
|
|
|
|
@@ -20035,27 +20052,36 @@ namespace ts {
|
|
|
|
|
// Instantiate a generic signature in the context of a non-generic signature (section 3.8.5 in TypeScript spec)
|
|
|
|
|
function instantiateSignatureInContextOf(signature: Signature, contextualSignature: Signature, contextualMapper?: TypeMapper, compareTypes?: TypeComparer): Signature {
|
|
|
|
|
const context = createInferenceContext(signature.typeParameters!, signature, InferenceFlags.None, compareTypes);
|
|
|
|
|
const sourceSignature = contextualMapper ? instantiateSignature(contextualSignature, contextualMapper) : contextualSignature;
|
|
|
|
|
// We clone the contextualMapper to avoid fixing. For example, when the source signature is <T>(x: T) => T[] and
|
|
|
|
|
// the contextual signature is (...args: A) => B, we want to infer the element type of A's constraint (say 'any')
|
|
|
|
|
// for T but leave it possible to later infer '[any]' back to A.
|
|
|
|
|
const restType = getEffectiveRestType(contextualSignature);
|
|
|
|
|
const mapper = contextualMapper && restType && restType.flags & TypeFlags.TypeParameter ? cloneTypeMapper(contextualMapper) : contextualMapper;
|
|
|
|
|
const sourceSignature = mapper ? instantiateSignature(contextualSignature, mapper) : contextualSignature;
|
|
|
|
|
forEachMatchingParameterType(sourceSignature, signature, (source, target) => {
|
|
|
|
|
// Type parameters from outer context referenced by source type are fixed by instantiation of the source type
|
|
|
|
|
inferTypes(context.inferences, source, target);
|
|
|
|
|
});
|
|
|
|
|
if (!contextualMapper) {
|
|
|
|
|
inferTypes(context.inferences, getReturnTypeOfSignature(contextualSignature), getReturnTypeOfSignature(signature), InferencePriority.ReturnType);
|
|
|
|
|
const signaturePredicate = getTypePredicateOfSignature(signature);
|
|
|
|
|
const contextualPredicate = getTypePredicateOfSignature(sourceSignature);
|
|
|
|
|
if (signaturePredicate && contextualPredicate && signaturePredicate.kind === contextualPredicate.kind &&
|
|
|
|
|
(signaturePredicate.kind === TypePredicateKind.This || signaturePredicate.parameterIndex === (contextualPredicate as IdentifierTypePredicate).parameterIndex)) {
|
|
|
|
|
inferTypes(context.inferences, contextualPredicate.type, signaturePredicate.type, InferencePriority.ReturnType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return getSignatureInstantiation(signature, getInferredTypes(context), isInJSFile(contextualSignature.declaration));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, excludeArgument: ReadonlyArray<boolean> | undefined, context: InferenceContext): Type[] {
|
|
|
|
|
function inferJsxTypeArguments(node: JsxOpeningLikeElement, signature: Signature, checkMode: CheckMode, context: InferenceContext): Type[] {
|
|
|
|
|
const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node);
|
|
|
|
|
|
|
|
|
|
const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, excludeArgument && excludeArgument[0] !== undefined ? identityMapper : context);
|
|
|
|
|
const checkAttrType = checkExpressionWithContextualType(node.attributes, paramType, context, checkMode);
|
|
|
|
|
inferTypes(context.inferences, checkAttrType, paramType);
|
|
|
|
|
|
|
|
|
|
return getInferredTypes(context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray<Expression>, excludeArgument: ReadonlyArray<boolean> | undefined, context: InferenceContext): Type[] {
|
|
|
|
|
function inferTypeArguments(node: CallLikeExpression, signature: Signature, args: ReadonlyArray<Expression>, checkMode: CheckMode, context: InferenceContext): Type[] {
|
|
|
|
|
// Clear out all the inference results from the last time inferTypeArguments was called on this context
|
|
|
|
|
for (const inference of context.inferences) {
|
|
|
|
|
// As an optimization, we don't have to clear (and later recompute) inferred types
|
|
|
|
@@ -20068,7 +20094,7 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isJsxOpeningLikeElement(node)) {
|
|
|
|
|
return inferJsxTypeArguments(node, signature, excludeArgument, context);
|
|
|
|
|
return inferJsxTypeArguments(node, signature, checkMode, context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If a contextual type is available, infer from that type to the return type of the call expression. For
|
|
|
|
@@ -20115,10 +20141,7 @@ namespace ts {
|
|
|
|
|
const arg = args[i];
|
|
|
|
|
if (arg.kind !== SyntaxKind.OmittedExpression) {
|
|
|
|
|
const paramType = getTypeAtPosition(signature, i);
|
|
|
|
|
// For context sensitive arguments we pass the identityMapper, which is a signal to treat all
|
|
|
|
|
// context sensitive function expressions as wildcards
|
|
|
|
|
const mapper = excludeArgument && excludeArgument[i] !== undefined ? identityMapper : context;
|
|
|
|
|
const argType = checkExpressionWithContextualType(arg, paramType, mapper);
|
|
|
|
|
const argType = checkExpressionWithContextualType(arg, paramType, context, checkMode);
|
|
|
|
|
inferTypes(context.inferences, argType, paramType);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@@ -20146,7 +20169,7 @@ namespace ts {
|
|
|
|
|
// and the argument are ...x forms.
|
|
|
|
|
return arg.kind === SyntaxKind.SyntheticExpression ?
|
|
|
|
|
createArrayType((<SyntheticExpression>arg).type) :
|
|
|
|
|
getArrayifiedType(checkExpressionWithContextualType((<SpreadElement>arg).expression, restType, context));
|
|
|
|
|
getArrayifiedType(checkExpressionWithContextualType((<SpreadElement>arg).expression, restType, context, CheckMode.Normal));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
const contextualType = getIndexTypeOfType(restType, IndexKind.Number) || anyType;
|
|
|
|
@@ -20154,7 +20177,7 @@ namespace ts {
|
|
|
|
|
const types = [];
|
|
|
|
|
let spreadIndex = -1;
|
|
|
|
|
for (let i = index; i < argCount; i++) {
|
|
|
|
|
const argType = checkExpressionWithContextualType(args[i], contextualType, context);
|
|
|
|
|
const argType = checkExpressionWithContextualType(args[i], contextualType, context, CheckMode.Normal);
|
|
|
|
|
if (spreadIndex < 0 && isSpreadArgument(args[i])) {
|
|
|
|
|
spreadIndex = i - index;
|
|
|
|
|
}
|
|
|
|
@@ -20212,14 +20235,13 @@ namespace ts {
|
|
|
|
|
* @param node a JSX opening-like element we are trying to figure its call signature
|
|
|
|
|
* @param signature a candidate signature we are trying whether it is a call signature
|
|
|
|
|
* @param relation a relationship to check parameter and argument type
|
|
|
|
|
* @param excludeArgument
|
|
|
|
|
*/
|
|
|
|
|
function checkApplicableSignatureForJsxOpeningLikeElement(node: JsxOpeningLikeElement, signature: Signature, relation: Map<RelationComparisonResult>, excludeArgument: boolean[] | undefined, reportErrors: boolean) {
|
|
|
|
|
function checkApplicableSignatureForJsxOpeningLikeElement(node: JsxOpeningLikeElement, signature: Signature, relation: Map<RelationComparisonResult>, checkMode: CheckMode, reportErrors: boolean) {
|
|
|
|
|
// Stateless function components can have maximum of three arguments: "props", "context", and "updater".
|
|
|
|
|
// However "context" and "updater" are implicit and can't be specify by users. Only the first parameter, props,
|
|
|
|
|
// can be specified by users through attributes property.
|
|
|
|
|
const paramType = getEffectiveFirstArgumentForJsxSignature(signature, node);
|
|
|
|
|
const attributesType = checkExpressionWithContextualType(node.attributes, paramType, excludeArgument && excludeArgument[0] ? identityMapper : undefined);
|
|
|
|
|
const attributesType = checkExpressionWithContextualType(node.attributes, paramType, /*contextualMapper*/ undefined, checkMode);
|
|
|
|
|
return checkTypeRelatedToAndOptionallyElaborate(attributesType, paramType, relation, reportErrors ? node.tagName : undefined, node.attributes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -20228,10 +20250,10 @@ namespace ts {
|
|
|
|
|
args: ReadonlyArray<Expression>,
|
|
|
|
|
signature: Signature,
|
|
|
|
|
relation: Map<RelationComparisonResult>,
|
|
|
|
|
excludeArgument: boolean[] | undefined,
|
|
|
|
|
checkMode: CheckMode,
|
|
|
|
|
reportErrors: boolean) {
|
|
|
|
|
if (isJsxOpeningLikeElement(node)) {
|
|
|
|
|
return checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, excludeArgument, reportErrors);
|
|
|
|
|
return checkApplicableSignatureForJsxOpeningLikeElement(node, signature, relation, checkMode, reportErrors);
|
|
|
|
|
}
|
|
|
|
|
const thisType = getThisTypeOfSignature(signature);
|
|
|
|
|
if (thisType && thisType !== voidType && node.kind !== SyntaxKind.NewExpression) {
|
|
|
|
@@ -20253,11 +20275,11 @@ namespace ts {
|
|
|
|
|
const arg = args[i];
|
|
|
|
|
if (arg.kind !== SyntaxKind.OmittedExpression) {
|
|
|
|
|
const paramType = getTypeAtPosition(signature, i);
|
|
|
|
|
const argType = checkExpressionWithContextualType(arg, paramType, excludeArgument && excludeArgument[i] ? identityMapper : undefined);
|
|
|
|
|
// If one or more arguments are still excluded (as indicated by a non-null excludeArgument parameter),
|
|
|
|
|
const argType = checkExpressionWithContextualType(arg, paramType, /*contextualMapper*/ undefined, checkMode);
|
|
|
|
|
// If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive),
|
|
|
|
|
// we obtain the regular type of any object literal arguments because we may not have inferred complete
|
|
|
|
|
// parameter types yet and therefore excess property checks may yield false positives (see #17041).
|
|
|
|
|
const checkArgType = excludeArgument ? getRegularTypeOfObjectLiteral(argType) : argType;
|
|
|
|
|
const checkArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType;
|
|
|
|
|
if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? arg : undefined, arg, headMessage)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
@@ -20473,7 +20495,7 @@ namespace ts {
|
|
|
|
|
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, belowArgCount === -Infinity ? aboveArgCount : belowArgCount, argCount);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean, fallbackError?: DiagnosticMessage): Signature {
|
|
|
|
|
function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode, fallbackError?: DiagnosticMessage): Signature {
|
|
|
|
|
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
|
|
|
|
|
const isDecorator = node.kind === SyntaxKind.Decorator;
|
|
|
|
|
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
|
|
|
|
@@ -20515,7 +20537,7 @@ namespace ts {
|
|
|
|
|
// For a decorator, no arguments are susceptible to contextual typing due to the fact
|
|
|
|
|
// decorators are applied to a declaration by the emitter, and not to an expression.
|
|
|
|
|
const isSingleNonGenericCandidate = candidates.length === 1 && !candidates[0].typeParameters;
|
|
|
|
|
let excludeArgument = !isDecorator && !isSingleNonGenericCandidate ? getExcludeArgument(args) : undefined;
|
|
|
|
|
let argCheckMode = !isDecorator && !isSingleNonGenericCandidate && some(args, isContextSensitive) ? CheckMode.SkipContextSensitive : CheckMode.Normal;
|
|
|
|
|
|
|
|
|
|
// The following variables are captured and modified by calls to chooseOverload.
|
|
|
|
|
// If overload resolution or type argument inference fails, we want to report the
|
|
|
|
@@ -20546,7 +20568,7 @@ namespace ts {
|
|
|
|
|
// If we are in signature help, a trailing comma indicates that we intend to provide another argument,
|
|
|
|
|
// so we will only accept overloads with arity at least 1 higher than the current number of provided arguments.
|
|
|
|
|
const signatureHelpTrailingComma =
|
|
|
|
|
isForSignatureHelp && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma;
|
|
|
|
|
!!(checkMode & CheckMode.IsForSignatureHelp) && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma;
|
|
|
|
|
|
|
|
|
|
// Section 4.12.1:
|
|
|
|
|
// if the candidate list contains one or more signatures for which the type of each argument
|
|
|
|
@@ -20574,12 +20596,7 @@ namespace ts {
|
|
|
|
|
// skip the checkApplicableSignature check.
|
|
|
|
|
if (reportErrors) {
|
|
|
|
|
if (candidateForArgumentError) {
|
|
|
|
|
// excludeArgument is undefined, in this case also equivalent to [undefined, undefined, ...]
|
|
|
|
|
// The importance of excludeArgument is to prevent us from typing function expression parameters
|
|
|
|
|
// in arguments too early. If possible, we'd like to only type them once we know the correct
|
|
|
|
|
// overload. However, this matters for the case where the call is correct. When the call is
|
|
|
|
|
// an error, we don't need to exclude any arguments, although it would cause no harm to do so.
|
|
|
|
|
checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, /*excludeArgument*/ undefined, /*reportErrors*/ true);
|
|
|
|
|
checkApplicableSignature(node, args, candidateForArgumentError, assignableRelation, CheckMode.Normal, /*reportErrors*/ true);
|
|
|
|
|
}
|
|
|
|
|
else if (candidateForArgumentArityError) {
|
|
|
|
|
diagnostics.add(getArgumentArityError(node, [candidateForArgumentArityError], args));
|
|
|
|
@@ -20613,7 +20630,7 @@ namespace ts {
|
|
|
|
|
if (typeArguments || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
|
if (!checkApplicableSignature(node, args, candidate, relation, excludeArgument, /*reportErrors*/ false)) {
|
|
|
|
|
if (!checkApplicableSignature(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false)) {
|
|
|
|
|
candidateForArgumentError = candidate;
|
|
|
|
|
return undefined;
|
|
|
|
|
}
|
|
|
|
@@ -20640,9 +20657,10 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
|
|
|
|
|
typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext);
|
|
|
|
|
typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext);
|
|
|
|
|
argCheckMode |= inferenceContext.flags & InferenceFlags.SkippedGenericFunction ? CheckMode.SkipGenericFunctions : CheckMode.Normal;
|
|
|
|
|
}
|
|
|
|
|
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration));
|
|
|
|
|
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters);
|
|
|
|
|
// If the original signature has a generic rest type, instantiation may produce a
|
|
|
|
|
// signature with different arity and we need to perform another arity check.
|
|
|
|
|
if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) {
|
|
|
|
@@ -20653,21 +20671,21 @@ namespace ts {
|
|
|
|
|
else {
|
|
|
|
|
checkCandidate = candidate;
|
|
|
|
|
}
|
|
|
|
|
if (!checkApplicableSignature(node, args, checkCandidate, relation, excludeArgument, /*reportErrors*/ false)) {
|
|
|
|
|
if (!checkApplicableSignature(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false)) {
|
|
|
|
|
// Give preference to error candidates that have no rest parameters (as they are more specific)
|
|
|
|
|
if (!candidateForArgumentError || getEffectiveRestType(candidateForArgumentError) || !getEffectiveRestType(checkCandidate)) {
|
|
|
|
|
candidateForArgumentError = checkCandidate;
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
if (excludeArgument) {
|
|
|
|
|
if (argCheckMode) {
|
|
|
|
|
// If one or more context sensitive arguments were excluded, we start including
|
|
|
|
|
// them now (and keeping do so for any subsequent candidates) and perform a second
|
|
|
|
|
// round of type inference and applicability checking for this particular candidate.
|
|
|
|
|
excludeArgument = undefined;
|
|
|
|
|
argCheckMode = CheckMode.Normal;
|
|
|
|
|
if (inferenceContext) {
|
|
|
|
|
const typeArgumentTypes = inferTypeArguments(node, candidate, args, excludeArgument, inferenceContext);
|
|
|
|
|
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration));
|
|
|
|
|
const typeArgumentTypes = inferTypeArguments(node, candidate, args, argCheckMode, inferenceContext);
|
|
|
|
|
checkCandidate = getSignatureInstantiation(candidate, typeArgumentTypes, isInJSFile(candidate.declaration), inferenceContext && inferenceContext.inferredTypeParameters);
|
|
|
|
|
// If the original signature has a generic rest type, instantiation may produce a
|
|
|
|
|
// signature with different arity and we need to perform another arity check.
|
|
|
|
|
if (getNonArrayRestType(candidate) && !hasCorrectArity(node, args, checkCandidate, signatureHelpTrailingComma)) {
|
|
|
|
@@ -20675,7 +20693,7 @@ namespace ts {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!checkApplicableSignature(node, args, checkCandidate, relation, excludeArgument, /*reportErrors*/ false)) {
|
|
|
|
|
if (!checkApplicableSignature(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false)) {
|
|
|
|
|
// Give preference to error candidates that have no rest parameters (as they are more specific)
|
|
|
|
|
if (!candidateForArgumentError || getEffectiveRestType(candidateForArgumentError) || !getEffectiveRestType(checkCandidate)) {
|
|
|
|
|
candidateForArgumentError = checkCandidate;
|
|
|
|
@@ -20691,21 +20709,6 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getExcludeArgument(args: ReadonlyArray<Expression>): boolean[] | undefined {
|
|
|
|
|
let excludeArgument: boolean[] | undefined;
|
|
|
|
|
// We do not need to call `getEffectiveArgumentCount` here as it only
|
|
|
|
|
// applies when calculating the number of arguments for a decorator.
|
|
|
|
|
for (let i = 0; i < args.length; i++) {
|
|
|
|
|
if (isContextSensitive(args[i])) {
|
|
|
|
|
if (!excludeArgument) {
|
|
|
|
|
excludeArgument = new Array(args.length);
|
|
|
|
|
}
|
|
|
|
|
excludeArgument[i] = true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return excludeArgument;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// No signature was applicable. We have already reported the errors for the invalid signature.
|
|
|
|
|
// If this is a type resolution session, e.g. Language Service, try to get better information than anySignature.
|
|
|
|
|
function getCandidateForOverloadFailure(
|
|
|
|
@@ -20805,7 +20808,7 @@ namespace ts {
|
|
|
|
|
|
|
|
|
|
function inferSignatureInstantiationForOverloadFailure(node: CallLikeExpression, typeParameters: ReadonlyArray<TypeParameter>, candidate: Signature, args: ReadonlyArray<Expression>): Signature {
|
|
|
|
|
const inferenceContext = createInferenceContext(typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
|
|
|
|
|
const typeArgumentTypes = inferTypeArguments(node, candidate, args, getExcludeArgument(args), inferenceContext);
|
|
|
|
|
const typeArgumentTypes = inferTypeArguments(node, candidate, args, CheckMode.SkipContextSensitive | CheckMode.SkipGenericFunctions, inferenceContext);
|
|
|
|
|
return createSignatureInstantiation(candidate, typeArgumentTypes);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -20828,7 +20831,7 @@ namespace ts {
|
|
|
|
|
return maxParamsIndex;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
|
|
|
|
|
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
|
|
|
|
|
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
|
|
|
|
const superType = checkSuperExpression(node.expression);
|
|
|
|
|
if (isTypeAny(superType)) {
|
|
|
|
@@ -20843,7 +20846,7 @@ namespace ts {
|
|
|
|
|
const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
|
|
|
|
|
if (baseTypeNode) {
|
|
|
|
|
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
|
|
|
|
|
return resolveCall(node, baseConstructors, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveCall(node, baseConstructors, candidatesOutArray, checkMode);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return resolveUntypedCall(node);
|
|
|
|
@@ -20903,12 +20906,32 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
// When a call to a generic function is an argument to an outer call to a generic function for which
|
|
|
|
|
// inference is in process, we have a choice to make. If the inner call relies on inferences made from
|
|
|
|
|
// its contextual type to its return type, deferring the inner call processing allows the best possible
|
|
|
|
|
// contextual type to accumulate. But if the outer call relies on inferences made from the return type of
|
|
|
|
|
// the inner call, the inner call should be processed early. There's no sure way to know which choice is
|
|
|
|
|
// right (only a full unification algorithm can determine that), so we resort to the following heuristic:
|
|
|
|
|
// If no type arguments are specified in the inner call and at least one call signature is generic and
|
|
|
|
|
// returns a function type, we choose to defer processing. This narrowly permits function composition
|
|
|
|
|
// operators to flow inferences through return types, but otherwise processes calls right away. We
|
|
|
|
|
// use the resolvingSignature singleton to indicate that we deferred processing. This result will be
|
|
|
|
|
// propagated out and eventually turned into silentNeverType (a type that is assignable to anything and
|
|
|
|
|
// from which we never make inferences).
|
|
|
|
|
if (checkMode & CheckMode.SkipGenericFunctions && !node.typeArguments && callSignatures.some(isGenericFunctionReturningFunction)) {
|
|
|
|
|
skippedGenericFunction(node, checkMode);
|
|
|
|
|
return resolvingSignature;
|
|
|
|
|
}
|
|
|
|
|
// If the function is explicitly marked with `@class`, then it must be constructed.
|
|
|
|
|
if (callSignatures.some(sig => isInJSFile(sig.declaration) && !!getJSDocClassTag(sig.declaration!))) {
|
|
|
|
|
error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType));
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveCall(node, callSignatures, candidatesOutArray, checkMode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function isGenericFunctionReturningFunction(signature: Signature) {
|
|
|
|
|
return !!(signature.typeParameters && isFunctionType(getReturnTypeOfSignature(signature)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -20922,7 +20945,7 @@ namespace ts {
|
|
|
|
|
!numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & (TypeFlags.Union | TypeFlags.Never)) && isTypeAssignableTo(funcType, globalFunctionType);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
|
|
|
|
|
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
|
|
|
|
|
if (node.arguments && languageVersion < ScriptTarget.ES5) {
|
|
|
|
|
const spreadIndex = getSpreadArgumentIndex(node.arguments);
|
|
|
|
|
if (spreadIndex >= 0) {
|
|
|
|
@@ -20975,7 +20998,7 @@ namespace ts {
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resolveCall(node, constructSignatures, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveCall(node, constructSignatures, candidatesOutArray, checkMode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// If expressionType's apparent type is an object type with no construct signatures but
|
|
|
|
@@ -20984,7 +21007,7 @@ namespace ts {
|
|
|
|
|
// operation is Any. It is an error to have a Void this type.
|
|
|
|
|
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
|
|
|
|
|
if (callSignatures.length) {
|
|
|
|
|
const signature = resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
const signature = resolveCall(node, callSignatures, candidatesOutArray, checkMode);
|
|
|
|
|
if (!noImplicitAny) {
|
|
|
|
|
if (signature.declaration && !isJSConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
|
|
|
|
|
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
|
|
|
|
@@ -21094,7 +21117,7 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
|
|
|
|
|
function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
|
|
|
|
|
const tagType = checkExpression(node.tag);
|
|
|
|
|
const apparentType = getApparentType(tagType);
|
|
|
|
|
|
|
|
|
@@ -21115,7 +21138,7 @@ namespace ts {
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveCall(node, callSignatures, candidatesOutArray, checkMode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -21146,7 +21169,7 @@ namespace ts {
|
|
|
|
|
/**
|
|
|
|
|
* Resolves a decorator as if it were a call expression.
|
|
|
|
|
*/
|
|
|
|
|
function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
|
|
|
|
|
function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
|
|
|
|
|
const funcType = checkExpression(node.expression);
|
|
|
|
|
const apparentType = getApparentType(funcType);
|
|
|
|
|
if (apparentType === errorType) {
|
|
|
|
@@ -21175,7 +21198,7 @@ namespace ts {
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp, headMessage);
|
|
|
|
|
return resolveCall(node, callSignatures, candidatesOutArray, checkMode, headMessage);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function createSignatureForJSXIntrinsic(node: JsxOpeningLikeElement, result: Type): Signature {
|
|
|
|
@@ -21204,11 +21227,11 @@ namespace ts {
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
|
|
|
|
|
function resolveJsxOpeningLikeElement(node: JsxOpeningLikeElement, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
|
|
|
|
|
if (isJsxIntrinsicIdentifier(node.tagName)) {
|
|
|
|
|
const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node);
|
|
|
|
|
const fakeSignature = createSignatureForJSXIntrinsic(node, result);
|
|
|
|
|
checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined), result, node.tagName, node.attributes);
|
|
|
|
|
checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes);
|
|
|
|
|
return fakeSignature;
|
|
|
|
|
}
|
|
|
|
|
const exprTypes = checkExpression(node.tagName);
|
|
|
|
@@ -21228,7 +21251,7 @@ namespace ts {
|
|
|
|
|
return resolveErrorCall(node);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return resolveCall(node, signatures, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveCall(node, signatures, candidatesOutArray, checkMode);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
@@ -21243,19 +21266,19 @@ namespace ts {
|
|
|
|
|
signature.parameters.length < getDecoratorArgumentCount(decorator, signature));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
|
|
|
|
|
function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, checkMode: CheckMode): Signature {
|
|
|
|
|
switch (node.kind) {
|
|
|
|
|
case SyntaxKind.CallExpression:
|
|
|
|
|
return resolveCallExpression(node, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveCallExpression(node, candidatesOutArray, checkMode);
|
|
|
|
|
case SyntaxKind.NewExpression:
|
|
|
|
|
return resolveNewExpression(node, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveNewExpression(node, candidatesOutArray, checkMode);
|
|
|
|
|
case SyntaxKind.TaggedTemplateExpression:
|
|
|
|
|
return resolveTaggedTemplateExpression(node, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveTaggedTemplateExpression(node, candidatesOutArray, checkMode);
|
|
|
|
|
case SyntaxKind.Decorator:
|
|
|
|
|
return resolveDecorator(node, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveDecorator(node, candidatesOutArray, checkMode);
|
|
|
|
|
case SyntaxKind.JsxOpeningElement:
|
|
|
|
|
case SyntaxKind.JsxSelfClosingElement:
|
|
|
|
|
return resolveJsxOpeningLikeElement(node, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
return resolveJsxOpeningLikeElement(node, candidatesOutArray, checkMode);
|
|
|
|
|
}
|
|
|
|
|
throw Debug.assertNever(node, "Branch in 'resolveSignature' should be unreachable.");
|
|
|
|
|
}
|
|
|
|
@@ -21267,7 +21290,7 @@ namespace ts {
|
|
|
|
|
* the function will fill it up with appropriate candidate signatures
|
|
|
|
|
* @return a signature of the call-like expression or undefined if one can't be found
|
|
|
|
|
*/
|
|
|
|
|
function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, isForSignatureHelp = false): Signature {
|
|
|
|
|
function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, checkMode?: CheckMode): Signature {
|
|
|
|
|
const links = getNodeLinks(node);
|
|
|
|
|
// If getResolvedSignature has already been called, we will have cached the resolvedSignature.
|
|
|
|
|
// However, it is possible that either candidatesOutArray was not passed in the first time,
|
|
|
|
@@ -21278,11 +21301,15 @@ namespace ts {
|
|
|
|
|
return cached;
|
|
|
|
|
}
|
|
|
|
|
links.resolvedSignature = resolvingSignature;
|
|
|
|
|
const result = resolveSignature(node, candidatesOutArray, isForSignatureHelp);
|
|
|
|
|
// If signature resolution originated in control flow type analysis (for example to compute the
|
|
|
|
|
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
|
|
|
|
|
// types from the control flow analysis.
|
|
|
|
|
links.resolvedSignature = flowLoopStart === flowLoopCount ? result : cached;
|
|
|
|
|
const result = resolveSignature(node, candidatesOutArray, checkMode || CheckMode.Normal);
|
|
|
|
|
// When CheckMode.SkipGenericFunctions is set we use resolvingSignature to indicate that call
|
|
|
|
|
// resolution should be deferred.
|
|
|
|
|
if (result !== resolvingSignature) {
|
|
|
|
|
// If signature resolution originated in control flow type analysis (for example to compute the
|
|
|
|
|
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
|
|
|
|
|
// types from the control flow analysis.
|
|
|
|
|
links.resolvedSignature = flowLoopStart === flowLoopCount ? result : cached;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -21366,10 +21393,15 @@ namespace ts {
|
|
|
|
|
* @param node The call/new expression to be checked.
|
|
|
|
|
* @returns On success, the expression's signature's return type. On failure, anyType.
|
|
|
|
|
*/
|
|
|
|
|
function checkCallExpression(node: CallExpression | NewExpression): Type {
|
|
|
|
|
function checkCallExpression(node: CallExpression | NewExpression, checkMode?: CheckMode): Type {
|
|
|
|
|
if (!checkGrammarTypeArguments(node, node.typeArguments)) checkGrammarArguments(node.arguments);
|
|
|
|
|
|
|
|
|
|
const signature = getResolvedSignature(node);
|
|
|
|
|
const signature = getResolvedSignature(node, /*candidatesOutArray*/ undefined, checkMode);
|
|
|
|
|
if (signature === resolvingSignature) {
|
|
|
|
|
// CheckMode.SkipGenericFunctions is enabled and this is a call to a generic function that
|
|
|
|
|
// returns a function type. We defer checking and return anyFunctionType.
|
|
|
|
|
return silentNeverType;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (node.expression.kind === SyntaxKind.SuperKeyword) {
|
|
|
|
|
return voidType;
|
|
|
|
@@ -21870,7 +21902,7 @@ namespace ts {
|
|
|
|
|
const functionFlags = getFunctionFlags(func);
|
|
|
|
|
let type: Type;
|
|
|
|
|
if (func.body.kind !== SyntaxKind.Block) {
|
|
|
|
|
type = checkExpressionCached(func.body, checkMode);
|
|
|
|
|
type = checkExpressionCached(func.body, checkMode && checkMode & ~CheckMode.SkipGenericFunctions);
|
|
|
|
|
if (functionFlags & FunctionFlags.Async) {
|
|
|
|
|
// From within an async function you can return either a non-promise value or a promise. Any
|
|
|
|
|
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
|
|
|
|
@@ -22060,7 +22092,7 @@ namespace ts {
|
|
|
|
|
forEachReturnStatement(<Block>func.body, returnStatement => {
|
|
|
|
|
const expr = returnStatement.expression;
|
|
|
|
|
if (expr) {
|
|
|
|
|
let type = checkExpressionCached(expr, checkMode);
|
|
|
|
|
let type = checkExpressionCached(expr, checkMode && checkMode & ~CheckMode.SkipGenericFunctions);
|
|
|
|
|
if (functionFlags & FunctionFlags.Async) {
|
|
|
|
|
// From within an async function you can return either a non-promise value or a promise. Any
|
|
|
|
|
// Promise/A+ compatible implementation will always assimilate any foreign promise, so the
|
|
|
|
@@ -22160,7 +22192,7 @@ namespace ts {
|
|
|
|
|
checkNodeDeferred(node);
|
|
|
|
|
|
|
|
|
|
// The identityMapper object is used to indicate that function expressions are wildcards
|
|
|
|
|
if (checkMode === CheckMode.SkipContextSensitive && isContextSensitive(node)) {
|
|
|
|
|
if (checkMode && checkMode & CheckMode.SkipContextSensitive && isContextSensitive(node)) {
|
|
|
|
|
// Skip parameters, return signature with return type that retains noncontextual parts so inferences can still be drawn in an early stage
|
|
|
|
|
if (!getEffectiveReturnTypeNode(node) && hasContextSensitiveReturnExpression(node)) {
|
|
|
|
|
const links = getNodeLinks(node);
|
|
|
|
@@ -22200,7 +22232,7 @@ namespace ts {
|
|
|
|
|
const signature = getSignaturesOfType(type, SignatureKind.Call)[0];
|
|
|
|
|
if (isContextSensitive(node)) {
|
|
|
|
|
const contextualMapper = getContextualMapper(node);
|
|
|
|
|
if (checkMode === CheckMode.Inferential) {
|
|
|
|
|
if (checkMode && checkMode & CheckMode.Inferential) {
|
|
|
|
|
inferFromAnnotatedParameters(signature, contextualSignature, contextualMapper);
|
|
|
|
|
}
|
|
|
|
|
const instantiatedContextualSignature = contextualMapper === identityMapper ?
|
|
|
|
@@ -23211,15 +23243,13 @@ namespace ts {
|
|
|
|
|
return node;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper: TypeMapper | undefined): Type {
|
|
|
|
|
function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper: TypeMapper | undefined, checkMode: CheckMode): Type {
|
|
|
|
|
const context = getContextNode(node);
|
|
|
|
|
const saveContextualType = context.contextualType;
|
|
|
|
|
const saveContextualMapper = context.contextualMapper;
|
|
|
|
|
context.contextualType = contextualType;
|
|
|
|
|
context.contextualMapper = contextualMapper;
|
|
|
|
|
const checkMode = contextualMapper === identityMapper ? CheckMode.SkipContextSensitive :
|
|
|
|
|
contextualMapper ? CheckMode.Inferential : CheckMode.Contextual;
|
|
|
|
|
const type = checkExpression(node, checkMode);
|
|
|
|
|
const type = checkExpression(node, checkMode | CheckMode.Contextual | (contextualMapper ? CheckMode.Inferential : 0));
|
|
|
|
|
// We strip literal freshness when an appropriate contextual type is present such that contextually typed
|
|
|
|
|
// literals always preserve their literal types (otherwise they might widen during type inference). An alternative
|
|
|
|
|
// here would be to not mark contextually typed literals as fresh in the first place.
|
|
|
|
@@ -23233,7 +23263,7 @@ namespace ts {
|
|
|
|
|
function checkExpressionCached(node: Expression, checkMode?: CheckMode): Type {
|
|
|
|
|
const links = getNodeLinks(node);
|
|
|
|
|
if (!links.resolvedType) {
|
|
|
|
|
if (checkMode) {
|
|
|
|
|
if (checkMode && checkMode !== CheckMode.Normal) {
|
|
|
|
|
return checkExpression(node, checkMode);
|
|
|
|
|
}
|
|
|
|
|
// When computing a type that we're going to cache, we need to ignore any ongoing control flow
|
|
|
|
@@ -23341,22 +23371,127 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName, type: Type, checkMode?: CheckMode) {
|
|
|
|
|
if (checkMode === CheckMode.Inferential) {
|
|
|
|
|
if (checkMode && checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions)) {
|
|
|
|
|
const signature = getSingleCallSignature(type);
|
|
|
|
|
if (signature && signature.typeParameters) {
|
|
|
|
|
if (checkMode & CheckMode.SkipGenericFunctions) {
|
|
|
|
|
skippedGenericFunction(node, checkMode);
|
|
|
|
|
return anyFunctionType;
|
|
|
|
|
}
|
|
|
|
|
const contextualType = getApparentTypeOfContextualType(<Expression>node);
|
|
|
|
|
if (contextualType) {
|
|
|
|
|
const contextualSignature = getSingleCallSignature(getNonNullableType(contextualType));
|
|
|
|
|
if (contextualSignature && !contextualSignature.typeParameters) {
|
|
|
|
|
return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, getContextualMapper(node)));
|
|
|
|
|
const context = <InferenceContext>getContextualMapper(node);
|
|
|
|
|
// We have an expression that is an argument of a generic function for which we are performing
|
|
|
|
|
// type argument inference. The expression is of a function type with a single generic call
|
|
|
|
|
// signature and a contextual function type with a single non-generic call signature. Now check
|
|
|
|
|
// if the outer function returns a function type with a single non-generic call signature and
|
|
|
|
|
// if some of the outer function type parameters have no inferences so far. If so, we can
|
|
|
|
|
// potentially add inferred type parameters to the outer function return type.
|
|
|
|
|
const returnSignature = context.signature && getSingleCallSignature(getReturnTypeOfSignature(context.signature));
|
|
|
|
|
if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) {
|
|
|
|
|
// Instantiate the expression type with its own type parameters as type arguments. This
|
|
|
|
|
// ensures that the type parameters are not erased to type any during type inference such
|
|
|
|
|
// that they can be inferred as actual types.
|
|
|
|
|
const uniqueTypeParameters = getUniqueTypeParameters(context, signature.typeParameters);
|
|
|
|
|
const strippedType = getOrCreateTypeFromSignature(getSignatureInstantiationWithoutFillingInTypeArguments(signature, uniqueTypeParameters));
|
|
|
|
|
// Infer from the stripped expression type to the contextual type starting with an empty
|
|
|
|
|
// set of inference candidates.
|
|
|
|
|
const inferences = map(context.typeParameters, createInferenceInfo);
|
|
|
|
|
inferTypes(inferences, strippedType, contextualType);
|
|
|
|
|
// If we produced some inference candidates and if the type parameters for which we produced
|
|
|
|
|
// candidates do not already have existing inferences, we adopt the new inference candidates and
|
|
|
|
|
// add the type parameters of the expression type to the set of inferred type parameters for
|
|
|
|
|
// the outer function return type.
|
|
|
|
|
if (some(inferences, hasInferenceCandidates) && !hasOverlappingInferences(context.inferences, inferences)) {
|
|
|
|
|
mergeInferences(context.inferences, inferences);
|
|
|
|
|
context.inferredTypeParameters = concatenate(context.inferredTypeParameters, uniqueTypeParameters);
|
|
|
|
|
return strippedType;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, context));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return type;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function skippedGenericFunction(node: Node, checkMode: CheckMode) {
|
|
|
|
|
if (checkMode & CheckMode.Inferential) {
|
|
|
|
|
// We have skipped a generic function during inferential typing. Obtain the inference context and
|
|
|
|
|
// indicate this has occurred such that we know a second pass of inference is be needed.
|
|
|
|
|
const context = <InferenceContext>getContextualMapper(node);
|
|
|
|
|
context.flags |= InferenceFlags.SkippedGenericFunction;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasInferenceCandidates(info: InferenceInfo) {
|
|
|
|
|
return !!(info.candidates || info.contraCandidates);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasOverlappingInferences(a: InferenceInfo[], b: InferenceInfo[]) {
|
|
|
|
|
for (let i = 0; i < a.length; i++) {
|
|
|
|
|
if (hasInferenceCandidates(a[i]) && hasInferenceCandidates(b[i])) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function mergeInferences(target: InferenceInfo[], source: InferenceInfo[]) {
|
|
|
|
|
for (let i = 0; i < target.length; i++) {
|
|
|
|
|
if (!hasInferenceCandidates(target[i]) && hasInferenceCandidates(source[i])) {
|
|
|
|
|
target[i] = source[i];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getUniqueTypeParameters(context: InferenceContext, typeParameters: ReadonlyArray<TypeParameter>): ReadonlyArray<TypeParameter> {
|
|
|
|
|
const result: TypeParameter[] = [];
|
|
|
|
|
let oldTypeParameters: TypeParameter[] | undefined;
|
|
|
|
|
let newTypeParameters: TypeParameter[] | undefined;
|
|
|
|
|
for (const tp of typeParameters) {
|
|
|
|
|
const name = tp.symbol.escapedName;
|
|
|
|
|
if (hasTypeParameterByName(context.inferredTypeParameters, name) || hasTypeParameterByName(result, name)) {
|
|
|
|
|
const newName = getUniqueTypeParameterName(concatenate(context.inferredTypeParameters, result), name);
|
|
|
|
|
const symbol = createSymbol(SymbolFlags.TypeParameter, newName);
|
|
|
|
|
const newTypeParameter = createTypeParameter(symbol);
|
|
|
|
|
newTypeParameter.target = tp;
|
|
|
|
|
oldTypeParameters = append(oldTypeParameters, tp);
|
|
|
|
|
newTypeParameters = append(newTypeParameters, newTypeParameter);
|
|
|
|
|
result.push(newTypeParameter);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
result.push(tp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (newTypeParameters) {
|
|
|
|
|
const mapper = createTypeMapper(oldTypeParameters!, newTypeParameters);
|
|
|
|
|
for (const tp of newTypeParameters) {
|
|
|
|
|
tp.mapper = mapper;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function hasTypeParameterByName(typeParameters: ReadonlyArray<TypeParameter> | undefined, name: __String) {
|
|
|
|
|
return some(typeParameters, tp => tp.symbol.escapedName === name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getUniqueTypeParameterName(typeParameters: ReadonlyArray<TypeParameter>, baseName: __String) {
|
|
|
|
|
let len = (<string>baseName).length;
|
|
|
|
|
while (len > 1 && (<string>baseName).charCodeAt(len - 1) >= CharacterCodes._0 && (<string>baseName).charCodeAt(len - 1) <= CharacterCodes._9) len--;
|
|
|
|
|
const s = (<string>baseName).slice(0, len);
|
|
|
|
|
for (let index = 1; true; index++) {
|
|
|
|
|
const augmentedName = <__String>(s + index);
|
|
|
|
|
if (!hasTypeParameterByName(typeParameters, augmentedName)) {
|
|
|
|
|
return augmentedName;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the type of an expression. Unlike checkExpression, this function is simply concerned
|
|
|
|
|
* with computing the type and may not fully check all contained sub-expressions for errors.
|
|
|
|
@@ -23496,7 +23631,7 @@ namespace ts {
|
|
|
|
|
}
|
|
|
|
|
/* falls through */
|
|
|
|
|
case SyntaxKind.NewExpression:
|
|
|
|
|
return checkCallExpression(<CallExpression>node);
|
|
|
|
|
return checkCallExpression(<CallExpression>node, checkMode);
|
|
|
|
|
case SyntaxKind.TaggedTemplateExpression:
|
|
|
|
|
return checkTaggedTemplateExpression(<TaggedTemplateExpression>node);
|
|
|
|
|
case SyntaxKind.ParenthesizedExpression:
|
|
|
|
|