From bd0ce7b357113270c473f5d537484280bf038df5 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 11 Dec 2022 17:30:20 -0800 Subject: [PATCH 01/14] `const` modifier on type parameters + revised contextual type logic --- src/compiler/checker.ts | 188 +++++++++++++++------------ src/compiler/diagnosticMessages.json | 4 + src/compiler/parser.ts | 8 +- src/compiler/types.ts | 2 - 4 files changed, 113 insertions(+), 89 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 3542a1e6c445f..b084107a93f97 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -2044,6 +2044,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let lastFlowNodeReachable: boolean; let flowTypeCache: Type[] | undefined; + const contextualTypeNodes: Node[] = []; + const contextualTypes: (Type | undefined)[] = []; + let contextualTypeCount = 0; + + let currentInferenceNode: Node | undefined; + let currentInferenceContext: InferenceContext | undefined; + const emptyStringType = getStringLiteralType(""); const zeroType = getNumberLiteralType(0); const zeroBigIntType = getBigIntLiteralType({ negative: false, base10Value: "0" }); @@ -13205,6 +13212,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined; } + function isConstTypeVariable(type: Type): boolean { + return !!(type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) || + type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType)); + } + function getConstraintOfIndexedAccess(type: IndexedAccessType) { return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined; } @@ -18971,13 +18983,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkExpressionForMutableLocationWithContextualType(next: Expression, sourcePropType: Type) { - next.contextualType = sourcePropType; - try { - return checkExpressionForMutableLocation(next, CheckMode.Contextual, sourcePropType); - } - finally { - next.contextualType = undefined; - } + pushContextualType(next, sourcePropType); + const result = checkExpressionForMutableLocation(next, CheckMode.Contextual); + popContextualType(); + return result; } type ElaborationIterator = IterableIterator<{ errorNode: Node, innerExpression: Expression | undefined, nameType: Type, errorMessage?: DiagnosticMessage | undefined }>; @@ -19219,19 +19228,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } // recreate a tuple from the elements, if possible // Since we're re-doing the expression type, we need to reapply the contextual type - const oldContext = node.contextualType; - node.contextualType = target; - try { - const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true); - node.contextualType = oldContext; - if (isTupleLikeType(tupleizedType)) { - return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, containingMessageChain, errorOutputContainer); - } - return false; - } - finally { - node.contextualType = oldContext; + pushContextualType(node, target); + const tupleizedType = checkArrayLiteral(node, CheckMode.Contextual, /*forceTuple*/ true); + popContextualType(); + if (isTupleLikeType(tupleizedType)) { + return elaborateElementwise(generateLimitedTupleElements(node, target), tupleizedType, target, relation, containingMessageChain, errorOutputContainer); } + return false; } function *generateObjectLiteralElements(node: ObjectLiteralExpression): ElaborationIterator { @@ -24435,7 +24438,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // all inferences were made to top-level occurrences of the type parameter, and // the type parameter has no constraint or its constraint includes no primitive or literal types, and // the type parameter was fixed during inference or does not occur at top-level in the return type. - const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter); + const primitiveConstraint = hasPrimitiveConstraint(inference.typeParameter) || isConstTypeVariable(inference.typeParameter); const widenLiteralTypes = !primitiveConstraint && inference.topLevel && (inference.isFixed || !isTypeParameterAtTopLevel(getReturnTypeOfSignature(signature), inference.typeParameter)); const baseCandidates = primitiveConstraint ? sameMap(candidates, getRegularTypeOfLiteralType) : @@ -28648,8 +28651,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We cannot answer semantic questions within a with block, do not proceed any further return undefined; } - if (node.contextualType) { - return node.contextualType; + const cached = getCachedContextualType(node); + if (cached) { + return cached; } const { parent } = node; switch (parent.kind) { @@ -28671,7 +28675,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getContextualTypeForArgument(parent as CallExpression | NewExpression, node); case SyntaxKind.TypeAssertionExpression: case SyntaxKind.AsExpression: - return isConstTypeReference((parent as AssertionExpression).type) ? tryFindWhenConstTypeReference(parent as AssertionExpression) : getTypeFromTypeNode((parent as AssertionExpression).type); + return isConstTypeReference((parent as AssertionExpression).type) ? getContextualType(parent as AssertionExpression, contextFlags) : getTypeFromTypeNode((parent as AssertionExpression).type); case SyntaxKind.BinaryExpression: return getContextualTypeForBinaryOperand(node, contextFlags); case SyntaxKind.PropertyAssignment: @@ -28693,7 +28697,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // 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 ? getContextualType(parent as ParenthesizedExpression, contextFlags) : - isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) ? tryFindWhenConstTypeReference(parent as ParenthesizedExpression) : + isJSDocTypeTag(tag) && isConstTypeReference(tag.typeExpression.type) ? getContextualType(parent as ParenthesizedExpression, contextFlags) : getTypeFromTypeNode(tag.typeExpression.type); } case SyntaxKind.NonNullExpression: @@ -28712,23 +28716,40 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return getContextualJsxElementAttributesType(parent as JsxOpeningLikeElement, contextFlags); } return undefined; + } - function tryFindWhenConstTypeReference(node: Expression) { - return getContextualType(node, contextFlags); + function pushContextualType(node: Node, type: Type | undefined) { + contextualTypeNodes[contextualTypeCount] = node; + contextualTypes[contextualTypeCount] = type; + contextualTypeCount++; + } + + function popContextualType() { + contextualTypeCount--; + } + + function getCachedContextualType(node: Node) { + for (let i = contextualTypeCount - 1; i >= 0; i--) { + if (node === contextualTypeNodes[i]) { + return contextualTypes[i]; + } } + return undefined; } function getInferenceContext(node: Node) { - const ancestor = findAncestor(node, n => !!n.inferenceContext); - return ancestor && ancestor.inferenceContext!; + return isNodeDescendantOf(node, currentInferenceNode) ? currentInferenceContext : undefined; } function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) { - if (isJsxOpeningElement(node) && node.parent.contextualType && contextFlags !== ContextFlags.Completions) { - // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit - // _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type - // (as below) instead! - return node.parent.contextualType; + if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) { + const cached = getCachedContextualType(node.parent); + if (cached) { + // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit + // _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type + // (as below) instead! + return cached; + } } return getContextualTypeForArgumentAtIndex(node, 0); } @@ -29058,9 +29079,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const elementCount = elements.length; const elementTypes: Type[] = []; const elementFlags: ElementFlags[] = []; - const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); + pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined)); const inDestructuringPattern = isAssignmentTarget(node); const inConstContext = isConstContext(node); + const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); + const inTupleContext = !!contextualType && someType(contextualType, isTupleLikeType); let hasOmittedExpression = false; for (let i = 0; i < elementCount; i++) { const e = elements[i]; @@ -29103,21 +29126,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { elementFlags.push(ElementFlags.Optional); } else { - const elementContextualType = getContextualTypeForElementExpression(contextualType, elementTypes.length); - const type = checkExpressionForMutableLocation(e, checkMode, elementContextualType, forceTuple); + const type = checkExpressionForMutableLocation(e, checkMode, forceTuple); elementTypes.push(addOptionality(type, /*isProperty*/ true, hasOmittedExpression)); elementFlags.push(hasOmittedExpression ? ElementFlags.Optional : ElementFlags.Required); - if (contextualType && someType(contextualType, isTupleLikeType) && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) { + if (inTupleContext && checkMode && checkMode & CheckMode.Inferential && !(checkMode & CheckMode.SkipContextSensitive) && isContextSensitive(e)) { const inferenceContext = getInferenceContext(node); Debug.assert(inferenceContext); // In CheckMode.Inferential we should always have an inference context addIntraExpressionInferenceSite(inferenceContext, e, type); } } } + popContextualType(); if (inDestructuringPattern) { return createTupleType(elementTypes, elementFlags); } - if (forceTuple || inConstContext || contextualType && someType(contextualType, isTupleLikeType)) { + if (forceTuple || inConstContext || inTupleContext) { return createArrayLiteralType(createTupleType(elementTypes, elementFlags, /*readonly*/ inConstContext)); } return createArrayLiteralType(createArrayType(elementTypes.length ? @@ -29239,6 +29262,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { let propertiesArray: Symbol[] = []; let spread: Type = emptyObjectType; + pushContextualType(node, getContextualType(node, /*contextFlags*/ undefined)); const contextualType = getApparentTypeOfContextualType(node, /*contextFlags*/ undefined); const contextualTypeHasPattern = contextualType && contextualType.pattern && (contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression); @@ -29399,6 +29423,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } propertiesArray.push(member); } + popContextualType(); // If object literal is contextually typed by the implied type of a binding pattern, augment the result // type with those properties for which the binding pattern specifies a default value. @@ -31607,6 +31632,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const types = []; const flags = []; const names = []; + const inConstContext = isConstTypeVariable(restType); for (let i = index; i < argCount; i++) { const arg = args[i]; if (isSpreadArgument(arg)) { @@ -31623,7 +31649,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { else { const contextualType = getIndexedAccessType(restType, getNumberLiteralType(i - index), AccessFlags.Contextual); const argType = checkExpressionWithContextualType(arg, contextualType, context, checkMode); - const hasPrimitiveContextualType = maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); + const hasPrimitiveContextualType = inConstContext || maybeTypeOfKind(contextualType, TypeFlags.Primitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping); types.push(hasPrimitiveContextualType ? getRegularTypeOfLiteralType(argType) : getWidenedLiteralType(argType)); flags.push(ElementFlags.Required); } @@ -31631,7 +31657,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { names.push((arg as SyntheticExpression).tupleNameSource!); } } - return createTupleType(types, flags, /*readonly*/ false, length(names) === length(types) ? names : undefined); + return createTupleType(types, flags, inConstContext, length(names) === length(types) ? names : undefined); } function checkTypeArguments(signature: Signature, typeArgumentNodes: readonly TypeNode[], reportErrors: boolean, headMessage?: DiagnosticMessage): Type[] | undefined { @@ -33087,7 +33113,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (isJsxIntrinsicIdentifier(node.tagName)) { const result = getIntrinsicAttributesTypeFromJsxOpeningLikeElement(node); const fakeSignature = createSignatureForJSXIntrinsic(node, result); - checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*mapper*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes); + checkTypeAssignableToAndOptionallyElaborate(checkExpressionWithContextualType(node.attributes, getEffectiveFirstArgumentForJsxSignature(fakeSignature, node), /*inferenceContext*/ undefined, CheckMode.Normal), result, node.tagName, node.attributes); if (length(node.typeArguments)) { forEach(node.typeArguments, checkSourceElement); diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), node.typeArguments!, Diagnostics.Expected_0_type_arguments_but_got_1, 0, length(node.typeArguments))); @@ -35971,32 +35997,27 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { } function checkExpressionWithContextualType(node: Expression, contextualType: Type, inferenceContext: InferenceContext | undefined, checkMode: CheckMode): Type { - const context = getContextNode(node); - const saveContextualType = context.contextualType; - const saveInferenceContext = context.inferenceContext; - try { - context.contextualType = contextualType; - context.inferenceContext = inferenceContext; - const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0)); - // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type - // parameters. This information is no longer needed after the call to checkExpression. - if (inferenceContext && inferenceContext.intraExpressionInferenceSites) { - inferenceContext.intraExpressionInferenceSites = undefined; - } - // 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. - const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ? - getRegularTypeOfLiteralType(type) : type; - return result; - } - finally { - // In the event our operation is canceled or some other exception occurs, reset the contextual type - // so that we do not accidentally hold onto an instance of the checker, as a Type created in the services layer - // may hold onto the checker that created it. - context.contextualType = saveContextualType; - context.inferenceContext = saveInferenceContext; - } + const contextNode = getContextNode(node); + pushContextualType(contextNode, contextualType); + const saveInferenceNode = currentInferenceNode; + const saveInferenceContext = currentInferenceContext; + currentInferenceNode = contextNode; + currentInferenceContext = inferenceContext; + const type = checkExpression(node, checkMode | CheckMode.Contextual | (inferenceContext ? CheckMode.Inferential : 0)); + // In CheckMode.Inferential we collect intra-expression inference sites to process before fixing any type + // parameters. This information is no longer needed after the call to checkExpression. + if (inferenceContext && inferenceContext.intraExpressionInferenceSites) { + inferenceContext.intraExpressionInferenceSites = undefined; + } + // 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. + const result = maybeTypeOfKind(type, TypeFlags.Literal) && isLiteralOfContextualType(type, instantiateContextualType(contextualType, node, /*contextFlags*/ undefined)) ? + getRegularTypeOfLiteralType(type) : type; + currentInferenceNode = saveInferenceNode; + currentInferenceContext = saveInferenceContext; + popContextualType(); + return result; } function checkExpressionCached(node: Expression | QualifiedName, checkMode?: CheckMode): Type { @@ -36105,15 +36126,21 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = node.parent; return isAssertionExpression(parent) && isConstTypeReference(parent.type) || isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) || + !isSpreadElement(node) && isConstTypeParameterContext(node) || (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) || (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) && isConstContext(parent.parent); } - function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, contextualType?: Type, forceTuple?: boolean): Type { + function isConstTypeParameterContext(node: Expression) { + const contextualType = getContextualType(node, ContextFlags.None); + return !!contextualType && someType(contextualType, isConstTypeVariable); + } + + function checkExpressionForMutableLocation(node: Expression, checkMode: CheckMode | undefined, forceTuple?: boolean): Type { const type = checkExpression(node, checkMode, forceTuple); return isConstContext(node) || isCommonJsExportedExpression(node) ? getRegularTypeOfLiteralType(type) : isTypeAssertion(node) ? type : - getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(arguments.length === 2 ? getContextualType(node, /*contextFlags*/ undefined) : contextualType, node, /*contextFlags*/ undefined)); + getWidenedLiteralLikeTypeForContextualType(type, instantiateContextualType(getContextualType(node, /*contextFlags*/ undefined), node, /*contextFlags*/ undefined)); } function checkPropertyAssignment(node: PropertyAssignment, checkMode?: CheckMode): Type { @@ -36360,18 +36387,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (links.contextFreeType) { return links.contextFreeType; } - const saveContextualType = node.contextualType; - node.contextualType = anyType; - try { - const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive); - return type; - } - finally { - // In the event our operation is canceled or some other exception occurs, reset the contextual type - // so that we do not accidentally hold onto an instance of the checker, as a Type created in the services layer - // may hold onto the checker that created it. - node.contextualType = saveContextualType; - } + pushContextualType(node, anyType); + const type = links.contextFreeType = checkExpression(node, CheckMode.SkipContextSensitive); + popContextualType(); + return type; } function checkExpression(node: Expression | QualifiedName, checkMode?: CheckMode, forceTuple?: boolean): Type { @@ -45392,16 +45411,19 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_an_index_signature, tokenToString(modifier.kind)); } } - if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword) { + if (modifier.kind !== SyntaxKind.InKeyword && modifier.kind !== SyntaxKind.OutKeyword && modifier.kind !== SyntaxKind.ConstKeyword) { if (node.kind === SyntaxKind.TypeParameter) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_cannot_appear_on_a_type_parameter, tokenToString(modifier.kind)); } } switch (modifier.kind) { case SyntaxKind.ConstKeyword: - if (node.kind !== SyntaxKind.EnumDeclaration) { + if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) { return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); } + if (node.kind === SyntaxKind.TypeParameter && !isFunctionLikeDeclaration(node.parent)) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_or_constructor, tokenToString(modifier.kind)); + } break; case SyntaxKind.OverrideKeyword: // If node.kind === SyntaxKind.Parameter, checkParameter reports an error if it's not a parameter property. diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index e146cce88c8cb..13c183c59bbfb 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -907,6 +907,10 @@ "category": "Error", "code": 1276 }, + "'{0}' modifier can only appear on a type parameter of a function or constructor": { + "category": "Error", + "code": 1277 + }, "'with' statements are not allowed in an async function block.": { "category": "Error", diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f1f8bd002e875..e74a31a13e62d 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2814,7 +2814,7 @@ namespace Parser { case ParsingContext.ArrayBindingElements: return token() === SyntaxKind.CommaToken || token() === SyntaxKind.DotDotDotToken || isBindingIdentifierOrPrivateIdentifierOrPattern(); case ParsingContext.TypeParameters: - return token() === SyntaxKind.InKeyword || isIdentifier(); + return token() === SyntaxKind.InKeyword || token() === SyntaxKind.ConstKeyword || isIdentifier(); case ParsingContext.ArrayLiteralMembers: switch (token()) { case SyntaxKind.CommaToken: @@ -3823,7 +3823,7 @@ namespace Parser { function parseTypeParameter(): TypeParameterDeclaration { const pos = getNodePos(); - const modifiers = parseModifiers(); + const modifiers = parseModifiers(/*permitConstAsModifier*/ true); const name = parseIdentifier(); let constraint: TypeNode | undefined; let expression: Expression | undefined; @@ -7742,10 +7742,10 @@ namespace Parser { * * In such situations, 'permitInvalidConstAsModifier' should be set to true. */ - function parseModifiers(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray | undefined { + function parseModifiers(permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray | undefined { const pos = getNodePos(); let list, modifier, hasSeenStatic = false; - while (modifier = tryParseModifier(permitInvalidConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) { + while (modifier = tryParseModifier(permitConstAsModifier, stopOnStartOfClassStaticBlock, hasSeenStatic)) { if (modifier.kind === SyntaxKind.StaticKeyword) hasSeenStatic = true; list = append(list, modifier); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index f8b0f5ef6dee2..e6ce574df4a94 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -902,8 +902,6 @@ export interface Node extends ReadonlyTextRange { /** @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 */ inferenceContext?: InferenceContext; // Inference context for contextual type } export interface JSDocContainer { From 7c48b0dd2b3d7d1cd6a64e9ece10104a7758d951 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 11 Dec 2022 17:31:07 -0800 Subject: [PATCH 02/14] Accept new baselines --- .../tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js b/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js index 12b3d134c26e8..14af3786d99ae 100644 --- a/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js +++ b/tests/baselines/reference/tsserver/plugins/getSupportedCodeFixes-can-be-proxied.js @@ -623,6 +623,7 @@ Info 32 [00:01:13.000] response: "1274", "1275", "1276", + "1277", "1300", "1309", "1313", @@ -1943,6 +1944,7 @@ Info 38 [00:01:19.000] response: "1274", "1275", "1276", + "1277", "1300", "1309", "1313", @@ -3175,6 +3177,7 @@ Info 40 [00:01:21.000] response: "1274", "1275", "1276", + "1277", "1300", "1309", "1313", From 88c71495a48c5e348a3103d925a7bf351e3993ac Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 11 Dec 2022 17:44:22 -0800 Subject: [PATCH 03/14] Fix modifier checking --- src/compiler/checker.ts | 4 ++-- src/compiler/diagnosticMessages.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b084107a93f97..12f4b92ed34ca 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -45421,8 +45421,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) { return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); } - if (node.kind === SyntaxKind.TypeParameter && !isFunctionLikeDeclaration(node.parent)) { - return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_or_constructor, tokenToString(modifier.kind)); + if (node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(node.parent) || isClassDeclaration(node.parent))) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, tokenToString(modifier.kind)); } break; case SyntaxKind.OverrideKeyword: diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 13c183c59bbfb..f9bab8053adad 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -907,7 +907,7 @@ "category": "Error", "code": 1276 }, - "'{0}' modifier can only appear on a type parameter of a function or constructor": { + "'{0}' modifier can only appear on a type parameter of a function, method or class": { "category": "Error", "code": 1277 }, From ccf252f8f3d07d90ca7d25cd62887cdc7fdf5b7a Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Sun, 11 Dec 2022 17:47:24 -0800 Subject: [PATCH 04/14] Add tests --- .../typeParameterConstModifiers.errors.txt | 68 +++++ .../reference/typeParameterConstModifiers.js | 86 ++++++ .../typeParameterConstModifiers.symbols | 217 ++++++++++++++ .../typeParameterConstModifiers.types | 264 ++++++++++++++++++ .../typeParameterConstModifiers.ts | 60 ++++ 5 files changed, 695 insertions(+) create mode 100644 tests/baselines/reference/typeParameterConstModifiers.errors.txt create mode 100644 tests/baselines/reference/typeParameterConstModifiers.js create mode 100644 tests/baselines/reference/typeParameterConstModifiers.symbols create mode 100644 tests/baselines/reference/typeParameterConstModifiers.types create mode 100644 tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts diff --git a/tests/baselines/reference/typeParameterConstModifiers.errors.txt b/tests/baselines/reference/typeParameterConstModifiers.errors.txt new file mode 100644 index 0000000000000..9d42083957bb6 --- /dev/null +++ b/tests/baselines/reference/typeParameterConstModifiers.errors.txt @@ -0,0 +1,68 @@ +tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(40,14): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class +tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(42,9): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class + + +==== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts (2 errors) ==== + declare function f1(x: T): T; + + const x11 = f1('a'); + const x12 = f1(['a', ['b', 'c']]); + const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + + declare function f2(x: T | undefined): T; + + const x21 = f2('a'); + const x22 = f2(['a', ['b', 'c']]); + const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + + declare function f3(x: T): T[]; + + const x31 = f3("hello"); + const x32 = f3("hello"); + + declare function f4(obj: [T, T]): T; + + const x41 = f4([[1, 'x'], [2, 'y']]); + const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]); + + declare function f5(obj: { x: T, y: T }): T; + + const x51 = f5({ x: [1, 'x'], y: [2, 'y'] }); + const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }); + + declare function f6(...args: T): T; + + const x61 = f6(1, 'b', { a: 1, b: 'x' }); + + class C1 { + constructor(x: T) {} + foo(x: U) { return x; } + } + + const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + const c72 = c71.foo(['a', ['b', 'c']]); + + interface I1 { x: T } // Error + ~~~~~ +!!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class + + type T1 = T; // Error + ~~~~~ +!!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class + + // Corrected repro from #51745 + + type Obj = { a: { b: { c: "123" } } }; + + type GetPath = + P extends readonly [] ? T : + P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath : + never; + + function set(obj: T, path: P, value: GetPath) {} + + declare let obj: Obj; + declare let value: "123"; + + set(obj, ['a', 'b', 'c'], value); + \ No newline at end of file diff --git a/tests/baselines/reference/typeParameterConstModifiers.js b/tests/baselines/reference/typeParameterConstModifiers.js new file mode 100644 index 0000000000000..b67c25273cfa6 --- /dev/null +++ b/tests/baselines/reference/typeParameterConstModifiers.js @@ -0,0 +1,86 @@ +//// [typeParameterConstModifiers.ts] +declare function f1(x: T): T; + +const x11 = f1('a'); +const x12 = f1(['a', ['b', 'c']]); +const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + +declare function f2(x: T | undefined): T; + +const x21 = f2('a'); +const x22 = f2(['a', ['b', 'c']]); +const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + +declare function f3(x: T): T[]; + +const x31 = f3("hello"); +const x32 = f3("hello"); + +declare function f4(obj: [T, T]): T; + +const x41 = f4([[1, 'x'], [2, 'y']]); +const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]); + +declare function f5(obj: { x: T, y: T }): T; + +const x51 = f5({ x: [1, 'x'], y: [2, 'y'] }); +const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }); + +declare function f6(...args: T): T; + +const x61 = f6(1, 'b', { a: 1, b: 'x' }); + +class C1 { + constructor(x: T) {} + foo(x: U) { return x; } +} + +const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +const c72 = c71.foo(['a', ['b', 'c']]); + +interface I1 { x: T } // Error + +type T1 = T; // Error + +// Corrected repro from #51745 + +type Obj = { a: { b: { c: "123" } } }; + +type GetPath = + P extends readonly [] ? T : + P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath : + never; + +function set(obj: T, path: P, value: GetPath) {} + +declare let obj: Obj; +declare let value: "123"; + +set(obj, ['a', 'b', 'c'], value); + + +//// [typeParameterConstModifiers.js] +"use strict"; +var x11 = f1('a'); +var x12 = f1(['a', ['b', 'c']]); +var x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +var x21 = f2('a'); +var x22 = f2(['a', ['b', 'c']]); +var x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +var x31 = f3("hello"); +var x32 = f3("hello"); +var x41 = f4([[1, 'x'], [2, 'y']]); +var x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]); +var x51 = f5({ x: [1, 'x'], y: [2, 'y'] }); +var x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }); +var x61 = f6(1, 'b', { a: 1, b: 'x' }); +var C1 = /** @class */ (function () { + function C1(x) { + } + C1.prototype.foo = function (x) { return x; }; + return C1; +}()); +var c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +var c72 = c71.foo(['a', ['b', 'c']]); +function set(obj, path, value) { } +set(obj, ['a', 'b', 'c'], value); diff --git a/tests/baselines/reference/typeParameterConstModifiers.symbols b/tests/baselines/reference/typeParameterConstModifiers.symbols new file mode 100644 index 0000000000000..628558a4be1f0 --- /dev/null +++ b/tests/baselines/reference/typeParameterConstModifiers.symbols @@ -0,0 +1,217 @@ +=== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts === +declare function f1(x: T): T; +>f1 : Symbol(f1, Decl(typeParameterConstModifiers.ts, 0, 0)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 0, 20)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 0, 29)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 0, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 0, 20)) + +const x11 = f1('a'); +>x11 : Symbol(x11, Decl(typeParameterConstModifiers.ts, 2, 5)) +>f1 : Symbol(f1, Decl(typeParameterConstModifiers.ts, 0, 0)) + +const x12 = f1(['a', ['b', 'c']]); +>x12 : Symbol(x12, Decl(typeParameterConstModifiers.ts, 3, 5)) +>f1 : Symbol(f1, Decl(typeParameterConstModifiers.ts, 0, 0)) + +const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>x13 : Symbol(x13, Decl(typeParameterConstModifiers.ts, 4, 5)) +>f1 : Symbol(f1, Decl(typeParameterConstModifiers.ts, 0, 0)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 4, 16)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 4, 22)) +>d : Symbol(d, Decl(typeParameterConstModifiers.ts, 4, 30)) +>f : Symbol(f, Decl(typeParameterConstModifiers.ts, 4, 50)) + +declare function f2(x: T | undefined): T; +>f2 : Symbol(f2, Decl(typeParameterConstModifiers.ts, 4, 64)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 6, 20)) +>U : Symbol(U, Decl(typeParameterConstModifiers.ts, 6, 28)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 6, 32)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 6, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 6, 20)) + +const x21 = f2('a'); +>x21 : Symbol(x21, Decl(typeParameterConstModifiers.ts, 8, 5)) +>f2 : Symbol(f2, Decl(typeParameterConstModifiers.ts, 4, 64)) + +const x22 = f2(['a', ['b', 'c']]); +>x22 : Symbol(x22, Decl(typeParameterConstModifiers.ts, 9, 5)) +>f2 : Symbol(f2, Decl(typeParameterConstModifiers.ts, 4, 64)) + +const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>x23 : Symbol(x23, Decl(typeParameterConstModifiers.ts, 10, 5)) +>f2 : Symbol(f2, Decl(typeParameterConstModifiers.ts, 4, 64)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 10, 16)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 10, 22)) +>d : Symbol(d, Decl(typeParameterConstModifiers.ts, 10, 30)) +>f : Symbol(f, Decl(typeParameterConstModifiers.ts, 10, 50)) + +declare function f3(x: T): T[]; +>f3 : Symbol(f3, Decl(typeParameterConstModifiers.ts, 10, 64)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 12, 20)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 12, 29)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 12, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 12, 20)) + +const x31 = f3("hello"); +>x31 : Symbol(x31, Decl(typeParameterConstModifiers.ts, 14, 5)) +>f3 : Symbol(f3, Decl(typeParameterConstModifiers.ts, 10, 64)) + +const x32 = f3("hello"); +>x32 : Symbol(x32, Decl(typeParameterConstModifiers.ts, 15, 5)) +>f3 : Symbol(f3, Decl(typeParameterConstModifiers.ts, 10, 64)) + +declare function f4(obj: [T, T]): T; +>f4 : Symbol(f4, Decl(typeParameterConstModifiers.ts, 15, 24)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 17, 20)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 17, 29)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 17, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 17, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 17, 20)) + +const x41 = f4([[1, 'x'], [2, 'y']]); +>x41 : Symbol(x41, Decl(typeParameterConstModifiers.ts, 19, 5)) +>f4 : Symbol(f4, Decl(typeParameterConstModifiers.ts, 15, 24)) + +const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]); +>x42 : Symbol(x42, Decl(typeParameterConstModifiers.ts, 20, 5)) +>f4 : Symbol(f4, Decl(typeParameterConstModifiers.ts, 15, 24)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 20, 17)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 20, 23)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 20, 35)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 20, 41)) + +declare function f5(obj: { x: T, y: T }): T; +>f5 : Symbol(f5, Decl(typeParameterConstModifiers.ts, 20, 53)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 22, 20)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 22, 29)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 22, 35)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 22, 20)) +>y : Symbol(y, Decl(typeParameterConstModifiers.ts, 22, 41)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 22, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 22, 20)) + +const x51 = f5({ x: [1, 'x'], y: [2, 'y'] }); +>x51 : Symbol(x51, Decl(typeParameterConstModifiers.ts, 24, 5)) +>f5 : Symbol(f5, Decl(typeParameterConstModifiers.ts, 20, 53)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 24, 16)) +>y : Symbol(y, Decl(typeParameterConstModifiers.ts, 24, 29)) + +const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }); +>x52 : Symbol(x52, Decl(typeParameterConstModifiers.ts, 25, 5)) +>f5 : Symbol(f5, Decl(typeParameterConstModifiers.ts, 20, 53)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 25, 16)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 25, 21)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 25, 27)) +>y : Symbol(y, Decl(typeParameterConstModifiers.ts, 25, 37)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 25, 42)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 25, 48)) + +declare function f6(...args: T): T; +>f6 : Symbol(f6, Decl(typeParameterConstModifiers.ts, 25, 61)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 27, 20)) +>args : Symbol(args, Decl(typeParameterConstModifiers.ts, 27, 56)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 27, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 27, 20)) + +const x61 = f6(1, 'b', { a: 1, b: 'x' }); +>x61 : Symbol(x61, Decl(typeParameterConstModifiers.ts, 29, 5)) +>f6 : Symbol(f6, Decl(typeParameterConstModifiers.ts, 25, 61)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 29, 24)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 29, 30)) + +class C1 { +>C1 : Symbol(C1, Decl(typeParameterConstModifiers.ts, 29, 41)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 31, 9)) + + constructor(x: T) {} +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 32, 16)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 31, 9)) + + foo(x: U) { return x; } +>foo : Symbol(C1.foo, Decl(typeParameterConstModifiers.ts, 32, 24)) +>U : Symbol(U, Decl(typeParameterConstModifiers.ts, 33, 8)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 33, 17)) +>U : Symbol(U, Decl(typeParameterConstModifiers.ts, 33, 8)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 33, 17)) +} + +const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>c71 : Symbol(c71, Decl(typeParameterConstModifiers.ts, 36, 5)) +>C1 : Symbol(C1, Decl(typeParameterConstModifiers.ts, 29, 41)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 36, 20)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 36, 26)) +>d : Symbol(d, Decl(typeParameterConstModifiers.ts, 36, 34)) +>f : Symbol(f, Decl(typeParameterConstModifiers.ts, 36, 54)) + +const c72 = c71.foo(['a', ['b', 'c']]); +>c72 : Symbol(c72, Decl(typeParameterConstModifiers.ts, 37, 5)) +>c71.foo : Symbol(C1.foo, Decl(typeParameterConstModifiers.ts, 32, 24)) +>c71 : Symbol(c71, Decl(typeParameterConstModifiers.ts, 36, 5)) +>foo : Symbol(C1.foo, Decl(typeParameterConstModifiers.ts, 32, 24)) + +interface I1 { x: T } // Error +>I1 : Symbol(I1, Decl(typeParameterConstModifiers.ts, 37, 39)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 39, 13)) +>x : Symbol(I1.x, Decl(typeParameterConstModifiers.ts, 39, 23)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 39, 13)) + +type T1 = T; // Error +>T1 : Symbol(T1, Decl(typeParameterConstModifiers.ts, 39, 30)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 41, 8)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 41, 8)) + +// Corrected repro from #51745 + +type Obj = { a: { b: { c: "123" } } }; +>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 41, 21)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 45, 12)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 45, 17)) +>c : Symbol(c, Decl(typeParameterConstModifiers.ts, 45, 22)) + +type GetPath = +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 45, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 47, 15)) + + P extends readonly [] ? T : +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 47, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 13)) + + P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath : +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 47, 15)) +>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 49, 29)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 13)) +>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 49, 57)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 45, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 13)) +>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 49, 29)) +>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 49, 57)) + + never; + +function set(obj: T, path: P, value: GetPath) {} +>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 50, 10)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 52, 51)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) +>path : Symbol(path, Decl(typeParameterConstModifiers.ts, 52, 58)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 52, 67)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 45, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) + +declare let obj: Obj; +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 54, 11)) +>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 41, 21)) + +declare let value: "123"; +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 55, 11)) + +set(obj, ['a', 'b', 'c'], value); +>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 50, 10)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 54, 11)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 55, 11)) + diff --git a/tests/baselines/reference/typeParameterConstModifiers.types b/tests/baselines/reference/typeParameterConstModifiers.types new file mode 100644 index 0000000000000..af172314e76e4 --- /dev/null +++ b/tests/baselines/reference/typeParameterConstModifiers.types @@ -0,0 +1,264 @@ +=== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts === +declare function f1(x: T): T; +>f1 : (x: T) => T +>x : T + +const x11 = f1('a'); +>x11 : "a" +>f1('a') : "a" +>f1 : (x: T) => T +>'a' : "a" + +const x12 = f1(['a', ['b', 'c']]); +>x12 : readonly ["a", readonly ["b", "c"]] +>f1(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]] +>f1 : (x: T) => T +>['a', ['b', 'c']] : ["a", ["b", "c"]] +>'a' : "a" +>['b', 'c'] : ["b", "c"] +>'b' : "b" +>'c' : "c" + +const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>x13 : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } +>f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } +>f1 : (x: T) => T +>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; } +>a : 1 +>1 : 1 +>b : "c" +>"c" : "c" +>d : ["e", 2, true, { f: "g"; }] +>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }] +>"e" : "e" +>2 : 2 +>true : true +>{ f: "g" } : { f: "g"; } +>f : "g" +>"g" : "g" + +declare function f2(x: T | undefined): T; +>f2 : (x: T | undefined) => T +>x : T | undefined + +const x21 = f2('a'); +>x21 : "a" +>f2('a') : "a" +>f2 : (x: T | undefined) => T +>'a' : "a" + +const x22 = f2(['a', ['b', 'c']]); +>x22 : readonly ["a", readonly ["b", "c"]] +>f2(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]] +>f2 : (x: T | undefined) => T +>['a', ['b', 'c']] : ["a", ["b", "c"]] +>'a' : "a" +>['b', 'c'] : ["b", "c"] +>'b' : "b" +>'c' : "c" + +const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>x23 : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } +>f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } +>f2 : (x: T | undefined) => T +>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; } +>a : 1 +>1 : 1 +>b : "c" +>"c" : "c" +>d : ["e", 2, true, { f: "g"; }] +>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }] +>"e" : "e" +>2 : 2 +>true : true +>{ f: "g" } : { f: "g"; } +>f : "g" +>"g" : "g" + +declare function f3(x: T): T[]; +>f3 : (x: T) => T[] +>x : T + +const x31 = f3("hello"); +>x31 : "hello"[] +>f3("hello") : "hello"[] +>f3 : (x: T) => T[] +>"hello" : "hello" + +const x32 = f3("hello"); +>x32 : "hello"[] +>f3("hello") : "hello"[] +>f3 : (x: T) => T[] +>"hello" : "hello" + +declare function f4(obj: [T, T]): T; +>f4 : (obj: [T, T]) => T +>obj : [T, T] + +const x41 = f4([[1, 'x'], [2, 'y']]); +>x41 : readonly [1, "x"] | readonly [2, "y"] +>f4([[1, 'x'], [2, 'y']]) : readonly [1, "x"] | readonly [2, "y"] +>f4 : (obj: [T, T]) => T +>[[1, 'x'], [2, 'y']] : [[1, "x"], [2, "y"]] +>[1, 'x'] : [1, "x"] +>1 : 1 +>'x' : "x" +>[2, 'y'] : [2, "y"] +>2 : 2 +>'y' : "y" + +const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]); +>x42 : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } +>f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]) : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } +>f4 : (obj: [T, T]) => T +>[{ a: 1, b: 'x' }, { a: 2, b: 'y' }] : [{ a: 1; b: "x"; }, { a: 2; b: "y"; }] +>{ a: 1, b: 'x' } : { a: 1; b: "x"; } +>a : 1 +>1 : 1 +>b : "x" +>'x' : "x" +>{ a: 2, b: 'y' } : { a: 2; b: "y"; } +>a : 2 +>2 : 2 +>b : "y" +>'y' : "y" + +declare function f5(obj: { x: T, y: T }): T; +>f5 : (obj: { x: T; y: T;}) => T +>obj : { x: T; y: T; } +>x : T +>y : T + +const x51 = f5({ x: [1, 'x'], y: [2, 'y'] }); +>x51 : readonly [1, "x"] | readonly [2, "y"] +>f5({ x: [1, 'x'], y: [2, 'y'] }) : readonly [1, "x"] | readonly [2, "y"] +>f5 : (obj: { x: T; y: T; }) => T +>{ x: [1, 'x'], y: [2, 'y'] } : { x: [1, "x"]; y: [2, "y"]; } +>x : [1, "x"] +>[1, 'x'] : [1, "x"] +>1 : 1 +>'x' : "x" +>y : [2, "y"] +>[2, 'y'] : [2, "y"] +>2 : 2 +>'y' : "y" + +const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }); +>x52 : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } +>f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }) : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } +>f5 : (obj: { x: T; y: T; }) => T +>{ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } } : { x: { a: 1; b: "x"; }; y: { a: 2; b: "y"; }; } +>x : { a: 1; b: "x"; } +>{ a: 1, b: 'x' } : { a: 1; b: "x"; } +>a : 1 +>1 : 1 +>b : "x" +>'x' : "x" +>y : { a: 2; b: "y"; } +>{ a: 2, b: 'y' } : { a: 2; b: "y"; } +>a : 2 +>2 : 2 +>b : "y" +>'y' : "y" + +declare function f6(...args: T): T; +>f6 : (...args: T) => T +>args : T + +const x61 = f6(1, 'b', { a: 1, b: 'x' }); +>x61 : readonly [1, "b", { readonly a: 1; readonly b: "x"; }] +>f6(1, 'b', { a: 1, b: 'x' }) : readonly [1, "b", { readonly a: 1; readonly b: "x"; }] +>f6 : (...args: T) => T +>1 : 1 +>'b' : "b" +>{ a: 1, b: 'x' } : { a: 1; b: "x"; } +>a : 1 +>1 : 1 +>b : "x" +>'x' : "x" + +class C1 { +>C1 : C1 + + constructor(x: T) {} +>x : T + + foo(x: U) { return x; } +>foo : (x: U) => U +>x : U +>x : U +} + +const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +>c71 : C1<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }> +>new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : C1<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }> +>C1 : typeof C1 +>{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; } +>a : 1 +>1 : 1 +>b : "c" +>"c" : "c" +>d : ["e", 2, true, { f: "g"; }] +>["e", 2, true, { f: "g" }] : ["e", 2, true, { f: "g"; }] +>"e" : "e" +>2 : 2 +>true : true +>{ f: "g" } : { f: "g"; } +>f : "g" +>"g" : "g" + +const c72 = c71.foo(['a', ['b', 'c']]); +>c72 : readonly ["a", readonly ["b", "c"]] +>c71.foo(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]] +>c71.foo : (x: U) => U +>c71 : C1<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }> +>foo : (x: U) => U +>['a', ['b', 'c']] : ["a", ["b", "c"]] +>'a' : "a" +>['b', 'c'] : ["b", "c"] +>'b' : "b" +>'c' : "c" + +interface I1 { x: T } // Error +>x : T + +type T1 = T; // Error +>T1 : T + +// Corrected repro from #51745 + +type Obj = { a: { b: { c: "123" } } }; +>Obj : { a: { b: { c: "123"; };}; } +>a : { b: { c: "123";}; } +>b : { c: "123"; } +>c : "123" + +type GetPath = +>GetPath : GetPath + + P extends readonly [] ? T : + P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath : + never; + +function set(obj: T, path: P, value: GetPath) {} +>set : (obj: T, path: P, value: GetPath) => void +>obj : T +>path : P +>value : GetPath + +declare let obj: Obj; +>obj : Obj + +declare let value: "123"; +>value : "123" + +set(obj, ['a', 'b', 'c'], value); +>set(obj, ['a', 'b', 'c'], value) : void +>set : (obj: T, path: P, value: GetPath) => void +>obj : Obj +>['a', 'b', 'c'] : ["a", "b", "c"] +>'a' : "a" +>'b' : "b" +>'c' : "c" +>value : "123" + diff --git a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts new file mode 100644 index 0000000000000..8ce99d87350f9 --- /dev/null +++ b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts @@ -0,0 +1,60 @@ +// @strict: true + +declare function f1(x: T): T; + +const x11 = f1('a'); +const x12 = f1(['a', ['b', 'c']]); +const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + +declare function f2(x: T | undefined): T; + +const x21 = f2('a'); +const x22 = f2(['a', ['b', 'c']]); +const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); + +declare function f3(x: T): T[]; + +const x31 = f3("hello"); +const x32 = f3("hello"); + +declare function f4(obj: [T, T]): T; + +const x41 = f4([[1, 'x'], [2, 'y']]); +const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]); + +declare function f5(obj: { x: T, y: T }): T; + +const x51 = f5({ x: [1, 'x'], y: [2, 'y'] }); +const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }); + +declare function f6(...args: T): T; + +const x61 = f6(1, 'b', { a: 1, b: 'x' }); + +class C1 { + constructor(x: T) {} + foo(x: U) { return x; } +} + +const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); +const c72 = c71.foo(['a', ['b', 'c']]); + +interface I1 { x: T } // Error + +type T1 = T; // Error + +// Corrected repro from #51745 + +type Obj = { a: { b: { c: "123" } } }; + +type GetPath = + P extends readonly [] ? T : + P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath : + never; + +function set(obj: T, path: P, value: GetPath) {} + +declare let obj: Obj; +declare let value: "123"; + +set(obj, ['a', 'b', 'c'], value); From f8fd1fd29f7975fcc3aeac8675c2cb107da33065 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Mon, 12 Dec 2022 15:58:39 -0800 Subject: [PATCH 05/14] Cache isConstTypeVariable check --- src/compiler/checker.ts | 17 +++++++++++------ src/compiler/types.ts | 12 +++++++----- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 12f4b92ed34ca..b947e842e3148 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13212,11 +13212,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined; } - function isConstTypeVariable(type: Type): boolean { - return !!(type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) || - type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType)); - } - function getConstraintOfIndexedAccess(type: IndexedAccessType) { return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined; } @@ -17037,6 +17032,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(getGenericObjectFlags(type) & ObjectFlags.IsGenericIndexType); } + function isConstTypeVariable(type: Type): boolean { + return !!(getGenericObjectFlags(type) & ObjectFlags.IsConstTypeVariable); + } + + function isConstTypeVariableWorker(type: Type): boolean { + return !!(type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) || + type.flags & TypeFlags.IndexedAccess && isConstTypeVariableWorker((type as IndexedAccessType).objectType)); + } + function getGenericObjectFlags(type: Type): ObjectFlags { if (type.flags & TypeFlags.UnionOrIntersection) { if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { @@ -17053,7 +17057,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; } return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) | - (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); + (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0) | + (isConstTypeVariableWorker(type) ? ObjectFlags.IsConstTypeVariable : 0); } function getSimplifiedType(type: Type, writing: boolean): Type { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index e6ce574df4a94..48dfb897de2b8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5922,22 +5922,24 @@ export const enum ObjectFlags { /** @internal */ IsGenericIndexType = 1 << 23, // Union or intersection contains generic index type /** @internal */ + IsConstTypeVariable = 1 << 24, // Union or intersection contains const type parameter + /** @internal */ IsGenericType = IsGenericObjectType | IsGenericIndexType, // Flags that require TypeFlags.Union /** @internal */ - ContainsIntersections = 1 << 24, // Union contains intersections + ContainsIntersections = 1 << 25, // Union contains intersections /** @internal */ - IsUnknownLikeUnionComputed = 1 << 25, // IsUnknownLikeUnion flag has been computed + IsUnknownLikeUnionComputed = 1 << 26, // IsUnknownLikeUnion flag has been computed /** @internal */ - IsUnknownLikeUnion = 1 << 26, // Union of null, undefined, and empty object type + IsUnknownLikeUnion = 1 << 27, // Union of null, undefined, and empty object type /** @internal */ // Flags that require TypeFlags.Intersection /** @internal */ - IsNeverIntersectionComputed = 1 << 24, // IsNeverLike flag has been computed + IsNeverIntersectionComputed = 1 << 25, // IsNeverLike flag has been computed /** @internal */ - IsNeverIntersection = 1 << 25, // Intersection reduces to never + IsNeverIntersection = 1 << 26, // Intersection reduces to never } /** @internal */ From c3fcf6e53de24225ebada9117af51612fce7f6e6 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Dec 2022 06:45:25 -0800 Subject: [PATCH 06/14] Revert "Cache isConstTypeVariable check" This reverts commit f8fd1fd29f7975fcc3aeac8675c2cb107da33065. --- src/compiler/checker.ts | 17 ++++++----------- src/compiler/types.ts | 12 +++++------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b947e842e3148..12f4b92ed34ca 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -13212,6 +13212,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined; } + function isConstTypeVariable(type: Type): boolean { + return !!(type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) || + type.flags & TypeFlags.IndexedAccess && isConstTypeVariable((type as IndexedAccessType).objectType)); + } + function getConstraintOfIndexedAccess(type: IndexedAccessType) { return hasNonCircularBaseConstraint(type) ? getConstraintFromIndexedAccess(type) : undefined; } @@ -17032,15 +17037,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return !!(getGenericObjectFlags(type) & ObjectFlags.IsGenericIndexType); } - function isConstTypeVariable(type: Type): boolean { - return !!(getGenericObjectFlags(type) & ObjectFlags.IsConstTypeVariable); - } - - function isConstTypeVariableWorker(type: Type): boolean { - return !!(type.flags & TypeFlags.TypeParameter && some((type as TypeParameter).symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Const)) || - type.flags & TypeFlags.IndexedAccess && isConstTypeVariableWorker((type as IndexedAccessType).objectType)); - } - function getGenericObjectFlags(type: Type): ObjectFlags { if (type.flags & TypeFlags.UnionOrIntersection) { if (!((type as UnionOrIntersectionType).objectFlags & ObjectFlags.IsGenericTypeComputed)) { @@ -17057,8 +17053,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return (type as SubstitutionType).objectFlags & ObjectFlags.IsGenericType; } return (type.flags & TypeFlags.InstantiableNonPrimitive || isGenericMappedType(type) || isGenericTupleType(type) ? ObjectFlags.IsGenericObjectType : 0) | - (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0) | - (isConstTypeVariableWorker(type) ? ObjectFlags.IsConstTypeVariable : 0); + (type.flags & (TypeFlags.InstantiableNonPrimitive | TypeFlags.Index | TypeFlags.TemplateLiteral | TypeFlags.StringMapping) && !isPatternLiteralType(type) ? ObjectFlags.IsGenericIndexType : 0); } function getSimplifiedType(type: Type, writing: boolean): Type { diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 48dfb897de2b8..e6ce574df4a94 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5922,24 +5922,22 @@ export const enum ObjectFlags { /** @internal */ IsGenericIndexType = 1 << 23, // Union or intersection contains generic index type /** @internal */ - IsConstTypeVariable = 1 << 24, // Union or intersection contains const type parameter - /** @internal */ IsGenericType = IsGenericObjectType | IsGenericIndexType, // Flags that require TypeFlags.Union /** @internal */ - ContainsIntersections = 1 << 25, // Union contains intersections + ContainsIntersections = 1 << 24, // Union contains intersections /** @internal */ - IsUnknownLikeUnionComputed = 1 << 26, // IsUnknownLikeUnion flag has been computed + IsUnknownLikeUnionComputed = 1 << 25, // IsUnknownLikeUnion flag has been computed /** @internal */ - IsUnknownLikeUnion = 1 << 27, // Union of null, undefined, and empty object type + IsUnknownLikeUnion = 1 << 26, // Union of null, undefined, and empty object type /** @internal */ // Flags that require TypeFlags.Intersection /** @internal */ - IsNeverIntersectionComputed = 1 << 25, // IsNeverLike flag has been computed + IsNeverIntersectionComputed = 1 << 24, // IsNeverLike flag has been computed /** @internal */ - IsNeverIntersection = 1 << 26, // Intersection reduces to never + IsNeverIntersection = 1 << 25, // Intersection reduces to never } /** @internal */ From 0507bf0e9b86a6cbbd9d1018e0cbe313068d396e Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Dec 2022 07:19:26 -0800 Subject: [PATCH 07/14] Fewer isConstTypeParameterContext checks --- src/compiler/checker.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 12f4b92ed34ca..08e331408c1d7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -33592,12 +33592,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { op === SyntaxKind.PlusToken && arg.kind === SyntaxKind.NumericLiteral; case SyntaxKind.PropertyAccessExpression: case SyntaxKind.ElementAccessExpression: - const expr = (node as PropertyAccessExpression | ElementAccessExpression).expression; - let symbol = getTypeOfNode(expr).symbol; - if (symbol && symbol.flags & SymbolFlags.Alias) { - symbol = resolveAlias(symbol); - } - return !!(symbol && getAllSymbolFlags(symbol) & SymbolFlags.Enum); + const expr = skipParentheses((node as PropertyAccessExpression | ElementAccessExpression).expression); + const symbol = isEntityNameExpression(expr) ? resolveEntityName(expr, SymbolFlags.Value, /*ignoreErrors*/ true) : undefined; + return !!(symbol && symbol.flags & SymbolFlags.Enum); } return false; } @@ -36126,7 +36123,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parent = node.parent; return isAssertionExpression(parent) && isConstTypeReference(parent.type) || isJSDocTypeAssertion(parent) && isConstTypeReference(getJSDocTypeAssertionType(parent)) || - !isSpreadElement(node) && isConstTypeParameterContext(node) || + isValidConstAssertionArgument(node) && isConstTypeParameterContext(node) || (isParenthesizedExpression(parent) || isArrayLiteralExpression(parent) || isSpreadElement(parent)) && isConstContext(parent) || (isPropertyAssignment(parent) || isShorthandPropertyAssignment(parent) || isTemplateSpan(parent)) && isConstContext(parent.parent); } From b56d187c4a971b35da17999b68670816d57abfc7 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Dec 2022 08:38:57 -0800 Subject: [PATCH 08/14] Pay attention to cached `undefined` contextual type --- src/compiler/checker.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 08e331408c1d7..a7f92f3aa7757 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -28651,9 +28651,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // We cannot answer semantic questions within a with block, do not proceed any further return undefined; } - const cached = getCachedContextualType(node); - if (cached) { - return cached; + const index = findContextualNode(node); + if (index >= 0) { + return contextualTypes[index]; } const { parent } = node; switch (parent.kind) { @@ -28728,13 +28728,13 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { contextualTypeCount--; } - function getCachedContextualType(node: Node) { + function findContextualNode(node: Node) { for (let i = contextualTypeCount - 1; i >= 0; i--) { if (node === contextualTypeNodes[i]) { - return contextualTypes[i]; + return i; } } - return undefined; + return -1; } function getInferenceContext(node: Node) { @@ -28743,12 +28743,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function getContextualJsxElementAttributesType(node: JsxOpeningLikeElement, contextFlags: ContextFlags | undefined) { if (isJsxOpeningElement(node) && contextFlags !== ContextFlags.Completions) { - const cached = getCachedContextualType(node.parent); - if (cached) { + const index = findContextualNode(node.parent); + if (index >= 0) { // Contextually applied type is moved from attributes up to the outer jsx attributes so when walking up from the children they get hit // _However_ to hit them from the _attributes_ we must look for them here; otherwise we'll used the declared type // (as below) instead! - return cached; + return contextualTypes[index]; } } return getContextualTypeForArgumentAtIndex(node, 0); From 54f649d3d6d49547a8184875eff8fa975368caec Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Dec 2022 11:41:59 -0800 Subject: [PATCH 09/14] Allow `const` modifier in more places + properly print back --- src/compiler/checker.ts | 15 +-- .../typeParameterConstModifiers.errors.txt | 5 + .../reference/typeParameterConstModifiers.js | 5 + .../typeParameterConstModifiers.symbols | 96 ++++++++++++------- .../typeParameterConstModifiers.types | 64 ++++++++----- .../typeParameterConstModifiers.ts | 5 + 6 files changed, 125 insertions(+), 65 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a7f92f3aa7757..36c4981d67130 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1012,6 +1012,7 @@ import { WideningContext, WithStatement, YieldExpression, + isConstructSignatureDeclaration, } from "./_namespaces/ts"; import * as performance from "./_namespaces/ts.performance"; import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers"; @@ -7181,7 +7182,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function typeParameterToDeclarationWithConstraint(type: TypeParameter, context: NodeBuilderContext, constraintNode: TypeNode | undefined): TypeParameterDeclaration { const savedContextFlags = context.flags; context.flags &= ~NodeBuilderFlags.WriteTypeParametersInQualifiedName; // Avoids potential infinite loop when building for a claimspace with a generic - const modifiers = factory.createModifiersFromModifierFlags(getVarianceModifiers(type)); + const modifiers = factory.createModifiersFromModifierFlags(getTypeParameterModifiers(type)); const name = typeParameterToName(type, context); const defaultParameter = getDefaultFromTypeParameter(type); const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter, context); @@ -22117,7 +22118,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { links.variances = emptyArray; const variances = []; for (const tp of typeParameters) { - const modifiers = getVarianceModifiers(tp); + const modifiers = getTypeParameterModifiers(tp); let variance = modifiers & ModifierFlags.Out ? modifiers & ModifierFlags.In ? VarianceFlags.Invariant : VarianceFlags.Covariant : modifiers & ModifierFlags.In ? VarianceFlags.Contravariant : undefined; @@ -22175,9 +22176,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return markerTypes.has(getTypeId(type)); } - function getVarianceModifiers(tp: TypeParameter): ModifierFlags { - return (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.In)) ? ModifierFlags.In : 0) | - (some(tp.symbol?.declarations, d => hasSyntacticModifier(d, ModifierFlags.Out)) ? ModifierFlags.Out: 0); + function getTypeParameterModifiers(tp: TypeParameter): ModifierFlags { + return reduceLeft(tp.symbol?.declarations, (modifiers, d) => modifiers | getEffectiveModifierFlags(d), ModifierFlags.None) & (ModifierFlags.In | ModifierFlags.Out | ModifierFlags.Const); } // Return true if the given type reference has a 'void' type argument for a covariant type parameter. @@ -36587,7 +36587,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { function checkTypeParameterDeferred(node: TypeParameterDeclaration) { if (isInterfaceDeclaration(node.parent) || isClassLike(node.parent) || isTypeAliasDeclaration(node.parent)) { const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node)); - const modifiers = getVarianceModifiers(typeParameter); + const modifiers = getTypeParameterModifiers(typeParameter) & (ModifierFlags.In | ModifierFlags.Out); if (modifiers) { const symbol = getSymbolOfNode(node.parent); if (isTypeAliasDeclaration(node.parent) && !(getObjectFlags(getDeclaredTypeOfSymbol(symbol)) & (ObjectFlags.Anonymous | ObjectFlags.Mapped))) { @@ -45418,7 +45418,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) { return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); } - if (node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(node.parent) || isClassDeclaration(node.parent))) { + if (node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(node.parent) || isClassDeclaration(node.parent) || isFunctionTypeNode(node.parent) || + isConstructorTypeNode(node.parent) || isCallSignatureDeclaration(node.parent) || isConstructSignatureDeclaration(node.parent))) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, tokenToString(modifier.kind)); } break; diff --git a/tests/baselines/reference/typeParameterConstModifiers.errors.txt b/tests/baselines/reference/typeParameterConstModifiers.errors.txt index 9d42083957bb6..71dcb57f6d3de 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.errors.txt +++ b/tests/baselines/reference/typeParameterConstModifiers.errors.txt @@ -50,6 +50,11 @@ tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterCon ~~~~~ !!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class + type T2 = (x: T) => T; + type T3 = { (x: T): T }; + type T4 = new (x: T) => T; + type T5 = { new (x: T): T }; + // Corrected repro from #51745 type Obj = { a: { b: { c: "123" } } }; diff --git a/tests/baselines/reference/typeParameterConstModifiers.js b/tests/baselines/reference/typeParameterConstModifiers.js index b67c25273cfa6..b907180d47f40 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.js +++ b/tests/baselines/reference/typeParameterConstModifiers.js @@ -42,6 +42,11 @@ interface I1 { x: T } // Error type T1 = T; // Error +type T2 = (x: T) => T; +type T3 = { (x: T): T }; +type T4 = new (x: T) => T; +type T5 = { new (x: T): T }; + // Corrected repro from #51745 type Obj = { a: { b: { c: "123" } } }; diff --git a/tests/baselines/reference/typeParameterConstModifiers.symbols b/tests/baselines/reference/typeParameterConstModifiers.symbols index 628558a4be1f0..5ce7154b7d9fc 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.symbols +++ b/tests/baselines/reference/typeParameterConstModifiers.symbols @@ -161,57 +161,85 @@ type T1 = T; // Error >T : Symbol(T, Decl(typeParameterConstModifiers.ts, 41, 8)) >T : Symbol(T, Decl(typeParameterConstModifiers.ts, 41, 8)) +type T2 = (x: T) => T; +>T2 : Symbol(T2, Decl(typeParameterConstModifiers.ts, 41, 21)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 43, 11)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 43, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 43, 11)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 43, 11)) + +type T3 = { (x: T): T }; +>T3 : Symbol(T3, Decl(typeParameterConstModifiers.ts, 43, 31)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 44, 13)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 44, 22)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 44, 13)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 44, 13)) + +type T4 = new (x: T) => T; +>T4 : Symbol(T4, Decl(typeParameterConstModifiers.ts, 44, 33)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 15)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 45, 24)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 15)) + +type T5 = { new (x: T): T }; +>T5 : Symbol(T5, Decl(typeParameterConstModifiers.ts, 45, 35)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 46, 17)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 46, 26)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 46, 17)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 46, 17)) + // Corrected repro from #51745 type Obj = { a: { b: { c: "123" } } }; ->Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 41, 21)) ->a : Symbol(a, Decl(typeParameterConstModifiers.ts, 45, 12)) ->b : Symbol(b, Decl(typeParameterConstModifiers.ts, 45, 17)) ->c : Symbol(c, Decl(typeParameterConstModifiers.ts, 45, 22)) +>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 46, 37)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 50, 12)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 50, 17)) +>c : Symbol(c, Decl(typeParameterConstModifiers.ts, 50, 22)) type GetPath = ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 45, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 47, 15)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 50, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) P extends readonly [] ? T : ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 47, 15)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath : ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 47, 15)) ->A : Symbol(A, Decl(typeParameterConstModifiers.ts, 49, 29)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 13)) ->Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 49, 57)) ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 45, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 13)) ->A : Symbol(A, Decl(typeParameterConstModifiers.ts, 49, 29)) ->Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 49, 57)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) +>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 54, 29)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) +>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 54, 57)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 50, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) +>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 54, 29)) +>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 54, 57)) never; function set(obj: T, path: P, value: GetPath) {} ->set : Symbol(set, Decl(typeParameterConstModifiers.ts, 50, 10)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 52, 51)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) ->path : Symbol(path, Decl(typeParameterConstModifiers.ts, 52, 58)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 52, 67)) ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 45, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) +>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 55, 10)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 57, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 57, 15)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 57, 51)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 57, 13)) +>path : Symbol(path, Decl(typeParameterConstModifiers.ts, 57, 58)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 57, 15)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 57, 67)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 50, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 57, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 57, 15)) declare let obj: Obj; ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 54, 11)) ->Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 41, 21)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 59, 11)) +>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 46, 37)) declare let value: "123"; ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 55, 11)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 60, 11)) set(obj, ['a', 'b', 'c'], value); ->set : Symbol(set, Decl(typeParameterConstModifiers.ts, 50, 10)) ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 54, 11)) ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 55, 11)) +>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 55, 10)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 59, 11)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 60, 11)) diff --git a/tests/baselines/reference/typeParameterConstModifiers.types b/tests/baselines/reference/typeParameterConstModifiers.types index af172314e76e4..3b9e9d27b3407 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.types +++ b/tests/baselines/reference/typeParameterConstModifiers.types @@ -1,18 +1,18 @@ === tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts === declare function f1(x: T): T; ->f1 : (x: T) => T +>f1 : (x: T) => T >x : T const x11 = f1('a'); >x11 : "a" >f1('a') : "a" ->f1 : (x: T) => T +>f1 : (x: T) => T >'a' : "a" const x12 = f1(['a', ['b', 'c']]); >x12 : readonly ["a", readonly ["b", "c"]] >f1(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]] ->f1 : (x: T) => T +>f1 : (x: T) => T >['a', ['b', 'c']] : ["a", ["b", "c"]] >'a' : "a" >['b', 'c'] : ["b", "c"] @@ -22,7 +22,7 @@ const x12 = f1(['a', ['b', 'c']]); const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); >x13 : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } >f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } ->f1 : (x: T) => T +>f1 : (x: T) => T >{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; } >a : 1 >1 : 1 @@ -38,19 +38,19 @@ const x13 = f1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); >"g" : "g" declare function f2(x: T | undefined): T; ->f2 : (x: T | undefined) => T +>f2 : (x: T | undefined) => T >x : T | undefined const x21 = f2('a'); >x21 : "a" >f2('a') : "a" ->f2 : (x: T | undefined) => T +>f2 : (x: T | undefined) => T >'a' : "a" const x22 = f2(['a', ['b', 'c']]); >x22 : readonly ["a", readonly ["b", "c"]] >f2(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]] ->f2 : (x: T | undefined) => T +>f2 : (x: T | undefined) => T >['a', ['b', 'c']] : ["a", ["b", "c"]] >'a' : "a" >['b', 'c'] : ["b", "c"] @@ -60,7 +60,7 @@ const x22 = f2(['a', ['b', 'c']]); const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); >x23 : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } >f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }) : { readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; } ->f2 : (x: T | undefined) => T +>f2 : (x: T | undefined) => T >{ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] } : { a: 1; b: "c"; d: ["e", 2, true, { f: "g"; }]; } >a : 1 >1 : 1 @@ -76,29 +76,29 @@ const x23 = f2({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); >"g" : "g" declare function f3(x: T): T[]; ->f3 : (x: T) => T[] +>f3 : (x: T) => T[] >x : T const x31 = f3("hello"); >x31 : "hello"[] >f3("hello") : "hello"[] ->f3 : (x: T) => T[] +>f3 : (x: T) => T[] >"hello" : "hello" const x32 = f3("hello"); >x32 : "hello"[] >f3("hello") : "hello"[] ->f3 : (x: T) => T[] +>f3 : (x: T) => T[] >"hello" : "hello" declare function f4(obj: [T, T]): T; ->f4 : (obj: [T, T]) => T +>f4 : (obj: [T, T]) => T >obj : [T, T] const x41 = f4([[1, 'x'], [2, 'y']]); >x41 : readonly [1, "x"] | readonly [2, "y"] >f4([[1, 'x'], [2, 'y']]) : readonly [1, "x"] | readonly [2, "y"] ->f4 : (obj: [T, T]) => T +>f4 : (obj: [T, T]) => T >[[1, 'x'], [2, 'y']] : [[1, "x"], [2, "y"]] >[1, 'x'] : [1, "x"] >1 : 1 @@ -110,7 +110,7 @@ const x41 = f4([[1, 'x'], [2, 'y']]); const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]); >x42 : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } >f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]) : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } ->f4 : (obj: [T, T]) => T +>f4 : (obj: [T, T]) => T >[{ a: 1, b: 'x' }, { a: 2, b: 'y' }] : [{ a: 1; b: "x"; }, { a: 2; b: "y"; }] >{ a: 1, b: 'x' } : { a: 1; b: "x"; } >a : 1 @@ -124,7 +124,7 @@ const x42 = f4([{ a: 1, b: 'x' }, { a: 2, b: 'y' }]); >'y' : "y" declare function f5(obj: { x: T, y: T }): T; ->f5 : (obj: { x: T; y: T;}) => T +>f5 : (obj: { x: T; y: T;}) => T >obj : { x: T; y: T; } >x : T >y : T @@ -132,7 +132,7 @@ declare function f5(obj: { x: T, y: T }): T; const x51 = f5({ x: [1, 'x'], y: [2, 'y'] }); >x51 : readonly [1, "x"] | readonly [2, "y"] >f5({ x: [1, 'x'], y: [2, 'y'] }) : readonly [1, "x"] | readonly [2, "y"] ->f5 : (obj: { x: T; y: T; }) => T +>f5 : (obj: { x: T; y: T; }) => T >{ x: [1, 'x'], y: [2, 'y'] } : { x: [1, "x"]; y: [2, "y"]; } >x : [1, "x"] >[1, 'x'] : [1, "x"] @@ -146,7 +146,7 @@ const x51 = f5({ x: [1, 'x'], y: [2, 'y'] }); const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }); >x52 : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } >f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }) : { readonly a: 1; readonly b: "x"; } | { readonly a: 2; readonly b: "y"; } ->f5 : (obj: { x: T; y: T; }) => T +>f5 : (obj: { x: T; y: T; }) => T >{ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } } : { x: { a: 1; b: "x"; }; y: { a: 2; b: "y"; }; } >x : { a: 1; b: "x"; } >{ a: 1, b: 'x' } : { a: 1; b: "x"; } @@ -162,13 +162,13 @@ const x52 = f5({ x: { a: 1, b: 'x' }, y: { a: 2, b: 'y' } }); >'y' : "y" declare function f6(...args: T): T; ->f6 : (...args: T) => T +>f6 : (...args: T) => T >args : T const x61 = f6(1, 'b', { a: 1, b: 'x' }); >x61 : readonly [1, "b", { readonly a: 1; readonly b: "x"; }] >f6(1, 'b', { a: 1, b: 'x' }) : readonly [1, "b", { readonly a: 1; readonly b: "x"; }] ->f6 : (...args: T) => T +>f6 : (...args: T) => T >1 : 1 >'b' : "b" >{ a: 1, b: 'x' } : { a: 1; b: "x"; } @@ -184,7 +184,7 @@ class C1 { >x : T foo(x: U) { return x; } ->foo : (x: U) => U +>foo : (x: U) => U >x : U >x : U } @@ -210,9 +210,9 @@ const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); const c72 = c71.foo(['a', ['b', 'c']]); >c72 : readonly ["a", readonly ["b", "c"]] >c71.foo(['a', ['b', 'c']]) : readonly ["a", readonly ["b", "c"]] ->c71.foo : (x: U) => U +>c71.foo : (x: U) => U >c71 : C1<{ readonly a: 1; readonly b: "c"; readonly d: readonly ["e", 2, true, { readonly f: "g"; }]; }> ->foo : (x: U) => U +>foo : (x: U) => U >['a', ['b', 'c']] : ["a", ["b", "c"]] >'a' : "a" >['b', 'c'] : ["b", "c"] @@ -225,6 +225,22 @@ interface I1 { x: T } // Error type T1 = T; // Error >T1 : T +type T2 = (x: T) => T; +>T2 : (x: T) => T +>x : T + +type T3 = { (x: T): T }; +>T3 : (x: T) => T +>x : T + +type T4 = new (x: T) => T; +>T4 : new (x: T) => T +>x : T + +type T5 = { new (x: T): T }; +>T5 : new (x: T) => T +>x : T + // Corrected repro from #51745 type Obj = { a: { b: { c: "123" } } }; @@ -241,7 +257,7 @@ type GetPath = never; function set(obj: T, path: P, value: GetPath) {} ->set : (obj: T, path: P, value: GetPath) => void +>set : (obj: T, path: P, value: GetPath) => void >obj : T >path : P >value : GetPath @@ -254,7 +270,7 @@ declare let value: "123"; set(obj, ['a', 'b', 'c'], value); >set(obj, ['a', 'b', 'c'], value) : void ->set : (obj: T, path: P, value: GetPath) => void +>set : (obj: T, path: P, value: GetPath) => void >obj : Obj >['a', 'b', 'c'] : ["a", "b", "c"] >'a' : "a" diff --git a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts index 8ce99d87350f9..a5984f1e334b0 100644 --- a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts +++ b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts @@ -43,6 +43,11 @@ interface I1 { x: T } // Error type T1 = T; // Error +type T2 = (x: T) => T; +type T3 = { (x: T): T }; +type T4 = new (x: T) => T; +type T5 = { new (x: T): T }; + // Corrected repro from #51745 type Obj = { a: { b: { c: "123" } } }; From d2af9418e5e328aa82a6bad8a0b90307d2a1341c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Dec 2022 11:59:05 -0800 Subject: [PATCH 10/14] Also permit `const` in method signature type parameters --- src/compiler/checker.ts | 5 +- .../typeParameterConstModifiers.errors.txt | 6 +- .../reference/typeParameterConstModifiers.js | 4 + .../typeParameterConstModifiers.symbols | 125 ++++++++++-------- .../typeParameterConstModifiers.types | 6 + .../typeParameterConstModifiers.ts | 4 + 6 files changed, 90 insertions(+), 60 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 36c4981d67130..38ac674391899 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -45418,8 +45418,9 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (node.kind !== SyntaxKind.EnumDeclaration && node.kind !== SyntaxKind.TypeParameter) { return grammarErrorOnNode(node, Diagnostics.A_class_member_cannot_have_the_0_keyword, tokenToString(SyntaxKind.ConstKeyword)); } - if (node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(node.parent) || isClassDeclaration(node.parent) || isFunctionTypeNode(node.parent) || - isConstructorTypeNode(node.parent) || isCallSignatureDeclaration(node.parent) || isConstructSignatureDeclaration(node.parent))) { + const parent = node.parent; + if (node.kind === SyntaxKind.TypeParameter && !(isFunctionLikeDeclaration(parent) || isClassDeclaration(parent) || isFunctionTypeNode(parent) || + isConstructorTypeNode(parent) || isCallSignatureDeclaration(parent) || isConstructSignatureDeclaration(parent) || isMethodSignature(parent))) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_can_only_appear_on_a_type_parameter_of_a_function_method_or_class, tokenToString(modifier.kind)); } break; diff --git a/tests/baselines/reference/typeParameterConstModifiers.errors.txt b/tests/baselines/reference/typeParameterConstModifiers.errors.txt index 71dcb57f6d3de..f712753a182e4 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.errors.txt +++ b/tests/baselines/reference/typeParameterConstModifiers.errors.txt @@ -1,5 +1,5 @@ tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(40,14): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class -tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(42,9): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class +tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(46,9): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class ==== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts (2 errors) ==== @@ -46,6 +46,10 @@ tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterCon ~~~~~ !!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class + interface I2 { + f(x: T): T; + } + type T1 = T; // Error ~~~~~ !!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class diff --git a/tests/baselines/reference/typeParameterConstModifiers.js b/tests/baselines/reference/typeParameterConstModifiers.js index b907180d47f40..26fc7866a1fb2 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.js +++ b/tests/baselines/reference/typeParameterConstModifiers.js @@ -40,6 +40,10 @@ const c72 = c71.foo(['a', ['b', 'c']]); interface I1 { x: T } // Error +interface I2 { + f(x: T): T; +} + type T1 = T; // Error type T2 = (x: T) => T; diff --git a/tests/baselines/reference/typeParameterConstModifiers.symbols b/tests/baselines/reference/typeParameterConstModifiers.symbols index 5ce7154b7d9fc..8e558fd0db35e 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.symbols +++ b/tests/baselines/reference/typeParameterConstModifiers.symbols @@ -156,90 +156,101 @@ interface I1 { x: T } // Error >x : Symbol(I1.x, Decl(typeParameterConstModifiers.ts, 39, 23)) >T : Symbol(T, Decl(typeParameterConstModifiers.ts, 39, 13)) +interface I2 { +>I2 : Symbol(I2, Decl(typeParameterConstModifiers.ts, 39, 30)) + + f(x: T): T; +>f : Symbol(I2.f, Decl(typeParameterConstModifiers.ts, 41, 14)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 6)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 42, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 6)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 6)) +} + type T1 = T; // Error ->T1 : Symbol(T1, Decl(typeParameterConstModifiers.ts, 39, 30)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 41, 8)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 41, 8)) +>T1 : Symbol(T1, Decl(typeParameterConstModifiers.ts, 43, 1)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 8)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 8)) type T2 = (x: T) => T; ->T2 : Symbol(T2, Decl(typeParameterConstModifiers.ts, 41, 21)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 43, 11)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 43, 20)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 43, 11)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 43, 11)) +>T2 : Symbol(T2, Decl(typeParameterConstModifiers.ts, 45, 21)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 11)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 47, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 11)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 11)) type T3 = { (x: T): T }; ->T3 : Symbol(T3, Decl(typeParameterConstModifiers.ts, 43, 31)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 44, 13)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 44, 22)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 44, 13)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 44, 13)) +>T3 : Symbol(T3, Decl(typeParameterConstModifiers.ts, 47, 31)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 13)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 48, 22)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 13)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 13)) type T4 = new (x: T) => T; ->T4 : Symbol(T4, Decl(typeParameterConstModifiers.ts, 44, 33)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 15)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 45, 24)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 15)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 15)) +>T4 : Symbol(T4, Decl(typeParameterConstModifiers.ts, 48, 33)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 49, 15)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 49, 24)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 49, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 49, 15)) type T5 = { new (x: T): T }; ->T5 : Symbol(T5, Decl(typeParameterConstModifiers.ts, 45, 35)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 46, 17)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 46, 26)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 46, 17)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 46, 17)) +>T5 : Symbol(T5, Decl(typeParameterConstModifiers.ts, 49, 35)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 17)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 50, 26)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 17)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 17)) // Corrected repro from #51745 type Obj = { a: { b: { c: "123" } } }; ->Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 46, 37)) ->a : Symbol(a, Decl(typeParameterConstModifiers.ts, 50, 12)) ->b : Symbol(b, Decl(typeParameterConstModifiers.ts, 50, 17)) ->c : Symbol(c, Decl(typeParameterConstModifiers.ts, 50, 22)) +>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 50, 37)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 54, 12)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 54, 17)) +>c : Symbol(c, Decl(typeParameterConstModifiers.ts, 54, 22)) type GetPath = ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 50, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 54, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 56, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 56, 15)) P extends readonly [] ? T : ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 56, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 56, 13)) P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath : ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 52, 15)) ->A : Symbol(A, Decl(typeParameterConstModifiers.ts, 54, 29)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) ->Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 54, 57)) ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 50, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 13)) ->A : Symbol(A, Decl(typeParameterConstModifiers.ts, 54, 29)) ->Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 54, 57)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 56, 15)) +>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 58, 29)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 56, 13)) +>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 58, 57)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 54, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 56, 13)) +>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 58, 29)) +>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 58, 57)) never; function set(obj: T, path: P, value: GetPath) {} ->set : Symbol(set, Decl(typeParameterConstModifiers.ts, 55, 10)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 57, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 57, 15)) ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 57, 51)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 57, 13)) ->path : Symbol(path, Decl(typeParameterConstModifiers.ts, 57, 58)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 57, 15)) ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 57, 67)) ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 50, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 57, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 57, 15)) +>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 59, 10)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 61, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 61, 15)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 61, 51)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 61, 13)) +>path : Symbol(path, Decl(typeParameterConstModifiers.ts, 61, 58)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 61, 15)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 61, 67)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 54, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 61, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 61, 15)) declare let obj: Obj; ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 59, 11)) ->Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 46, 37)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 63, 11)) +>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 50, 37)) declare let value: "123"; ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 60, 11)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 64, 11)) set(obj, ['a', 'b', 'c'], value); ->set : Symbol(set, Decl(typeParameterConstModifiers.ts, 55, 10)) ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 59, 11)) ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 60, 11)) +>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 59, 10)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 63, 11)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 64, 11)) diff --git a/tests/baselines/reference/typeParameterConstModifiers.types b/tests/baselines/reference/typeParameterConstModifiers.types index 3b9e9d27b3407..dc54eed07b879 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.types +++ b/tests/baselines/reference/typeParameterConstModifiers.types @@ -222,6 +222,12 @@ const c72 = c71.foo(['a', ['b', 'c']]); interface I1 { x: T } // Error >x : T +interface I2 { + f(x: T): T; +>f : (x: T) => T +>x : T +} + type T1 = T; // Error >T1 : T diff --git a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts index a5984f1e334b0..3a8e5a49f01a5 100644 --- a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts +++ b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts @@ -41,6 +41,10 @@ const c72 = c71.foo(['a', ['b', 'c']]); interface I1 { x: T } // Error +interface I2 { + f(x: T): T; +} + type T1 = T; // Error type T2 = (x: T) => T; From a31576131cc48f64f87f0f901e2f827176759933 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Dec 2022 13:51:16 -0800 Subject: [PATCH 11/14] Fix parsing of `const` modifier in array expression type parameters --- src/compiler/checker.ts | 2 +- src/compiler/parser.ts | 3 ++- .../typeParameterLists/typeParameterConstModifiers.ts | 3 +++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 38ac674391899..6a190d620c144 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -447,6 +447,7 @@ import { isComputedPropertyName, isConstructorDeclaration, isConstructorTypeNode, + isConstructSignatureDeclaration, isConstTypeReference, isDeclaration, isDeclarationName, @@ -1012,7 +1013,6 @@ import { WideningContext, WithStatement, YieldExpression, - isConstructSignatureDeclaration, } from "./_namespaces/ts"; import * as performance from "./_namespaces/ts.performance"; import * as moduleSpecifiers from "./_namespaces/ts.moduleSpecifiers"; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index e74a31a13e62d..9201ebb787760 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5203,13 +5203,14 @@ namespace Parser { // If we have "<" not followed by an identifier, // then this definitely is not an arrow function. - if (!isIdentifier()) { + if (!isIdentifier() && token() !== SyntaxKind.ConstKeyword) { return Tristate.False; } // JSX overrides if (languageVariant === LanguageVariant.JSX) { const isArrowFunctionInJsx = lookAhead(() => { + parseOptional(SyntaxKind.ConstKeyword); const third = nextToken(); if (third === SyntaxKind.ExtendsKeyword) { const fourth = nextToken(); diff --git a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts index 3a8e5a49f01a5..8e074f5c53ab2 100644 --- a/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts +++ b/tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts @@ -39,6 +39,9 @@ class C1 { const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); const c72 = c71.foo(['a', ['b', 'c']]); +const fx1 = (x: T) => x; +const fx2 = (x: T) => x; + interface I1 { x: T } // Error interface I2 { From f6bbf9c9aa8da315429ad77df016645ba214418c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Dec 2022 13:51:35 -0800 Subject: [PATCH 12/14] Accept new baselines --- .../typeParameterConstModifiers.errors.txt | 7 +- .../reference/typeParameterConstModifiers.js | 5 + .../typeParameterConstModifiers.symbols | 146 ++++++++++-------- .../typeParameterConstModifiers.types | 12 ++ 4 files changed, 102 insertions(+), 68 deletions(-) diff --git a/tests/baselines/reference/typeParameterConstModifiers.errors.txt b/tests/baselines/reference/typeParameterConstModifiers.errors.txt index f712753a182e4..06889c06a04ca 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.errors.txt +++ b/tests/baselines/reference/typeParameterConstModifiers.errors.txt @@ -1,5 +1,5 @@ -tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(40,14): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class -tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(46,9): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class +tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(43,14): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class +tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts(49,9): error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class ==== tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterConstModifiers.ts (2 errors) ==== @@ -42,6 +42,9 @@ tests/cases/conformance/types/typeParameters/typeParameterLists/typeParameterCon const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); const c72 = c71.foo(['a', ['b', 'c']]); + const fx1 = (x: T) => x; + const fx2 = (x: T) => x; + interface I1 { x: T } // Error ~~~~~ !!! error TS1277: 'const' modifier can only appear on a type parameter of a function, method or class diff --git a/tests/baselines/reference/typeParameterConstModifiers.js b/tests/baselines/reference/typeParameterConstModifiers.js index 26fc7866a1fb2..4a1e057e15383 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.js +++ b/tests/baselines/reference/typeParameterConstModifiers.js @@ -38,6 +38,9 @@ class C1 { const c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); const c72 = c71.foo(['a', ['b', 'c']]); +const fx1 = (x: T) => x; +const fx2 = (x: T) => x; + interface I1 { x: T } // Error interface I2 { @@ -91,5 +94,7 @@ var C1 = /** @class */ (function () { }()); var c71 = new C1({ a: 1, b: "c", d: ["e", 2, true, { f: "g" }] }); var c72 = c71.foo(['a', ['b', 'c']]); +var fx1 = function (x) { return x; }; +var fx2 = function (x) { return x; }; function set(obj, path, value) { } set(obj, ['a', 'b', 'c'], value); diff --git a/tests/baselines/reference/typeParameterConstModifiers.symbols b/tests/baselines/reference/typeParameterConstModifiers.symbols index 8e558fd0db35e..010301c319bc5 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.symbols +++ b/tests/baselines/reference/typeParameterConstModifiers.symbols @@ -150,107 +150,121 @@ const c72 = c71.foo(['a', ['b', 'c']]); >c71 : Symbol(c71, Decl(typeParameterConstModifiers.ts, 36, 5)) >foo : Symbol(C1.foo, Decl(typeParameterConstModifiers.ts, 32, 24)) -interface I1 { x: T } // Error ->I1 : Symbol(I1, Decl(typeParameterConstModifiers.ts, 37, 39)) +const fx1 = (x: T) => x; +>fx1 : Symbol(fx1, Decl(typeParameterConstModifiers.ts, 39, 5)) >T : Symbol(T, Decl(typeParameterConstModifiers.ts, 39, 13)) ->x : Symbol(I1.x, Decl(typeParameterConstModifiers.ts, 39, 23)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 39, 22)) >T : Symbol(T, Decl(typeParameterConstModifiers.ts, 39, 13)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 39, 22)) + +const fx2 = (x: T) => x; +>fx2 : Symbol(fx2, Decl(typeParameterConstModifiers.ts, 40, 5)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 40, 13)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 40, 23)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 40, 13)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 40, 23)) + +interface I1 { x: T } // Error +>I1 : Symbol(I1, Decl(typeParameterConstModifiers.ts, 40, 34)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 13)) +>x : Symbol(I1.x, Decl(typeParameterConstModifiers.ts, 42, 23)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 13)) interface I2 { ->I2 : Symbol(I2, Decl(typeParameterConstModifiers.ts, 39, 30)) +>I2 : Symbol(I2, Decl(typeParameterConstModifiers.ts, 42, 30)) f(x: T): T; ->f : Symbol(I2.f, Decl(typeParameterConstModifiers.ts, 41, 14)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 6)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 42, 15)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 6)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 42, 6)) +>f : Symbol(I2.f, Decl(typeParameterConstModifiers.ts, 44, 14)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 6)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 45, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 6)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 6)) } type T1 = T; // Error ->T1 : Symbol(T1, Decl(typeParameterConstModifiers.ts, 43, 1)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 8)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 45, 8)) +>T1 : Symbol(T1, Decl(typeParameterConstModifiers.ts, 46, 1)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 8)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 8)) type T2 = (x: T) => T; ->T2 : Symbol(T2, Decl(typeParameterConstModifiers.ts, 45, 21)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 11)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 47, 20)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 11)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 47, 11)) +>T2 : Symbol(T2, Decl(typeParameterConstModifiers.ts, 48, 21)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 11)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 50, 20)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 11)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 11)) type T3 = { (x: T): T }; ->T3 : Symbol(T3, Decl(typeParameterConstModifiers.ts, 47, 31)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 13)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 48, 22)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 13)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 48, 13)) +>T3 : Symbol(T3, Decl(typeParameterConstModifiers.ts, 50, 31)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 51, 13)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 51, 22)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 51, 13)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 51, 13)) type T4 = new (x: T) => T; ->T4 : Symbol(T4, Decl(typeParameterConstModifiers.ts, 48, 33)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 49, 15)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 49, 24)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 49, 15)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 49, 15)) +>T4 : Symbol(T4, Decl(typeParameterConstModifiers.ts, 51, 33)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 15)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 52, 24)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 52, 15)) type T5 = { new (x: T): T }; ->T5 : Symbol(T5, Decl(typeParameterConstModifiers.ts, 49, 35)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 17)) ->x : Symbol(x, Decl(typeParameterConstModifiers.ts, 50, 26)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 17)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 50, 17)) +>T5 : Symbol(T5, Decl(typeParameterConstModifiers.ts, 52, 35)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 53, 17)) +>x : Symbol(x, Decl(typeParameterConstModifiers.ts, 53, 26)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 53, 17)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 53, 17)) // Corrected repro from #51745 type Obj = { a: { b: { c: "123" } } }; ->Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 50, 37)) ->a : Symbol(a, Decl(typeParameterConstModifiers.ts, 54, 12)) ->b : Symbol(b, Decl(typeParameterConstModifiers.ts, 54, 17)) ->c : Symbol(c, Decl(typeParameterConstModifiers.ts, 54, 22)) +>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 53, 37)) +>a : Symbol(a, Decl(typeParameterConstModifiers.ts, 57, 12)) +>b : Symbol(b, Decl(typeParameterConstModifiers.ts, 57, 17)) +>c : Symbol(c, Decl(typeParameterConstModifiers.ts, 57, 22)) type GetPath = ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 54, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 56, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 56, 15)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 57, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 59, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 59, 15)) P extends readonly [] ? T : ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 56, 15)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 56, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 59, 15)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 59, 13)) P extends readonly [infer A extends keyof T, ...infer Rest] ? GetPath : ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 56, 15)) ->A : Symbol(A, Decl(typeParameterConstModifiers.ts, 58, 29)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 56, 13)) ->Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 58, 57)) ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 54, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 56, 13)) ->A : Symbol(A, Decl(typeParameterConstModifiers.ts, 58, 29)) ->Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 58, 57)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 59, 15)) +>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 61, 29)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 59, 13)) +>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 61, 57)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 57, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 59, 13)) +>A : Symbol(A, Decl(typeParameterConstModifiers.ts, 61, 29)) +>Rest : Symbol(Rest, Decl(typeParameterConstModifiers.ts, 61, 57)) never; function set(obj: T, path: P, value: GetPath) {} ->set : Symbol(set, Decl(typeParameterConstModifiers.ts, 59, 10)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 61, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 61, 15)) ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 61, 51)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 61, 13)) ->path : Symbol(path, Decl(typeParameterConstModifiers.ts, 61, 58)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 61, 15)) ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 61, 67)) ->GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 54, 38)) ->T : Symbol(T, Decl(typeParameterConstModifiers.ts, 61, 13)) ->P : Symbol(P, Decl(typeParameterConstModifiers.ts, 61, 15)) +>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 62, 10)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 64, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 64, 15)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 64, 51)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 64, 13)) +>path : Symbol(path, Decl(typeParameterConstModifiers.ts, 64, 58)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 64, 15)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 64, 67)) +>GetPath : Symbol(GetPath, Decl(typeParameterConstModifiers.ts, 57, 38)) +>T : Symbol(T, Decl(typeParameterConstModifiers.ts, 64, 13)) +>P : Symbol(P, Decl(typeParameterConstModifiers.ts, 64, 15)) declare let obj: Obj; ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 63, 11)) ->Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 50, 37)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 66, 11)) +>Obj : Symbol(Obj, Decl(typeParameterConstModifiers.ts, 53, 37)) declare let value: "123"; ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 64, 11)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 67, 11)) set(obj, ['a', 'b', 'c'], value); ->set : Symbol(set, Decl(typeParameterConstModifiers.ts, 59, 10)) ->obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 63, 11)) ->value : Symbol(value, Decl(typeParameterConstModifiers.ts, 64, 11)) +>set : Symbol(set, Decl(typeParameterConstModifiers.ts, 62, 10)) +>obj : Symbol(obj, Decl(typeParameterConstModifiers.ts, 66, 11)) +>value : Symbol(value, Decl(typeParameterConstModifiers.ts, 67, 11)) diff --git a/tests/baselines/reference/typeParameterConstModifiers.types b/tests/baselines/reference/typeParameterConstModifiers.types index dc54eed07b879..e5d3d230be180 100644 --- a/tests/baselines/reference/typeParameterConstModifiers.types +++ b/tests/baselines/reference/typeParameterConstModifiers.types @@ -219,6 +219,18 @@ const c72 = c71.foo(['a', ['b', 'c']]); >'b' : "b" >'c' : "c" +const fx1 = (x: T) => x; +>fx1 : (x: T) => T +>(x: T) => x : (x: T) => T +>x : T +>x : T + +const fx2 = (x: T) => x; +>fx2 : (x: T) => T +>(x: T) => x : (x: T) => T +>x : T +>x : T + interface I1 { x: T } // Error >x : T From dccb290383cc2aeab3d2be18255fdc2e2f0abc4c Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Tue, 13 Dec 2022 14:08:15 -0800 Subject: [PATCH 13/14] Remove unused properties from NodeLinks --- src/compiler/types.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 90f94609a3a11..82062effaf9fb 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -5958,9 +5958,6 @@ export interface NodeLinks { skipDirectInference?: true; // Flag set by the API `getContextualType` call on a node when `Completions` is passed to force the checker to skip making inferences to a node's type declarationRequiresScopeChange?: boolean; // Set by `useOuterVariableScopeInParameter` in checker when downlevel emit would change the name resolution scope inside of a parameter. serializedTypes?: Map; // Collection of types serialized at this location - - contextualType?: Type; // Used to temporarily assign a contextual type during overload resolution - inferenceContext?: InferenceContext; // Inference context for contextual type } /** @internal */ From fde9c473d3d64aa8c4bdc99ab5edf0f833d3b210 Mon Sep 17 00:00:00 2001 From: Anders Hejlsberg Date: Thu, 15 Dec 2022 13:26:12 -0800 Subject: [PATCH 14/14] Rename `permitInvalidConstAsModifier` to `permitConstAsModifier` --- src/compiler/parser.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 57bc3711152b5..d259d7e028691 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -7702,11 +7702,11 @@ namespace Parser { return list && createNodeArray(list, pos); } - function tryParseModifier(permitInvalidConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined { + function tryParseModifier(permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean, hasSeenStaticModifier?: boolean): Modifier | undefined { const pos = getNodePos(); const kind = token(); - if (token() === SyntaxKind.ConstKeyword && permitInvalidConstAsModifier) { + if (token() === SyntaxKind.ConstKeyword && permitConstAsModifier) { // We need to ensure that any subsequent modifiers appear on the same line // so that when 'const' is a standalone declaration, we don't issue an error. if (!tryParse(nextTokenIsOnSameLineAndCanFollowModifier)) { @@ -7741,7 +7741,7 @@ namespace Parser { * In those situations, if we are entirely sure that 'const' is not valid on its own (such as when ASI takes effect * and turns it into a standalone declaration), then it is better to parse it and report an error later. * - * In such situations, 'permitInvalidConstAsModifier' should be set to true. + * In such situations, 'permitConstAsModifier' should be set to true. */ function parseModifiers(permitConstAsModifier?: boolean, stopOnStartOfClassStaticBlock?: boolean): NodeArray | undefined { const pos = getNodePos(); @@ -7773,7 +7773,7 @@ namespace Parser { const hasJSDoc = hasPrecedingJSDocComment(); const decorators = parseDecorators(); - const modifiers = parseModifiers(/*permitInvalidConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true); + const modifiers = parseModifiers(/*permitConstAsModifier*/ true, /*stopOnStartOfClassStaticBlock*/ true); if (token() === SyntaxKind.StaticKeyword && lookAhead(nextTokenIsOpenBrace)) { return parseClassStaticBlockDeclaration(pos, hasJSDoc, decorators, modifiers); }