mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-14 19:16:17 -06:00
Introduce CheckMode enum and getContextualMapper() function
This commit is contained in:
parent
5bda48ba8d
commit
993397b5ab
@ -433,6 +433,12 @@ namespace ts {
|
||||
ResolvedReturnType
|
||||
}
|
||||
|
||||
const enum CheckMode {
|
||||
Normal = 0, // Normal type checking
|
||||
SkipContextSensitive = 1, // Skip context sensitive function expressions
|
||||
Inferential = 2, // Inferential typing
|
||||
}
|
||||
|
||||
const builtinGlobals = createMap<Symbol>();
|
||||
builtinGlobals.set(undefinedSymbol.name, undefinedSymbol);
|
||||
|
||||
@ -11543,7 +11549,7 @@ namespace ts {
|
||||
while (type) {
|
||||
const thisType = getThisTypeFromContextualType(type);
|
||||
if (thisType) {
|
||||
return thisType;
|
||||
return instantiateType(thisType, getContextualMapper(containingLiteral));
|
||||
}
|
||||
if (literal.parent.kind !== SyntaxKind.PropertyAssignment) {
|
||||
break;
|
||||
@ -11929,6 +11935,16 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getContextualMapper(node: Node) {
|
||||
while (node) {
|
||||
if (node.contextualMapper) {
|
||||
return node.contextualMapper;
|
||||
}
|
||||
node = node.parent;
|
||||
}
|
||||
return identityMapper;
|
||||
}
|
||||
|
||||
// If the given type is an object or union type, if that type has a single signature, and if
|
||||
// that signature is non-generic, return the signature. Otherwise return undefined.
|
||||
function getNonGenericSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature {
|
||||
@ -12019,31 +12035,12 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the mapper implies an inference context. Specifically, there are 4 possible values
|
||||
* for a mapper. Let's go through each one of them:
|
||||
*
|
||||
* 1. undefined - this means we are not doing inferential typing, but we may do contextual typing,
|
||||
* which could cause us to assign a parameter a type
|
||||
* 2. identityMapper - means we want to avoid assigning a parameter a type, whether or not we are in
|
||||
* inferential typing (context is undefined for the identityMapper)
|
||||
* 3. a mapper created by createInferenceMapper - we are doing inferential typing, we want to assign
|
||||
* types to parameters and fix type parameters (context is defined)
|
||||
* 4. an instantiation mapper created by createTypeMapper or createTypeEraser - this should never be
|
||||
* passed as the contextual mapper when checking an expression (context is undefined for these)
|
||||
*
|
||||
* isInferentialContext is detecting if we are in case 3
|
||||
*/
|
||||
function isInferentialContext(mapper: TypeMapper) {
|
||||
return mapper && mapper.context;
|
||||
}
|
||||
|
||||
function checkSpreadExpression(node: SpreadElement, contextualMapper?: TypeMapper): Type {
|
||||
function checkSpreadExpression(node: SpreadElement, checkMode?: CheckMode): Type {
|
||||
if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
|
||||
checkExternalEmitHelpers(node, ExternalEmitHelpers.SpreadIncludes);
|
||||
}
|
||||
|
||||
const arrayOrIterableType = checkExpression(node.expression, contextualMapper);
|
||||
const arrayOrIterableType = checkExpression(node.expression, checkMode);
|
||||
return checkIteratedTypeOrElementType(arrayOrIterableType, node.expression, /*allowStringInput*/ false, /*allowAsyncIterable*/ false);
|
||||
}
|
||||
|
||||
@ -12052,7 +12049,7 @@ namespace ts {
|
||||
(node.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>node).operatorToken.kind === SyntaxKind.EqualsToken);
|
||||
}
|
||||
|
||||
function checkArrayLiteral(node: ArrayLiteralExpression, contextualMapper?: TypeMapper): Type {
|
||||
function checkArrayLiteral(node: ArrayLiteralExpression, checkMode?: CheckMode): Type {
|
||||
const elements = node.elements;
|
||||
let hasSpreadElement = false;
|
||||
const elementTypes: Type[] = [];
|
||||
@ -12071,7 +12068,7 @@ namespace ts {
|
||||
// get the contextual element type from it. So we do something similar to
|
||||
// getContextualTypeForElementExpression, which will crucially not error
|
||||
// if there is no index type / iterated type.
|
||||
const restArrayType = checkExpression((<SpreadElement>e).expression, contextualMapper);
|
||||
const restArrayType = checkExpression((<SpreadElement>e).expression, checkMode);
|
||||
const restElementType = getIndexTypeOfType(restArrayType, IndexKind.Number) ||
|
||||
getIteratedTypeOrElementType(restArrayType, /*errorNode*/ undefined, /*allowStringInput*/ false, /*allowAsyncIterable*/ false, /*checkAssignability*/ false);
|
||||
if (restElementType) {
|
||||
@ -12079,7 +12076,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
const type = checkExpressionForMutableLocation(e, contextualMapper);
|
||||
const type = checkExpressionForMutableLocation(e, checkMode);
|
||||
elementTypes.push(type);
|
||||
}
|
||||
hasSpreadElement = hasSpreadElement || e.kind === SyntaxKind.SpreadElement;
|
||||
@ -12194,7 +12191,7 @@ namespace ts {
|
||||
return createIndexInfo(unionType, /*isReadonly*/ false);
|
||||
}
|
||||
|
||||
function checkObjectLiteral(node: ObjectLiteralExpression, contextualMapper?: TypeMapper): Type {
|
||||
function checkObjectLiteral(node: ObjectLiteralExpression, checkMode?: CheckMode): Type {
|
||||
const inDestructuringPattern = isAssignmentTarget(node);
|
||||
// Grammar checking
|
||||
checkGrammarObjectLiteralExpression(node, inDestructuringPattern);
|
||||
@ -12221,14 +12218,14 @@ namespace ts {
|
||||
isObjectLiteralMethod(memberDecl)) {
|
||||
let type: Type;
|
||||
if (memberDecl.kind === SyntaxKind.PropertyAssignment) {
|
||||
type = checkPropertyAssignment(<PropertyAssignment>memberDecl, contextualMapper);
|
||||
type = checkPropertyAssignment(<PropertyAssignment>memberDecl, checkMode);
|
||||
}
|
||||
else if (memberDecl.kind === SyntaxKind.MethodDeclaration) {
|
||||
type = checkObjectLiteralMethod(<MethodDeclaration>memberDecl, contextualMapper);
|
||||
type = checkObjectLiteralMethod(<MethodDeclaration>memberDecl, checkMode);
|
||||
}
|
||||
else {
|
||||
Debug.assert(memberDecl.kind === SyntaxKind.ShorthandPropertyAssignment);
|
||||
type = checkExpressionForMutableLocation((<ShorthandPropertyAssignment>memberDecl).name, contextualMapper);
|
||||
type = checkExpressionForMutableLocation((<ShorthandPropertyAssignment>memberDecl).name, checkMode);
|
||||
}
|
||||
|
||||
typeFlags |= type.flags;
|
||||
@ -12434,7 +12431,7 @@ namespace ts {
|
||||
* @remarks Because this function calls getSpreadType, it needs to use the same checks as checkObjectLiteral,
|
||||
* which also calls getSpreadType.
|
||||
*/
|
||||
function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, filter?: (symbol: Symbol) => boolean, contextualMapper?: TypeMapper) {
|
||||
function createJsxAttributesTypeFromAttributesProperty(openingLikeElement: JsxOpeningLikeElement, filter?: (symbol: Symbol) => boolean, checkMode?: CheckMode) {
|
||||
const attributes = openingLikeElement.attributes;
|
||||
let attributesTable = createMap<Symbol>();
|
||||
let spread: Type = emptyObjectType;
|
||||
@ -12443,7 +12440,7 @@ namespace ts {
|
||||
const member = attributeDecl.symbol;
|
||||
if (isJsxAttribute(attributeDecl)) {
|
||||
const exprType = attributeDecl.initializer ?
|
||||
checkExpression(attributeDecl.initializer, contextualMapper) :
|
||||
checkExpression(attributeDecl.initializer, checkMode) :
|
||||
trueType; // <Elem attr /> is sugar for <Elem attr={true} />
|
||||
|
||||
const attributeSymbol = <TransientSymbol>createSymbol(SymbolFlags.Property | SymbolFlags.Transient | member.flags, member.name);
|
||||
@ -12514,8 +12511,8 @@ namespace ts {
|
||||
* (See "checkApplicableSignatureForJsxOpeningLikeElement" for how the function is used)
|
||||
* @param node a JSXAttributes to be resolved of its type
|
||||
*/
|
||||
function checkJsxAttributes(node: JsxAttributes, contextualMapper?: TypeMapper) {
|
||||
return createJsxAttributesTypeFromAttributesProperty(node.parent as JsxOpeningLikeElement, /*filter*/ undefined, contextualMapper);
|
||||
function checkJsxAttributes(node: JsxAttributes, checkMode?: CheckMode) {
|
||||
return createJsxAttributesTypeFromAttributesProperty(node.parent as JsxOpeningLikeElement, /*filter*/ undefined, checkMode);
|
||||
}
|
||||
|
||||
function getJsxType(name: string) {
|
||||
@ -13013,9 +13010,9 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkJsxExpression(node: JsxExpression, contextualMapper?: TypeMapper) {
|
||||
function checkJsxExpression(node: JsxExpression, checkMode?: CheckMode) {
|
||||
if (node.expression) {
|
||||
const type = checkExpression(node.expression, contextualMapper);
|
||||
const type = checkExpression(node.expression, checkMode);
|
||||
if (node.dotDotDotToken && type !== anyType && !isArrayType(type)) {
|
||||
error(node, Diagnostics.JSX_spread_child_must_be_an_array_type, node.toString(), typeToString(type));
|
||||
}
|
||||
@ -14877,9 +14874,9 @@ namespace ts {
|
||||
return signature.parameters.length > 0 ? getTypeAtPosition(signature, 0) : neverType;
|
||||
}
|
||||
|
||||
function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper) {
|
||||
function assignContextualParameterTypes(signature: Signature, context: Signature, mapper: TypeMapper, checkMode: CheckMode) {
|
||||
const len = signature.parameters.length - (signature.hasRestParameter ? 1 : 0);
|
||||
if (isInferentialContext(mapper)) {
|
||||
if (checkMode === CheckMode.Inferential) {
|
||||
for (let i = 0; i < len; i++) {
|
||||
const declaration = <ParameterDeclaration>signature.parameters[i].valueDeclaration;
|
||||
if (declaration.type) {
|
||||
@ -14893,21 +14890,21 @@ namespace ts {
|
||||
if (!parameter) {
|
||||
signature.thisParameter = createSymbolWithType(context.thisParameter, undefined);
|
||||
}
|
||||
assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper);
|
||||
assignTypeToParameterAndFixTypeParameters(signature.thisParameter, getTypeOfSymbol(context.thisParameter), mapper, checkMode);
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < len; i++) {
|
||||
const parameter = signature.parameters[i];
|
||||
if (!(<ParameterDeclaration>parameter.valueDeclaration).type) {
|
||||
const contextualParameterType = getTypeAtPosition(context, i);
|
||||
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
|
||||
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper, checkMode);
|
||||
}
|
||||
}
|
||||
if (signature.hasRestParameter && isRestParameterIndex(context, signature.parameters.length - 1)) {
|
||||
const parameter = lastOrUndefined(signature.parameters);
|
||||
if (!(<ParameterDeclaration>parameter.valueDeclaration).type) {
|
||||
const contextualParameterType = getTypeOfSymbol(lastOrUndefined(context.parameters));
|
||||
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper);
|
||||
assignTypeToParameterAndFixTypeParameters(parameter, contextualParameterType, mapper, checkMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -14927,7 +14924,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type, mapper: TypeMapper) {
|
||||
function assignTypeToParameterAndFixTypeParameters(parameter: Symbol, contextualType: Type, mapper: TypeMapper, checkMode: CheckMode) {
|
||||
const links = getSymbolLinks(parameter);
|
||||
if (!links.type) {
|
||||
links.type = instantiateType(contextualType, mapper);
|
||||
@ -14939,7 +14936,7 @@ namespace ts {
|
||||
}
|
||||
assignBindingElementTypes(<ParameterDeclaration>parameter.valueDeclaration);
|
||||
}
|
||||
else if (isInferentialContext(mapper)) {
|
||||
else if (checkMode === CheckMode.Inferential) {
|
||||
// Even if the parameter already has a type, it might be because it was given a type while
|
||||
// processing the function as an argument to a prior signature during overload resolution.
|
||||
// If this was the case, it may have caused some type parameters to be fixed. So here,
|
||||
@ -15007,7 +15004,7 @@ namespace ts {
|
||||
return promiseType;
|
||||
}
|
||||
|
||||
function getReturnTypeFromBody(func: FunctionLikeDeclaration, contextualMapper?: TypeMapper): Type {
|
||||
function getReturnTypeFromBody(func: FunctionLikeDeclaration, checkMode?: CheckMode): Type {
|
||||
const contextualSignature = getContextualSignatureForFunctionLikeDeclaration(func);
|
||||
if (!func.body) {
|
||||
return unknownType;
|
||||
@ -15016,7 +15013,7 @@ namespace ts {
|
||||
const functionFlags = getFunctionFlags(func);
|
||||
let type: Type;
|
||||
if (func.body.kind !== SyntaxKind.Block) {
|
||||
type = checkExpressionCached(<Expression>func.body, contextualMapper);
|
||||
type = checkExpressionCached(<Expression>func.body, checkMode);
|
||||
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
|
||||
@ -15028,7 +15025,7 @@ namespace ts {
|
||||
else {
|
||||
let types: Type[];
|
||||
if (functionFlags & FunctionFlags.Generator) { // Generator or AsyncGenerator function
|
||||
types = checkAndAggregateYieldOperandTypes(func, contextualMapper);
|
||||
types = checkAndAggregateYieldOperandTypes(func, checkMode);
|
||||
if (types.length === 0) {
|
||||
const iterableIteratorAny = functionFlags & FunctionFlags.Async
|
||||
? createAsyncIterableIteratorType(anyType) // AsyncGenerator function
|
||||
@ -15041,7 +15038,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
types = checkAndAggregateReturnExpressionTypes(func, contextualMapper);
|
||||
types = checkAndAggregateReturnExpressionTypes(func, checkMode);
|
||||
if (!types) {
|
||||
// For an async function, the return type will not be never, but rather a Promise for never.
|
||||
return functionFlags & FunctionFlags.Async
|
||||
@ -15085,13 +15082,13 @@ namespace ts {
|
||||
: widenedType; // Generator function, AsyncGenerator function, or normal function
|
||||
}
|
||||
|
||||
function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, contextualMapper: TypeMapper): Type[] {
|
||||
function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode): Type[] {
|
||||
const aggregatedTypes: Type[] = [];
|
||||
const functionFlags = getFunctionFlags(func);
|
||||
forEachYieldExpression(<Block>func.body, yieldExpression => {
|
||||
const expr = yieldExpression.expression;
|
||||
if (expr) {
|
||||
let type = checkExpressionCached(expr, contextualMapper);
|
||||
let type = checkExpressionCached(expr, checkMode);
|
||||
if (yieldExpression.asteriskToken) {
|
||||
// A yield* expression effectively yields everything that its operand yields
|
||||
type = checkIteratedTypeOrElementType(type, yieldExpression.expression, /*allowStringInput*/ false, (functionFlags & FunctionFlags.Async) !== 0);
|
||||
@ -15131,7 +15128,7 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
|
||||
function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, contextualMapper: TypeMapper): Type[] {
|
||||
function checkAndAggregateReturnExpressionTypes(func: FunctionLikeDeclaration, checkMode: CheckMode): Type[] {
|
||||
const functionFlags = getFunctionFlags(func);
|
||||
const aggregatedTypes: Type[] = [];
|
||||
let hasReturnWithNoExpression = functionHasImplicitReturn(func);
|
||||
@ -15139,7 +15136,7 @@ namespace ts {
|
||||
forEachReturnStatement(<Block>func.body, returnStatement => {
|
||||
const expr = returnStatement.expression;
|
||||
if (expr) {
|
||||
let type = checkExpressionCached(expr, contextualMapper);
|
||||
let type = checkExpressionCached(expr, checkMode);
|
||||
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
|
||||
@ -15226,7 +15223,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, contextualMapper?: TypeMapper): Type {
|
||||
function checkFunctionExpressionOrObjectLiteralMethod(node: FunctionExpression | MethodDeclaration, checkMode?: CheckMode): Type {
|
||||
Debug.assert(node.kind !== SyntaxKind.MethodDeclaration || isObjectLiteralMethod(node));
|
||||
|
||||
// Grammar checking
|
||||
@ -15236,7 +15233,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// The identityMapper object is used to indicate that function expressions are wildcards
|
||||
if (contextualMapper === identityMapper && isContextSensitive(node)) {
|
||||
if (checkMode === CheckMode.SkipContextSensitive && isContextSensitive(node)) {
|
||||
checkNodeDeferred(node);
|
||||
return anyFunctionType;
|
||||
}
|
||||
@ -15244,7 +15241,7 @@ namespace ts {
|
||||
const links = getNodeLinks(node);
|
||||
const type = getTypeOfSymbol(node.symbol);
|
||||
const contextSensitive = isContextSensitive(node);
|
||||
const mightFixTypeParameters = contextSensitive && isInferentialContext(contextualMapper);
|
||||
const mightFixTypeParameters = contextSensitive && checkMode === CheckMode.Inferential;
|
||||
|
||||
// Check if function expression is contextually typed and assign parameter types if so.
|
||||
// See the comment in assignTypeToParameterAndFixTypeParameters to understand why we need to
|
||||
@ -15260,10 +15257,10 @@ namespace ts {
|
||||
if (contextualSignature) {
|
||||
const signature = getSignaturesOfType(type, SignatureKind.Call)[0];
|
||||
if (contextSensitive) {
|
||||
assignContextualParameterTypes(signature, contextualSignature, contextualMapper || identityMapper);
|
||||
assignContextualParameterTypes(signature, contextualSignature, getContextualMapper(node), checkMode);
|
||||
}
|
||||
if (mightFixTypeParameters || !node.type && !signature.resolvedReturnType) {
|
||||
const returnType = getReturnTypeFromBody(node, contextualMapper);
|
||||
const returnType = getReturnTypeFromBody(node, checkMode);
|
||||
if (!signature.resolvedReturnType) {
|
||||
signature.resolvedReturnType = returnType;
|
||||
}
|
||||
@ -15639,7 +15636,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, contextualMapper?: TypeMapper): Type {
|
||||
function checkArrayLiteralAssignment(node: ArrayLiteralExpression, sourceType: Type, checkMode?: CheckMode): Type {
|
||||
if (languageVersion < ScriptTarget.ES2015 && compilerOptions.downlevelIteration) {
|
||||
checkExternalEmitHelpers(node, ExternalEmitHelpers.Read);
|
||||
}
|
||||
@ -15650,13 +15647,13 @@ namespace ts {
|
||||
const elementType = checkIteratedTypeOrElementType(sourceType, node, /*allowStringInput*/ false, /*allowAsyncIterable*/ false) || unknownType;
|
||||
const elements = node.elements;
|
||||
for (let i = 0; i < elements.length; i++) {
|
||||
checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, elementType, contextualMapper);
|
||||
checkArrayLiteralDestructuringElementAssignment(node, sourceType, i, elementType, checkMode);
|
||||
}
|
||||
return sourceType;
|
||||
}
|
||||
|
||||
function checkArrayLiteralDestructuringElementAssignment(node: ArrayLiteralExpression, sourceType: Type,
|
||||
elementIndex: number, elementType: Type, contextualMapper?: TypeMapper) {
|
||||
elementIndex: number, elementType: Type, checkMode?: CheckMode) {
|
||||
const elements = node.elements;
|
||||
const element = elements[elementIndex];
|
||||
if (element.kind !== SyntaxKind.OmittedExpression) {
|
||||
@ -15668,7 +15665,7 @@ namespace ts {
|
||||
? getTypeOfPropertyOfType(sourceType, propName)
|
||||
: elementType;
|
||||
if (type) {
|
||||
return checkDestructuringAssignment(element, type, contextualMapper);
|
||||
return checkDestructuringAssignment(element, type, checkMode);
|
||||
}
|
||||
else {
|
||||
// We still need to check element expression here because we may need to set appropriate flag on the expression
|
||||
@ -15692,7 +15689,7 @@ namespace ts {
|
||||
error((<BinaryExpression>restExpression).operatorToken, Diagnostics.A_rest_element_cannot_have_an_initializer);
|
||||
}
|
||||
else {
|
||||
return checkDestructuringAssignment(restExpression, createArrayType(elementType), contextualMapper);
|
||||
return checkDestructuringAssignment(restExpression, createArrayType(elementType), checkMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15700,7 +15697,7 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, contextualMapper?: TypeMapper): Type {
|
||||
function checkDestructuringAssignment(exprOrAssignment: Expression | ShorthandPropertyAssignment, sourceType: Type, checkMode?: CheckMode): Type {
|
||||
let target: Expression;
|
||||
if (exprOrAssignment.kind === SyntaxKind.ShorthandPropertyAssignment) {
|
||||
const prop = <ShorthandPropertyAssignment>exprOrAssignment;
|
||||
@ -15711,7 +15708,7 @@ namespace ts {
|
||||
!(getFalsyFlags(checkExpression(prop.objectAssignmentInitializer)) & TypeFlags.Undefined)) {
|
||||
sourceType = getTypeWithFacts(sourceType, TypeFacts.NEUndefined);
|
||||
}
|
||||
checkBinaryLikeExpression(prop.name, prop.equalsToken, prop.objectAssignmentInitializer, contextualMapper);
|
||||
checkBinaryLikeExpression(prop.name, prop.equalsToken, prop.objectAssignmentInitializer, checkMode);
|
||||
}
|
||||
target = (<ShorthandPropertyAssignment>exprOrAssignment).name;
|
||||
}
|
||||
@ -15720,20 +15717,20 @@ namespace ts {
|
||||
}
|
||||
|
||||
if (target.kind === SyntaxKind.BinaryExpression && (<BinaryExpression>target).operatorToken.kind === SyntaxKind.EqualsToken) {
|
||||
checkBinaryExpression(<BinaryExpression>target, contextualMapper);
|
||||
checkBinaryExpression(<BinaryExpression>target, checkMode);
|
||||
target = (<BinaryExpression>target).left;
|
||||
}
|
||||
if (target.kind === SyntaxKind.ObjectLiteralExpression) {
|
||||
return checkObjectLiteralAssignment(<ObjectLiteralExpression>target, sourceType);
|
||||
}
|
||||
if (target.kind === SyntaxKind.ArrayLiteralExpression) {
|
||||
return checkArrayLiteralAssignment(<ArrayLiteralExpression>target, sourceType, contextualMapper);
|
||||
return checkArrayLiteralAssignment(<ArrayLiteralExpression>target, sourceType, checkMode);
|
||||
}
|
||||
return checkReferenceAssignment(target, sourceType, contextualMapper);
|
||||
return checkReferenceAssignment(target, sourceType, checkMode);
|
||||
}
|
||||
|
||||
function checkReferenceAssignment(target: Expression, sourceType: Type, contextualMapper?: TypeMapper): Type {
|
||||
const targetType = checkExpression(target, contextualMapper);
|
||||
function checkReferenceAssignment(target: Expression, sourceType: Type, checkMode?: CheckMode): Type {
|
||||
const targetType = checkExpression(target, checkMode);
|
||||
const error = target.parent.kind === SyntaxKind.SpreadAssignment ?
|
||||
Diagnostics.The_target_of_an_object_rest_assignment_must_be_a_variable_or_a_property_access :
|
||||
Diagnostics.The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access;
|
||||
@ -15821,17 +15818,17 @@ namespace ts {
|
||||
getUnionType([type1, type2], /*subtypeReduction*/ true);
|
||||
}
|
||||
|
||||
function checkBinaryExpression(node: BinaryExpression, contextualMapper?: TypeMapper) {
|
||||
return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, contextualMapper, node);
|
||||
function checkBinaryExpression(node: BinaryExpression, checkMode?: CheckMode) {
|
||||
return checkBinaryLikeExpression(node.left, node.operatorToken, node.right, checkMode, node);
|
||||
}
|
||||
|
||||
function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, contextualMapper?: TypeMapper, errorNode?: Node) {
|
||||
function checkBinaryLikeExpression(left: Expression, operatorToken: Node, right: Expression, checkMode?: CheckMode, errorNode?: Node) {
|
||||
const operator = operatorToken.kind;
|
||||
if (operator === SyntaxKind.EqualsToken && (left.kind === SyntaxKind.ObjectLiteralExpression || left.kind === SyntaxKind.ArrayLiteralExpression)) {
|
||||
return checkDestructuringAssignment(left, checkExpression(right, contextualMapper), contextualMapper);
|
||||
return checkDestructuringAssignment(left, checkExpression(right, checkMode), checkMode);
|
||||
}
|
||||
let leftType = checkExpression(left, contextualMapper);
|
||||
let rightType = checkExpression(right, contextualMapper);
|
||||
let leftType = checkExpression(left, checkMode);
|
||||
let rightType = checkExpression(right, checkMode);
|
||||
switch (operator) {
|
||||
case SyntaxKind.AsteriskToken:
|
||||
case SyntaxKind.AsteriskAsteriskToken:
|
||||
@ -16094,10 +16091,10 @@ namespace ts {
|
||||
return anyType;
|
||||
}
|
||||
|
||||
function checkConditionalExpression(node: ConditionalExpression, contextualMapper?: TypeMapper): Type {
|
||||
function checkConditionalExpression(node: ConditionalExpression, checkMode?: CheckMode): Type {
|
||||
checkExpression(node.condition);
|
||||
const type1 = checkExpression(node.whenTrue, contextualMapper);
|
||||
const type2 = checkExpression(node.whenFalse, contextualMapper);
|
||||
const type1 = checkExpression(node.whenTrue, checkMode);
|
||||
const type2 = checkExpression(node.whenFalse, checkMode);
|
||||
return getBestChoiceType(type1, type2);
|
||||
}
|
||||
|
||||
@ -16130,15 +16127,20 @@ namespace ts {
|
||||
return stringType;
|
||||
}
|
||||
|
||||
function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper?: TypeMapper): Type {
|
||||
function checkExpressionWithContextualType(node: Expression, contextualType: Type, contextualMapper: TypeMapper): Type {
|
||||
const saveContextualType = node.contextualType;
|
||||
const saveContextualMapper = node.contextualMapper;
|
||||
node.contextualType = contextualType;
|
||||
const result = checkExpression(node, contextualMapper);
|
||||
node.contextualMapper = contextualMapper;
|
||||
const checkMode = contextualMapper === identityMapper ? CheckMode.SkipContextSensitive :
|
||||
contextualMapper ? CheckMode.Inferential : CheckMode.Normal;
|
||||
const result = checkExpression(node, checkMode);
|
||||
node.contextualType = saveContextualType;
|
||||
node.contextualMapper = saveContextualMapper;
|
||||
return result;
|
||||
}
|
||||
|
||||
function checkExpressionCached(node: Expression, contextualMapper?: TypeMapper): Type {
|
||||
function checkExpressionCached(node: Expression, checkMode?: CheckMode): Type {
|
||||
const links = getNodeLinks(node);
|
||||
if (!links.resolvedType) {
|
||||
// When computing a type that we're going to cache, we need to ignore any ongoing control flow
|
||||
@ -16146,7 +16148,7 @@ namespace ts {
|
||||
// to the top of the stack ensures all transient types are computed from a known point.
|
||||
const saveFlowLoopStart = flowLoopStart;
|
||||
flowLoopStart = flowLoopCount;
|
||||
links.resolvedType = checkExpression(node, contextualMapper);
|
||||
links.resolvedType = checkExpression(node, checkMode);
|
||||
flowLoopStart = saveFlowLoopStart;
|
||||
}
|
||||
return links.resolvedType;
|
||||
@ -16181,12 +16183,12 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
function checkExpressionForMutableLocation(node: Expression, contextualMapper?: TypeMapper): Type {
|
||||
const type = checkExpression(node, contextualMapper);
|
||||
function checkExpressionForMutableLocation(node: Expression, checkMode?: CheckMode): Type {
|
||||
const type = checkExpression(node, checkMode);
|
||||
return isTypeAssertion(node) || isLiteralContextualType(getContextualType(node)) ? type : getWidenedLiteralType(type);
|
||||
}
|
||||
|
||||
function checkPropertyAssignment(node: PropertyAssignment, contextualMapper?: TypeMapper): Type {
|
||||
function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type {
|
||||
// Do not use hasDynamicName here, because that returns false for well known symbols.
|
||||
// We want to perform checkComputedPropertyName for all computed properties, including
|
||||
// well known symbols.
|
||||
@ -16194,10 +16196,10 @@ namespace ts {
|
||||
checkComputedPropertyName(<ComputedPropertyName>node.name);
|
||||
}
|
||||
|
||||
return checkExpressionForMutableLocation((<PropertyAssignment>node).initializer, contextualMapper);
|
||||
return checkExpressionForMutableLocation((<PropertyAssignment>node).initializer, checkMode);
|
||||
}
|
||||
|
||||
function checkObjectLiteralMethod(node: MethodDeclaration, contextualMapper?: TypeMapper): Type {
|
||||
function checkObjectLiteralMethod(node: MethodDeclaration, checkMode?: CheckMode): Type {
|
||||
// Grammar checking
|
||||
checkGrammarMethod(node);
|
||||
|
||||
@ -16208,19 +16210,19 @@ namespace ts {
|
||||
checkComputedPropertyName(<ComputedPropertyName>node.name);
|
||||
}
|
||||
|
||||
const uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, contextualMapper);
|
||||
return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, contextualMapper);
|
||||
const uninstantiatedType = checkFunctionExpressionOrObjectLiteralMethod(node, checkMode);
|
||||
return instantiateTypeWithSingleGenericCallSignature(node, uninstantiatedType, checkMode);
|
||||
}
|
||||
|
||||
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, contextualMapper?: TypeMapper) {
|
||||
if (isInferentialContext(contextualMapper)) {
|
||||
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration, type: Type, checkMode?: CheckMode) {
|
||||
if (checkMode === CheckMode.Inferential) {
|
||||
const signature = getSingleCallSignature(type);
|
||||
if (signature && signature.typeParameters) {
|
||||
const contextualType = getApparentTypeOfContextualType(<Expression>node);
|
||||
if (contextualType) {
|
||||
const contextualSignature = getSingleCallSignature(contextualType);
|
||||
if (contextualSignature && !contextualSignature.typeParameters) {
|
||||
return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, contextualMapper));
|
||||
return getOrCreateTypeFromSignature(instantiateSignatureInContextOf(signature, contextualSignature, getContextualMapper(node)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -16254,14 +16256,14 @@ namespace ts {
|
||||
// object, it serves as an indicator that all contained function and arrow expressions should be considered to
|
||||
// have the wildcard function type; this form of type check is used during overload resolution to exclude
|
||||
// contextually typed function and arrow expressions in the initial phase.
|
||||
function checkExpression(node: Expression | QualifiedName, contextualMapper?: TypeMapper): Type {
|
||||
function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode): Type {
|
||||
let type: Type;
|
||||
if (node.kind === SyntaxKind.QualifiedName) {
|
||||
type = checkQualifiedName(<QualifiedName>node);
|
||||
}
|
||||
else {
|
||||
const uninstantiatedType = checkExpressionWorker(<Expression>node, contextualMapper);
|
||||
type = instantiateTypeWithSingleGenericCallSignature(<Expression>node, uninstantiatedType, contextualMapper);
|
||||
const uninstantiatedType = checkExpressionWorker(<Expression>node, checkMode);
|
||||
type = instantiateTypeWithSingleGenericCallSignature(<Expression>node, uninstantiatedType, checkMode);
|
||||
}
|
||||
|
||||
if (isConstEnumObjectType(type)) {
|
||||
@ -16281,7 +16283,7 @@ namespace ts {
|
||||
return type;
|
||||
}
|
||||
|
||||
function checkExpressionWorker(node: Expression, contextualMapper: TypeMapper): Type {
|
||||
function checkExpressionWorker(node: Expression, checkMode: CheckMode): Type {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return checkIdentifier(<Identifier>node);
|
||||
@ -16303,9 +16305,9 @@ namespace ts {
|
||||
case SyntaxKind.RegularExpressionLiteral:
|
||||
return globalRegExpType;
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return checkArrayLiteral(<ArrayLiteralExpression>node, contextualMapper);
|
||||
return checkArrayLiteral(<ArrayLiteralExpression>node, checkMode);
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return checkObjectLiteral(<ObjectLiteralExpression>node, contextualMapper);
|
||||
return checkObjectLiteral(<ObjectLiteralExpression>node, checkMode);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
return checkPropertyAccessExpression(<PropertyAccessExpression>node);
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
@ -16316,12 +16318,12 @@ namespace ts {
|
||||
case SyntaxKind.TaggedTemplateExpression:
|
||||
return checkTaggedTemplateExpression(<TaggedTemplateExpression>node);
|
||||
case SyntaxKind.ParenthesizedExpression:
|
||||
return checkExpression((<ParenthesizedExpression>node).expression, contextualMapper);
|
||||
return checkExpression((<ParenthesizedExpression>node).expression, checkMode);
|
||||
case SyntaxKind.ClassExpression:
|
||||
return checkClassExpression(<ClassExpression>node);
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return checkFunctionExpressionOrObjectLiteralMethod(<FunctionExpression>node, contextualMapper);
|
||||
return checkFunctionExpressionOrObjectLiteralMethod(<FunctionExpression>node, checkMode);
|
||||
case SyntaxKind.TypeOfExpression:
|
||||
return checkTypeOfExpression(<TypeOfExpression>node);
|
||||
case SyntaxKind.TypeAssertionExpression:
|
||||
@ -16342,23 +16344,23 @@ namespace ts {
|
||||
case SyntaxKind.PostfixUnaryExpression:
|
||||
return checkPostfixUnaryExpression(<PostfixUnaryExpression>node);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return checkBinaryExpression(<BinaryExpression>node, contextualMapper);
|
||||
return checkBinaryExpression(<BinaryExpression>node, checkMode);
|
||||
case SyntaxKind.ConditionalExpression:
|
||||
return checkConditionalExpression(<ConditionalExpression>node, contextualMapper);
|
||||
return checkConditionalExpression(<ConditionalExpression>node, checkMode);
|
||||
case SyntaxKind.SpreadElement:
|
||||
return checkSpreadExpression(<SpreadElement>node, contextualMapper);
|
||||
return checkSpreadExpression(<SpreadElement>node, checkMode);
|
||||
case SyntaxKind.OmittedExpression:
|
||||
return undefinedWideningType;
|
||||
case SyntaxKind.YieldExpression:
|
||||
return checkYieldExpression(<YieldExpression>node);
|
||||
case SyntaxKind.JsxExpression:
|
||||
return checkJsxExpression(<JsxExpression>node, contextualMapper);
|
||||
return checkJsxExpression(<JsxExpression>node, checkMode);
|
||||
case SyntaxKind.JsxElement:
|
||||
return checkJsxElement(<JsxElement>node);
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
return checkJsxSelfClosingElement(<JsxSelfClosingElement>node);
|
||||
case SyntaxKind.JsxAttributes:
|
||||
return checkJsxAttributes(<JsxAttributes>node, contextualMapper);
|
||||
return checkJsxAttributes(<JsxAttributes>node, checkMode);
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
Debug.fail("Shouldn't ever directly check a JsxOpeningElement");
|
||||
}
|
||||
|
||||
@ -522,6 +522,8 @@
|
||||
/* @internal */ localSymbol?: Symbol; // Local symbol declared by node (initialized by binding only for exported nodes)
|
||||
/* @internal */ flowNode?: FlowNode; // Associated FlowNode (initialized by binding)
|
||||
/* @internal */ emitNode?: EmitNode; // Associated EmitNode (initialized by transforms)
|
||||
/* @internal */ contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
|
||||
/* @internal */ contextualMapper?: TypeMapper; // Mapper for contextual type
|
||||
}
|
||||
|
||||
export interface NodeArray<T extends Node> extends Array<T>, TextRange {
|
||||
@ -960,7 +962,6 @@
|
||||
|
||||
export interface Expression extends Node {
|
||||
_expressionBrand: any;
|
||||
contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution
|
||||
}
|
||||
|
||||
export interface OmittedExpression extends Expression {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user