mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-06 02:33:53 -06:00
Introduce ContextFlags to propagate origin of request for contextual type
This commit is contained in:
parent
7ec7f02ec3
commit
3d0e2f5f45
@ -701,6 +701,11 @@ namespace ts {
|
||||
IsForSignatureHelp = 1 << 4, // Call resolution for purposes of signature help
|
||||
}
|
||||
|
||||
const enum ContextFlags {
|
||||
None = 0,
|
||||
Signature = 1 << 0, // Obtaining contextual signature
|
||||
}
|
||||
|
||||
const enum CallbackCheck {
|
||||
None,
|
||||
Bivariant,
|
||||
@ -17751,7 +17756,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getContextualTypeForBinaryOperand(node: Expression): Type | undefined {
|
||||
function getContextualTypeForBinaryOperand(node: Expression, contextFlags?: ContextFlags): Type | undefined {
|
||||
const binaryExpression = <BinaryExpression>node.parent;
|
||||
const { left, operatorToken, right } = binaryExpression;
|
||||
switch (operatorToken.kind) {
|
||||
@ -17768,12 +17773,12 @@ namespace ts {
|
||||
// When an || expression has a contextual type, the operands are contextually typed by that type. When an ||
|
||||
// expression has no contextual type, the right operand is contextually typed by the type of the left operand,
|
||||
// except for the special case of Javascript declarations of the form `namespace.prop = namespace.prop || {}`
|
||||
const type = getContextualType(binaryExpression);
|
||||
const type = getContextualType(binaryExpression, contextFlags);
|
||||
return !type && node === right && !isDefaultedExpandoInitializer(binaryExpression) ?
|
||||
getTypeOfExpression(left) : type;
|
||||
case SyntaxKind.AmpersandAmpersandToken:
|
||||
case SyntaxKind.CommaToken:
|
||||
return node === right ? getContextualType(binaryExpression) : undefined;
|
||||
return node === right ? getContextualType(binaryExpression, contextFlags) : undefined;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
@ -17882,19 +17887,18 @@ namespace ts {
|
||||
// In an object literal contextually typed by a type T, the contextual type of a property assignment is the type of
|
||||
// the matching property in T, if one exists. Otherwise, it is the type of the numeric index signature in T, if one
|
||||
// exists. Otherwise, it is the type of the string index signature in T, if one exists.
|
||||
function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration): Type | undefined {
|
||||
function getContextualTypeForObjectLiteralMethod(node: MethodDeclaration, contextFlags?: ContextFlags): Type | undefined {
|
||||
Debug.assert(isObjectLiteralMethod(node));
|
||||
if (node.flags & NodeFlags.InWithStatement) {
|
||||
// We cannot answer semantic questions within a with block, do not proceed any further
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return getContextualTypeForObjectLiteralElement(node);
|
||||
return getContextualTypeForObjectLiteralElement(node, contextFlags);
|
||||
}
|
||||
|
||||
function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike) {
|
||||
function getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike, contextFlags?: ContextFlags) {
|
||||
const objectLiteral = <ObjectLiteralExpression>element.parent;
|
||||
const type = getApparentTypeOfContextualType(objectLiteral);
|
||||
const type = getApparentTypeOfContextualType(objectLiteral, contextFlags);
|
||||
if (type) {
|
||||
if (!hasNonBindableDynamicName(element)) {
|
||||
// For a (non-symbol) computed property, there is no reason to look up the name
|
||||
@ -17906,11 +17910,9 @@ namespace ts {
|
||||
return propertyType;
|
||||
}
|
||||
}
|
||||
|
||||
return isNumericName(element.name!) && getIndexTypeOfContextualType(type, IndexKind.Number) ||
|
||||
getIndexTypeOfContextualType(type, IndexKind.String);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@ -17925,9 +17927,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
// In a contextually typed conditional expression, the true/false expressions are contextually typed by the same type.
|
||||
function getContextualTypeForConditionalOperand(node: Expression): Type | undefined {
|
||||
function getContextualTypeForConditionalOperand(node: Expression, contextFlags?: ContextFlags): Type | undefined {
|
||||
const conditional = <ConditionalExpression>node.parent;
|
||||
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional) : undefined;
|
||||
return node === conditional.whenTrue || node === conditional.whenFalse ? getContextualType(conditional, contextFlags) : undefined;
|
||||
}
|
||||
|
||||
function getContextualTypeForChildJsxExpression(node: JsxElement, child: JsxChild) {
|
||||
@ -18022,8 +18024,8 @@ namespace ts {
|
||||
|
||||
// Return the contextual type for a given expression node. During overload resolution, a contextual type may temporarily
|
||||
// be "pushed" onto a node using the contextualType property.
|
||||
function getApparentTypeOfContextualType(node: Expression): Type | undefined {
|
||||
const contextualType = instantiateContextualType(getContextualType(node), node);
|
||||
function getApparentTypeOfContextualType(node: Expression, contextFlags?: ContextFlags): Type | undefined {
|
||||
const contextualType = instantiateContextualType(getContextualType(node, contextFlags), node, contextFlags);
|
||||
if (contextualType) {
|
||||
const apparentType = mapType(contextualType, getApparentType, /*noReductions*/ true);
|
||||
if (apparentType.flags & TypeFlags.Union) {
|
||||
@ -18040,13 +18042,19 @@ namespace ts {
|
||||
|
||||
// If the given contextual type contains instantiable types and if a mapper representing
|
||||
// return type inferences is available, instantiate those types using that mapper.
|
||||
function instantiateContextualType(contextualType: Type | undefined, node: Expression): Type | undefined {
|
||||
function instantiateContextualType(contextualType: Type | undefined, node: Expression, contextFlags?: ContextFlags): Type | undefined {
|
||||
if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) {
|
||||
const inferenceContext = getInferenceContext(node);
|
||||
if (inferenceContext) {
|
||||
if ((isFunctionExpressionOrArrowFunction(node) || isObjectLiteralMethod(node)) && isContextSensitive(node)) {
|
||||
// If no inferences have been made, nothing is gained from instantiating as type parameters
|
||||
// would just be replaced with their defaults similar to the apparent type.
|
||||
if (inferenceContext && some(inferenceContext.inferences, hasInferenceCandidates)) {
|
||||
// For contextual signatures we incorporate all inferences made so far, e.g. from return
|
||||
// types as well as arguments to the left in a function call.
|
||||
if (contextFlags && contextFlags & ContextFlags.Signature) {
|
||||
return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper);
|
||||
}
|
||||
// For other purposes (e.g. determining whether to produce literal types) we only
|
||||
// incorporate inferences made from the return type in a function call.
|
||||
if (inferenceContext.returnMapper) {
|
||||
return instantiateInstantiableTypes(contextualType, inferenceContext.returnMapper);
|
||||
}
|
||||
@ -18088,7 +18096,7 @@ namespace ts {
|
||||
* @param node the expression whose contextual type will be returned.
|
||||
* @returns the contextual type of an expression.
|
||||
*/
|
||||
function getContextualType(node: Expression): Type | undefined {
|
||||
function getContextualType(node: Expression, contextFlags?: ContextFlags): Type | undefined {
|
||||
if (node.flags & NodeFlags.InWithStatement) {
|
||||
// We cannot answer semantic questions within a with block, do not proceed any further
|
||||
return undefined;
|
||||
@ -18118,26 +18126,26 @@ namespace ts {
|
||||
case SyntaxKind.AsExpression:
|
||||
return isConstTypeReference((<AssertionExpression>parent).type) ? undefined : getTypeFromTypeNode((<AssertionExpression>parent).type);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return getContextualTypeForBinaryOperand(node);
|
||||
return getContextualTypeForBinaryOperand(node, contextFlags);
|
||||
case SyntaxKind.PropertyAssignment:
|
||||
case SyntaxKind.ShorthandPropertyAssignment:
|
||||
return getContextualTypeForObjectLiteralElement(<PropertyAssignment | ShorthandPropertyAssignment>parent);
|
||||
return getContextualTypeForObjectLiteralElement(<PropertyAssignment | ShorthandPropertyAssignment>parent, contextFlags);
|
||||
case SyntaxKind.SpreadAssignment:
|
||||
return getApparentTypeOfContextualType(parent.parent as ObjectLiteralExpression);
|
||||
return getApparentTypeOfContextualType(parent.parent as ObjectLiteralExpression, contextFlags);
|
||||
case SyntaxKind.ArrayLiteralExpression: {
|
||||
const arrayLiteral = <ArrayLiteralExpression>parent;
|
||||
const type = getApparentTypeOfContextualType(arrayLiteral);
|
||||
const type = getApparentTypeOfContextualType(arrayLiteral, contextFlags);
|
||||
return getContextualTypeForElementExpression(type, indexOfNode(arrayLiteral.elements, node));
|
||||
}
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
return getContextualTypeForConditionalOperand(node);
|
||||
return getContextualTypeForConditionalOperand(node, contextFlags);
|
||||
case SyntaxKind.TemplateSpan:
|
||||
Debug.assert(parent.parent.kind === SyntaxKind.TemplateExpression);
|
||||
return getContextualTypeForSubstitutionExpression(<TemplateExpression>parent.parent, node);
|
||||
case SyntaxKind.ParenthesizedExpression: {
|
||||
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
|
||||
const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined;
|
||||
return tag ? getTypeFromTypeNode(tag.typeExpression!.type) : getContextualType(<ParenthesizedExpression>parent);
|
||||
return tag ? getTypeFromTypeNode(tag.typeExpression!.type) : getContextualType(<ParenthesizedExpression>parent, contextFlags);
|
||||
}
|
||||
case SyntaxKind.JsxExpression:
|
||||
return getContextualTypeForJsxExpression(<JsxExpression>parent);
|
||||
@ -18328,12 +18336,6 @@ namespace ts {
|
||||
: undefined;
|
||||
}
|
||||
|
||||
function getContextualTypeForFunctionLikeDeclaration(node: FunctionExpression | ArrowFunction | MethodDeclaration) {
|
||||
return isObjectLiteralMethod(node) ?
|
||||
getContextualTypeForObjectLiteralMethod(node) :
|
||||
getApparentTypeOfContextualType(node);
|
||||
}
|
||||
|
||||
// Return the contextual signature for a given expression node. A contextual type provides a
|
||||
// contextual signature if it has a single call signature and if that call signature is non-generic.
|
||||
// If the contextual type is a union type, get the signature from each type possible and if they are
|
||||
@ -18345,7 +18347,9 @@ namespace ts {
|
||||
if (typeTagSignature) {
|
||||
return typeTagSignature;
|
||||
}
|
||||
const type = getContextualTypeForFunctionLikeDeclaration(node);
|
||||
const type = isObjectLiteralMethod(node) ?
|
||||
getContextualTypeForObjectLiteralMethod(node, ContextFlags.Signature) :
|
||||
getApparentTypeOfContextualType(node, ContextFlags.Signature);
|
||||
if (!type) {
|
||||
return undefined;
|
||||
}
|
||||
@ -20249,7 +20253,7 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function getSpreadArgumentType(args: ReadonlyArray<Expression>, index: number, argCount: number, restType: TypeParameter, context: InferenceContext | undefined) {
|
||||
function getSpreadArgumentType(args: ReadonlyArray<Expression>, index: number, argCount: number, restType: Type, context: InferenceContext | undefined) {
|
||||
if (index >= argCount - 1) {
|
||||
const arg = args[argCount - 1];
|
||||
if (isSpreadArgument(arg)) {
|
||||
@ -20260,7 +20264,7 @@ namespace ts {
|
||||
getArrayifiedType(checkExpressionWithContextualType((<SpreadElement>arg).expression, restType, context, CheckMode.Normal));
|
||||
}
|
||||
}
|
||||
const contextualType = getIndexTypeOfType(restType, IndexKind.Number) || anyType;
|
||||
const contextualType = getIndexedAccessType(restType, numberType);
|
||||
const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index);
|
||||
const types = [];
|
||||
let spreadIndex = -1;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user