diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 72b9e4acadedb..b01352968eb42 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -1000,6 +1000,7 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { const saveExceptionTarget = currentExceptionTarget; const saveActiveLabelList = activeLabelList; const saveHasExplicitReturn = hasExplicitReturn; + const saveSeenThisKeyword = seenThisKeyword; const isImmediatelyInvoked = ( containerFlags & ContainerFlags.IsFunctionExpression && !hasSyntacticModifier(node, ModifierFlags.Async) && @@ -1022,19 +1023,22 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { currentContinueTarget = undefined; activeLabelList = undefined; hasExplicitReturn = false; + seenThisKeyword = false; bindChildren(node); - // Reset all reachability check related flags on node (for incremental scenarios) - node.flags &= ~NodeFlags.ReachabilityAndEmitFlags; + // Reset flags (for incremental scenarios) + node.flags &= ~(NodeFlags.ReachabilityAndEmitFlags | NodeFlags.ContainsThis); if (!(currentFlow.flags & FlowFlags.Unreachable) && containerFlags & ContainerFlags.IsFunctionLike && nodeIsPresent((node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).body)) { node.flags |= NodeFlags.HasImplicitReturn; if (hasExplicitReturn) node.flags |= NodeFlags.HasExplicitReturn; (node as FunctionLikeDeclaration | ClassStaticBlockDeclaration).endFlowNode = currentFlow; } + if (seenThisKeyword) { + node.flags |= NodeFlags.ContainsThis; + } if (node.kind === SyntaxKind.SourceFile) { node.flags |= emitFlags; (node as SourceFile).endFlowNode = currentFlow; } - if (currentReturnTarget) { addAntecedent(currentReturnTarget, currentFlow); currentFlow = finishFlowLabel(currentReturnTarget); @@ -1051,12 +1055,15 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { currentExceptionTarget = saveExceptionTarget; activeLabelList = saveActiveLabelList; hasExplicitReturn = saveHasExplicitReturn; + seenThisKeyword = node.kind === SyntaxKind.ArrowFunction ? saveSeenThisKeyword || seenThisKeyword : saveSeenThisKeyword; } else if (containerFlags & ContainerFlags.IsInterface) { + const saveSeenThisKeyword = seenThisKeyword; seenThisKeyword = false; bindChildren(node); Debug.assertNotNode(node, isIdentifier); // ContainsThis cannot overlap with HasExtendedUnicodeEscape on Identifier node.flags = seenThisKeyword ? node.flags | NodeFlags.ContainsThis : node.flags & ~NodeFlags.ContainsThis; + seenThisKeyword = saveSeenThisKeyword; } else { bindChildren(node); @@ -2852,6 +2859,9 @@ function createBinder(): (file: SourceFile, options: CompilerOptions) => void { } // falls through case SyntaxKind.ThisKeyword: + if (node.kind === SyntaxKind.ThisKeyword) { + seenThisKeyword = true; + } // TODO: Why use `isExpression` here? both Identifier and ThisKeyword are expressions. if (currentFlow && (isExpression(node) || parent.kind === SyntaxKind.ShorthandPropertyAssignment)) { (node as Identifier | ThisExpression).flowNode = currentFlow; @@ -3833,6 +3843,8 @@ export function getContainerFlags(node: Node): ContainerFlags { // falls through case SyntaxKind.Constructor: case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ClassStaticBlockDeclaration: + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike; case SyntaxKind.MethodSignature: case SyntaxKind.CallSignature: case SyntaxKind.JSDocSignature: @@ -3840,12 +3852,11 @@ export function getContainerFlags(node: Node): ContainerFlags { case SyntaxKind.FunctionType: case SyntaxKind.ConstructSignature: case SyntaxKind.ConstructorType: - case SyntaxKind.ClassStaticBlockDeclaration: - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike; + return ContainerFlags.IsContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike; case SyntaxKind.JSDocImportTag: // treat as a container to prevent using an enclosing effective host, ensuring import bindings are scoped correctly - return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals; + return ContainerFlags.IsContainer | ContainerFlags.HasLocals; case SyntaxKind.FunctionExpression: case SyntaxKind.ArrowFunction: @@ -3853,8 +3864,6 @@ export function getContainerFlags(node: Node): ContainerFlags { case SyntaxKind.ModuleBlock: return ContainerFlags.IsControlFlowContainer; - case SyntaxKind.PropertyDeclaration: - return (node as PropertyDeclaration).initializer ? ContainerFlags.IsControlFlowContainer : 0; case SyntaxKind.CatchClause: case SyntaxKind.ForStatement: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 74663e107cc66..80ded1c22ffff 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -21143,9 +21143,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const { initializer } = node as JsxAttribute; return !!initializer && isContextSensitive(initializer); } - case SyntaxKind.JsxExpression: { + case SyntaxKind.JsxExpression: + case SyntaxKind.YieldExpression: { // It is possible to that node.expression is undefined (e.g
) - const { expression } = node as JsxExpression; + const { expression } = node as JsxExpression | YieldExpression; return !!expression && isContextSensitive(expression); } } @@ -21154,7 +21155,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function isContextSensitiveFunctionLikeDeclaration(node: FunctionLikeDeclaration): boolean { - return hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node); + return hasContextSensitiveParameters(node) || hasContextSensitiveReturnExpression(node) || !!(getFunctionFlags(node) & FunctionFlags.Generator && node.body && forEachYieldExpression(node.body as Block, isContextSensitive)); } function hasContextSensitiveReturnExpression(node: FunctionLikeDeclaration) { @@ -32629,7 +32630,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (inferenceContext && contextFlags! & ContextFlags.Signature && some(inferenceContext.inferences, hasInferenceCandidatesOrDefault)) { // 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. - return instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); + const type = instantiateInstantiableTypes(contextualType, inferenceContext.nonFixingMapper); + if (!(type.flags & TypeFlags.AnyOrUnknown)) { + return type; + } } if (inferenceContext?.returnMapper) { // For other purposes (e.g. determining whether to produce literal types) we only diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index cdf898ca8c3fc..5562f9f736397 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -2880,19 +2880,24 @@ export function forEachReturnStatement