diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 30b51d561ac..d7bc1157f7b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7540,7 +7540,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const parameterType = getTypeOfSymbol(parameterSymbol); const parameterTypeNode = serializeTypeForDeclaration(context, parameterDeclaration, parameterType, parameterSymbol); - const modifiers = !(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags && parameterDeclaration && canHaveModifiers(parameterDeclaration) ? map(getModifiers(parameterDeclaration), factory.cloneNode) : undefined; + const modifiers = parameterDeclaration && canHaveModifiers(parameterDeclaration) && (!(context.flags & NodeBuilderFlags.OmitParameterModifiers) && preserveModifierFlags || hasSyntacticModifier(parameterDeclaration, ModifierFlags.Deferred)) ? map(getModifiers(parameterDeclaration), factory.cloneNode) : undefined; const isRest = parameterDeclaration && isRestParameter(parameterDeclaration) || getCheckFlags(parameterSymbol) & CheckFlags.RestParameter; const dotDotDotToken = isRest ? factory.createToken(SyntaxKind.DotDotDotToken) : undefined; const name = parameterToParameterDeclarationName(parameterSymbol, parameterDeclaration, context); @@ -50145,6 +50145,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { if (flags & ModifierFlags.Deferred) { return grammarErrorOnNode(modifier, Diagnostics._0_modifier_already_seen, "deferred"); } + if (flags & ModifierFlags.Public) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "deferred", "public"); + } + if (flags & ModifierFlags.Protected) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "deferred", "protected"); + } + if (flags & ModifierFlags.Private) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "deferred", "private"); + } + if (flags & ModifierFlags.Readonly) { + return grammarErrorOnNode(modifier, Diagnostics._0_modifier_must_precede_1_modifier, "deferred", "readonly"); + } flags |= ModifierFlags.Deferred; break; } diff --git a/src/compiler/factory/nodeFactory.ts b/src/compiler/factory/nodeFactory.ts index 71f6f3cf13a..d712505a7a3 100644 --- a/src/compiler/factory/nodeFactory.ts +++ b/src/compiler/factory/nodeFactory.ts @@ -222,6 +222,7 @@ import { JSDocCallbackTag, JSDocClassTag, JSDocComment, + JSDocDeferredTag, JSDocDeprecatedTag, JSDocEnumTag, JSDocFunctionType, @@ -938,6 +939,12 @@ export function createNodeFactory(flags: NodeFactoryFlags, baseFactory: BaseNode get updateJSDocDeprecatedTag() { return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocDeprecatedTag); }, + get createJSDocDeferredTag() { + return getJSDocSimpleTagCreateFunction(SyntaxKind.JSDocDeferredTag); + }, + get updateJSDocDeferredTag() { + return getJSDocSimpleTagUpdateFunction(SyntaxKind.JSDocDeferredTag); + }, get createJSDocThrowsTag() { return getJSDocTypeLikeTagCreateFunction(SyntaxKind.JSDocThrowsTag); }, diff --git a/src/compiler/factory/nodeTests.ts b/src/compiler/factory/nodeTests.ts index cd31b63f818..8d04d482125 100644 --- a/src/compiler/factory/nodeTests.ts +++ b/src/compiler/factory/nodeTests.ts @@ -87,6 +87,7 @@ import { JSDocAuthorTag, JSDocCallbackTag, JSDocClassTag, + JSDocDeferredTag, JSDocDeprecatedTag, JSDocEnumTag, JSDocFunctionType, @@ -1132,6 +1133,10 @@ export function isJSDocDeprecatedTag(node: Node): node is JSDocDeprecatedTag { return node.kind === SyntaxKind.JSDocDeprecatedTag; } +export function isJSDocDeferredTag(node: Node): node is JSDocDeferredTag { + return node.kind === SyntaxKind.JSDocDeferredTag; +} + export function isJSDocSeeTag(node: Node): node is JSDocSeeTag { return node.kind === SyntaxKind.JSDocSeeTag; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 37d69ec340f..6ccbbe76dbd 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -9057,6 +9057,9 @@ namespace Parser { hasDeprecatedTag = true; tag = parseSimpleTag(start, factory.createJSDocDeprecatedTag, tagName, margin, indentText); break; + case "deferred": + tag = parseSimpleTag(start, factory.createJSDocDeferredTag, tagName, margin, indentText); + break; case "this": tag = parseThisTag(start, tagName, margin, indentText); break; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 76ae32f94b4..5ae864fb89b 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -421,6 +421,7 @@ export const enum SyntaxKind { JSDocImplementsTag, JSDocAuthorTag, JSDocDeprecatedTag, + JSDocDeferredTag, JSDocClassTag, JSDocPublicTag, JSDocPrivateTag, @@ -856,35 +857,36 @@ export const enum ModifierFlags { Protected = 1 << 2, // Property/Method Readonly = 1 << 3, // Property/Method Override = 1 << 4, // Override method. + Deferred = 1 << 5, // Parameter // Syntactic-only modifiers - Export = 1 << 5, // Declarations - Abstract = 1 << 6, // Class/Method/ConstructSignature - Ambient = 1 << 7, // Declarations - Static = 1 << 8, // Property/Method - Accessor = 1 << 9, // Property - Async = 1 << 10, // Property/Method/Function - Default = 1 << 11, // Function/Class (export default declaration) - Const = 1 << 12, // Const enum - In = 1 << 13, // Contravariance modifier - Out = 1 << 14, // Covariance modifier - Deferred = 1 << 15, // Parameter + Export = 1 << 6, // Declarations + Abstract = 1 << 7, // Class/Method/ConstructSignature + Ambient = 1 << 8, // Declarations + Static = 1 << 9, // Property/Method + Accessor = 1 << 10, // Property + Async = 1 << 11, // Property/Method/Function + Default = 1 << 12, // Function/Class (export default declaration) + Const = 1 << 13, // Const enum + In = 1 << 14, // Contravariance modifier + Out = 1 << 15, // Covariance modifier Decorator = 1 << 16, // Contains a decorator. // JSDoc-only modifiers Deprecated = 1 << 17, // Deprecated tag. // Cache-only JSDoc-modifiers. Should match order of Syntactic/JSDoc modifiers, above. - /** @internal */ JSDocPublic = 1 << 23, // if this value changes, `selectEffectiveModifierFlags` must change accordingly - /** @internal */ JSDocPrivate = 1 << 24, - /** @internal */ JSDocProtected = 1 << 25, - /** @internal */ JSDocReadonly = 1 << 26, - /** @internal */ JSDocOverride = 1 << 27, + /** @internal */ JSDocPublic = 1 << 22, // if this value changes, `selectEffectiveModifierFlags` must change accordingly + /** @internal */ JSDocPrivate = 1 << 23, + /** @internal */ JSDocProtected = 1 << 24, + /** @internal */ JSDocReadonly = 1 << 25, + /** @internal */ JSDocOverride = 1 << 26, + /** @internal */ JSDocDeferred = 1 << 27, - /** @internal */ SyntacticOrJSDocModifiers = Public | Private | Protected | Readonly | Override, - /** @internal */ SyntacticOnlyModifiers = Export | Ambient | Abstract | Static | Accessor | Async | Default | Const | In | Out | Deferred | Decorator, + /** @internal */ SyntacticOrJSDocModifiers = Public | Private | Protected | Readonly | Override | Deferred, + /** @internal */ SyntacticOnlyModifiers = Export | Ambient | Abstract | Static | Accessor | Async | Default | Const | In | Out | Decorator, /** @internal */ SyntacticModifiers = SyntacticOrJSDocModifiers | SyntacticOnlyModifiers, - /** @internal */ JSDocCacheOnlyModifiers = JSDocPublic | JSDocPrivate | JSDocProtected | JSDocReadonly | JSDocOverride, + /** @internal */ JSDocCacheOnlyModifiers = JSDocPublic | JSDocPrivate | JSDocProtected | JSDocReadonly | JSDocOverride | JSDocDeferred, /** @internal */ JSDocOnlyModifiers = Deprecated, /** @internal */ NonCacheOnlyModifiers = SyntacticOrJSDocModifiers | SyntacticOnlyModifiers | JSDocOnlyModifiers, @@ -3970,6 +3972,10 @@ export interface JSDocDeprecatedTag extends JSDocTag { kind: SyntaxKind.JSDocDeprecatedTag; } +export interface JSDocDeferredTag extends JSDocTag { + kind: SyntaxKind.JSDocDeferredTag; +} + export interface JSDocClassTag extends JSDocTag { readonly kind: SyntaxKind.JSDocClassTag; } @@ -8985,6 +8991,8 @@ export interface NodeFactory { updateJSDocUnknownTag(node: JSDocUnknownTag, tagName: Identifier, comment: string | NodeArray | undefined): JSDocUnknownTag; createJSDocDeprecatedTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; updateJSDocDeprecatedTag(node: JSDocDeprecatedTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeprecatedTag; + createJSDocDeferredTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeferredTag; + updateJSDocDeferredTag(node: JSDocDeferredTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocDeferredTag; createJSDocOverrideTag(tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; updateJSDocOverrideTag(node: JSDocOverrideTag, tagName: Identifier | undefined, comment?: string | NodeArray): JSDocOverrideTag; createJSDocThrowsTag(tagName: Identifier, typeExpression: JSDocTypeExpression | undefined, comment?: string | NodeArray): JSDocThrowsTag; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 04c2eb3b064..3eb64dee33b 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -170,6 +170,7 @@ import { getDirectoryPath, getImpliedNodeFormatForEmitWorker, getJSDocAugmentsTag, + getJSDocDeferredTagNoCache, getJSDocDeprecatedTagNoCache, getJSDocImplementsTags, getJSDocOverrideTagNoCache, @@ -7062,15 +7063,18 @@ export function getSyntacticModifierFlags(node: Node): ModifierFlags { function getRawJSDocModifierFlagsNoCache(node: Node): ModifierFlags { let flags = ModifierFlags.None; - if (!!node.parent && !isParameter(node)) { + if (node.parent) { if (isInJSFile(node)) { - if (getJSDocPublicTagNoCache(node)) flags |= ModifierFlags.JSDocPublic; - if (getJSDocPrivateTagNoCache(node)) flags |= ModifierFlags.JSDocPrivate; - if (getJSDocProtectedTagNoCache(node)) flags |= ModifierFlags.JSDocProtected; - if (getJSDocReadonlyTagNoCache(node)) flags |= ModifierFlags.JSDocReadonly; - if (getJSDocOverrideTagNoCache(node)) flags |= ModifierFlags.JSDocOverride; + if (!isParameter(node)) { + if (getJSDocPublicTagNoCache(node)) flags |= ModifierFlags.JSDocPublic; + if (getJSDocPrivateTagNoCache(node)) flags |= ModifierFlags.JSDocPrivate; + if (getJSDocProtectedTagNoCache(node)) flags |= ModifierFlags.JSDocProtected; + if (getJSDocReadonlyTagNoCache(node)) flags |= ModifierFlags.JSDocReadonly; + if (getJSDocOverrideTagNoCache(node)) flags |= ModifierFlags.JSDocOverride; + } + if (getJSDocDeferredTagNoCache(node)) flags |= ModifierFlags.JSDocDeferred; } - if (getJSDocDeprecatedTagNoCache(node)) flags |= ModifierFlags.Deprecated; + if (!isParameter(node) && getJSDocDeprecatedTagNoCache(node)) flags |= ModifierFlags.Deprecated; } return flags; @@ -7082,7 +7086,7 @@ function selectSyntacticModifierFlags(flags: ModifierFlags) { function selectEffectiveModifierFlags(flags: ModifierFlags) { return (flags & ModifierFlags.NonCacheOnlyModifiers) | - ((flags & ModifierFlags.JSDocCacheOnlyModifiers) >>> 23); // shift ModifierFlags.JSDoc* to match ModifierFlags.* + ((flags & ModifierFlags.JSDocCacheOnlyModifiers) >>> 22); // shift ModifierFlags.JSDoc* to match ModifierFlags.* } function getJSDocModifierFlagsNoCache(node: Node): ModifierFlags { diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts index 1bca593edd2..25b4c838efc 100644 --- a/src/compiler/utilitiesPublic.ts +++ b/src/compiler/utilitiesPublic.ts @@ -137,6 +137,7 @@ import { isJSDoc, isJSDocAugmentsTag, isJSDocClassTag, + isJSDocDeferredTag, isJSDocDeprecatedTag, isJSDocEnumTag, isJSDocFunctionType, @@ -183,6 +184,7 @@ import { JSDocClassTag, JSDocComment, JSDocContainer, + JSDocDeferredTag, JSDocDeprecatedTag, JSDocEnumTag, JSDocImplementsTag, @@ -1123,6 +1125,16 @@ export function getJSDocDeprecatedTagNoCache(node: Node): JSDocDeprecatedTag | u return getFirstJSDocTag(node, isJSDocDeprecatedTag, /*noCache*/ true); } +/** Gets the JSDoc deferred tag for the node if present */ +export function getJSDocDeferredTag(node: Node): JSDocDeferredTag | undefined { + return getFirstJSDocTag(node, isJSDocDeferredTag); +} + +/** @internal */ +export function getJSDocDeferredTagNoCache(node: Node): JSDocDeferredTag | undefined { + return getFirstJSDocTag(node, isJSDocDeferredTag, /*noCache*/ true); +} + /** Gets the JSDoc enum tag for the node if present */ export function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined { return getFirstJSDocTag(node, isJSDocEnumTag);