[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No-op string in constructor is repeated and reordered when constructor assignment is used #48671

Closed
rhuitl opened this issue Apr 13, 2022 · 12 comments · Fixed by #48687
Closed
Assignees
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue

Comments

@rhuitl
Copy link
rhuitl commented Apr 13, 2022

Bug Report

The TypeScript code

class Example {
    constructor(private A: string) {
        "ngInject";
    }
}

when compiled with TS 4.6.2 yields:

"use strict";
class Example {
    constructor(A) {
        this.A = A;
        "ngInject";
        "ngInject";
    }
}

when compiled with TS 4.5.5 yields:

"use strict";
class Example {
    constructor(A) {
        "ngInject";
        this.A = A;
    }
}

The differences are:

  • the string "ngInject;" is repeated
  • the string appears after the constructor assignment, not before as in 4.5.

For our use case, the repetition is probably not a real problem, however the re-ordering is. If any of these two are by design now, we can work around - but I wanted to double check with the TypeScript developers because it seems to be a bit unexpected.

🕗 Version & Regression Information

We observed errors in a AngularJS-based project using ng-annotate-patched which relies on the string to annotate classes for AngularJS. It works wiht TS 4.5 and broke with TS 4.6.

TS 4.6.2 (broken)
TS 4.5.5 (good)

⏯ Playground Link

https://www.typescriptlang.org/play?removeComments=true&target=2&ts=4.5.5#code/MYGwhgzhAECiAeYC2AHEBTaBvAUASGAHsA7CAFwCcBXYMwigChQoEsA3MMzAQQC5pyrYgHMAlNnx4ARCICSxAFbpaUgNz4Avji1A

@RyanCavanaugh RyanCavanaugh added the Bug A bug in TypeScript label Apr 13, 2022
@RyanCavanaugh RyanCavanaugh added this to the TypeScript 4.7.1 milestone Apr 13, 2022
@RyanCavanaugh
Copy link
Member

👉 @JoshuaKGoldberg if you feel like it

@jakebailey
Copy link
Member
jakebailey commented Apr 13, 2022

The repetition is weird, but the reordering doesn't seem to be wrong to me at first glance; I would think that the parameters being properties implies that they must be assigned before any part of the body executes.

Is there some special case for these sort of string-y statements at the start of blocks? Playground Link

I guess so, because "use strict".

@JoshuaKGoldberg
Copy link
Contributor
JoshuaKGoldberg commented Apr 13, 2022

Yes, they're directive prologues, also sometimes callied prologue directives. I've only ever seen "use esm" and "use strict" in the wild till now. TIL about ng-annotate-patched.

#29374 and https://blog.joshuakgoldberg.com/code-before-super-technical-overview/ have a good amount of backing context for how those are meant to be at the beginning of the constructor.

I can probably take a look within this week!

Edit: or today 😄

@jakebailey
Copy link
Member

Also TIL that the spec lets you have whatever prologues you want. 😄

@fatcerberus
Copy link

I mean, why wouldn't it? They're just strings, if the engine doesn't recognize a directive, it can just ignore it as a no-op.

@jakebailey
Copy link
Member

I just mean from the POV that there's nothing wrong with this code:

function foo() {
    console.log("Hello, world!");
    console.log(Math.random());
    "some random string as an expression statement";
}

Because a string is an expression which can be alone in a statement.

But if it's the first statement of a source file or a function body, then it's special and must not be reordered even if our emit is going to be placing things semantically "before" the block the user typed, because that changes its meaning.

@jakebailey
Copy link
Member
jakebailey commented Apr 13, 2022

FWIW this bug applies with "use strict" too (even though for some reason, running this emitted code crashes; running it elsewhere does not).

Playground Link

https://glot.io/snippets/g8u41v3925

@fatcerberus
Copy link

Out of curiosity, does the spec say anything about multiple directives? i.e. if I write...

function foo() {
    "use fooey";
    "use bard";
    console.log(812);
}

...are both strings required to be kept at the top of the function?

@jakebailey
Copy link
Member

I don't know about the spec, but at runtime it sure seems like it applies all of them: https://glot.io/snippets/g8u48lkc4o (don't ask me what runtime this site uses)

@JoshuaKGoldberg
Copy link
Contributor

From https://es5.github.io/#x14.1:

A Directive Prologue may contain more than one Use Strict Directive. However, an implementation may issue a warning if this occurs.

@fatcerberus
Copy link
fatcerberus commented Apr 14, 2022

Yes, but that's specifically only about "use strict":

A Use Strict Directive is an ExpressionStatement in a Directive Prologue whose StringLiteral is either the exact character sequences "use strict" or 'use strict'.

What I was wondering about is, if there are multiple custom directives other than use strict, if those are still considered part of the prologue. The spec seems a bit vague on that point.

edit: Just read that section again, looks like the answer to my question is yes:

A Directive Prologue is the longest sequence of ExpressionStatement productions occurring as the initial SourceElement productions of a Program or FunctionBody and where each ExpressionStatement in the sequence consists entirely of a StringLiteral token followed a semicolon. The semicolon may appear explicitly or may be inserted by automatic semicolon insertion. A Directive Prologue may be an empty sequence.

@rhuitl
Copy link
Author
rhuitl commented Apr 14, 2022

23 hours and 57 minutes from a bug report to a fix, you guys are awesome :-) Thank you!

babakks added a commit to babakks/TypeScript that referenced this issue Jul 22, 2022
Signed-off-by: Babak K. Shandiz <babak.k.shandiz@gmail.com>

diff --git a/package-lock.json b/package-lock.json
index 521fb599..bd23f406 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -219,9 +219,9 @@
             }
         },
         "@octokit/openapi-types": {
-            "version": "12.10.0",
-            "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.10.0.tgz",
-            "integrity": "sha512-xsgA7LKuQ/2QReMZQXNlBP68ferPlqw66Jmx5/J399Cn5EgIDaHXou6Rgn1GkpDNjkPji67fTlC2rz6ABaVFKw==",
+            "version": "12.10.1",
+            "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.10.1.tgz",
+            "integrity": "sha512-P+SukKanjFY0ZhsK6wSVnQmxTP2eVPPE8OPSNuxaMYtgVzwJZgfGdwlYjf4RlRU4vLEw4ts2fsE2icG4nZ5ddQ==",
             "dev": true
         },
         "@octokit/plugin-paginate-rest": {
@@ -240,9 +240,9 @@
             "dev": true
         },
         "@octokit/plugin-rest-endpoint-methods": {
-            "version": "6.1.0",
-            "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.1.0.tgz",
-            "integrity": "sha512-gP/yHUY0k/uKkEqXF6tZGRhCFqZNjQ0qdh9/gVo74AJ2pc3cr1rjnW/KRw1uXUKB/H9Y0rRBCBxsLXJmQjPv3A==",
+            "version": "6.1.2",
+            "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.1.2.tgz",
+            "integrity": "sha512-sAfSKtLHNq0UQ2iFuI41I6m5SK6bnKFRJ5kUjDRVbmQXiRVi4aQiIcgG4cM7bt+bhSiWL4HwnTxDkWFlKeKClA==",
             "dev": true,
             "requires": {
                 "@octokit/types": "^6.40.0",
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index ce644034..4dd1b7ba 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -2191,7 +2191,7 @@ namespace ts {
             // 1. When result is undefined, after checking for a missing "this."
             // 2. When result is defined
             function checkAndReportErrorForInvalidInitializer() {
-                if (propertyWithInvalidInitializer && !(getEmitScriptTarget(compilerOptions) === ScriptTarget.ESNext && useDefineForClassFields)) {
+                if (propertyWithInvalidInitializer && !(useDefineForClassFields && getEmitScriptTarget(compilerOptions) >= ScriptTarget.ES2022)) {
                     // We have a match, but the reference occurred within a property initializer and the identifier also binds
                     // to a local variable in the constructor where the code will be emitted. Note that this is actually allowed
                     // with ESNext+useDefineForClassFields because the scope semantics are different.
@@ -11896,6 +11896,9 @@ namespace ts {
                     else if ((type as MappedType).objectFlags & ObjectFlags.Mapped) {
                         resolveMappedTypeMembers(type as MappedType);
                     }
+                    else {
+                        Debug.fail("Unhandled object type " + Debug.formatObjectFlags(type.objectFlags));
+                    }
                 }
                 else if (type.flags & TypeFlags.Union) {
                     resolveUnionTypeMembers(type as UnionType);
@@ -11903,6 +11906,9 @@ namespace ts {
                 else if (type.flags & TypeFlags.Intersection) {
                     resolveIntersectionTypeMembers(type as IntersectionType);
                 }
+                else {
+                    Debug.fail("Unhandled type " + Debug.formatTypeFlags(type.flags));
+                }
             }
             return type as ResolvedType;
         }
@@ -12743,12 +12749,14 @@ namespace ts {

         // Return list of type parameters with duplicates removed (duplicate identifier errors are generated in the actual
         // type checking functions).
-        function getTypeParametersFromDeclaration(declaration: DeclarationWithTypeParameters): TypeParameter[] | undefined {
+        function getTypeParametersFromDeclaration(declaration: DeclarationWithTypeParameters): readonly TypeParameter[] | undefined {
             let result: TypeParameter[] | undefined;
             for (const node of getEffectiveTypeParameterDeclarations(declaration)) {
                 result = appendIfUnique(result, getDeclaredTypeOfTypeParameter(node.symbol));
             }
-            return result;
+            return result?.length ? result
+                : isFunctionDeclaration(declaration) ? getSignatureOfTypeTag(declaration)?.typeParameters
+                : undefined;
         }

         function symbolsToArray(symbols: SymbolTable): Symbol[] {
@@ -22556,15 +22564,11 @@ namespace ts {
                     inferFromTypeArguments(getTypeArguments(source as TypeReference), getTypeArguments(target as TypeReference), getVariances((source as TypeReference).target));
                 }
                 else if (source.flags & TypeFlags.Index && target.flags & TypeFlags.Index) {
-                    contravariant = !contravariant;
-                    inferFromTypes((source as IndexType).type, (target as IndexType).type);
-                    contravariant = !contravariant;
+                    inferFromContravariantTypes((source as IndexType).type, (target as IndexType).type);
                 }
                 else if ((isLiteralType(source) || source.flags & TypeFlags.String) && target.flags & TypeFlags.Index) {
                     const empty = createEmptyObjectTypeFromStringLiteral(source);
-                    contravariant = !contravariant;
-                    inferWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof);
-                    contravariant = !contravariant;
+                    inferFromContravariantTypesWithPriority(empty, (target as IndexType).type, InferencePriority.LiteralKeyof);
                 }
                 else if (source.flags & TypeFlags.IndexedAccess && target.flags & TypeFlags.IndexedAccess) {
                     inferFromTypes((source as IndexedAccessType).objectType, (target as IndexedAccessType).objectType);
@@ -22577,10 +22581,7 @@ namespace ts {
                 }
                 else if (source.flags & TypeFlags.Substitution) {
                     inferFromTypes((source as SubstitutionType).baseType, target);
-                    const oldPriority = priority;
-                    priority |= InferencePriority.SubstituteSource;
-                    inferFromTypes((source as SubstitutionType).substitute, target); // Make substitute inference at a lower priority
-                    priority = oldPriority;
+                    inferWithPriority((source as SubstitutionType).substitute, target, InferencePriority.SubstituteSource); // Make substitute inference at a lower priority
                 }
                 else if (target.flags & TypeFlags.Conditional) {
                     invokeOnce(source, target, inferToConditionalType);
@@ -22631,6 +22632,20 @@ namespace ts {
                 priority = savePriority;
             }

+            function inferFromContravariantTypesWithPriority(source: Type, target: Type, newPriority: InferencePriority) {
+                const savePriority = priority;
+                priority |= newPriority;
+                inferFromContravariantTypes(source, target);
+                priority = savePriority;
+            }
+
+            function inferToMultipleTypesWithPriority(source: Type, targets: Type[], targetFlags: TypeFlags, newPriority: InferencePriority) {
+                const savePriority = priority;
+                priority |= newPriority;
+                inferToMultipleTypes(source, targets, targetFlags);
+                priority = savePriority;
+            }
+
             function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) {
                 const key = source.id + "," + target.id;
                 const status = visited && visited.get(key);
@@ -22694,10 +22709,14 @@ namespace ts {
             }

             function inferFromContravariantTypes(source: Type, target: Type) {
+                contravariant = !contravariant;
+                inferFromTypes(source, target);
+                contravariant = !contravariant;
+            }
+
+            function inferFromContravariantTypesIfStrictFunctionTypes(source: Type, target: Type) {
                 if (strictFunctionTypes || priority & InferencePriority.AlwaysStrict) {
-                    contravariant = !contravariant;
-                    inferFromTypes(source, target);
-                    contravariant = !contravariant;
+                    inferFromContravariantTypes(source, target);
                 }
                 else {
                     inferFromTypes(source, target);
@@ -22860,11 +22879,8 @@ namespace ts {
                     inferFromTypes(getFalseTypeFromConditionalType(source as ConditionalType), getFalseTypeFromConditionalType(target));
                 }
                 else {
-                    const savePriority = priority;
-                    priority |= contravariant ? InferencePriority.ContravariantConditional : 0;
                     const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)];
-                    inferToMultipleTypes(source, targetTypes, target.flags);
-                    priority = savePriority;
+                    inferToMultipleTypesWithPriority(source, targetTypes, target.flags, contravariant ? InferencePriority.ContravariantConditional : 0);
                 }
             }

@@ -23059,7 +23075,7 @@ namespace ts {
                 const kind = target.declaration ? target.declaration.kind : SyntaxKind.Unknown;
                 // Once we descend into a bivariant signature we remain bivariant for all nested inferences
                 bivariant = bivariant || kind === SyntaxKind.MethodDeclaration || kind === SyntaxKind.MethodSignature || kind === SyntaxKind.Constructor;
-                applyToParameterTypes(source, target, inferFromContravariantTypes);
+                applyToParameterTypes(source, target, inferFromContravariantTypesIfStrictFunctionTypes);
                 bivariant = saveBivariant;
                 applyToReturnTypes(source, target, inferFromTypes);
             }
@@ -24613,7 +24629,7 @@ namespace ts {
                 }
                 // for (const _ in ref) acts as a nonnull on ref
                 if (isVariableDeclaration(node) && node.parent.parent.kind === SyntaxKind.ForInStatement && isMatchingReference(reference, node.parent.parent.expression)) {
-                    return getNonNullableTypeIfNeeded(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent)));
+                    return getNonNullableTypeIfNeeded(finalizeEvolvingArrayType(getTypeFromFlowType(getTypeAtFlowNode(flow.antecedent))));
                 }
                 // Assignment doesn't affect reference
                 return undefined;
@@ -30764,7 +30780,7 @@ namespace ts {

             let typeArguments: NodeArray<TypeNode> | undefined;

-            if (!isDecorator) {
+            if (!isDecorator && !isSuperCall(node)) {
                 typeArguments = (node as CallExpression).typeArguments;

                 // We already perform checking on the type arguments on the class declaration itself.
@@ -33439,7 +33455,7 @@ namespace ts {
                         error(node.operand, Diagnostics.The_0_operator_cannot_be_applied_to_type_symbol, tokenToString(node.operator));
                     }
                     if (node.operator === SyntaxKind.PlusToken) {
-                        if (maybeTypeOfKind(operandType, TypeFlags.BigIntLike)) {
+                        if (maybeTypeOfKindConsideringBaseConstraint(operandType, TypeFlags.BigIntLike)) {
                             error(node.operand, Diagnostics.Operator_0_cannot_be_applied_to_type_1, tokenToString(node.operator), typeToString(getBaseTypeOfLiteralType(operandType)));
                         }
                         return numberType;
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index f9aa3e57..299a0fda 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -5285,12 +5285,15 @@ namespace ts {

         function parseSuperExpression(): MemberExpression {
             const pos = getNodePos();
-            const expression = parseTokenNode<PrimaryExpression>();
+            let expression = parseTokenNode<MemberExpression>();
             if (token() === SyntaxKind.LessThanToken) {
                 const startPos = getNodePos();
                 const typeArguments = tryParse(parseTypeArgumentsInExpression);
                 if (typeArguments !== undefined) {
                     parseErrorAt(startPos, getNodePos(), Diagnostics.super_may_not_use_type_arguments);
+                    if (!isTemplateStartOfTaggedTemplate()) {
+                        expression = factory.createExpressionWithTypeArguments(expression, typeArguments);
+                    }
                 }
             }

diff --git a/src/compiler/transformers/ts.ts b/src/compiler/transformers/ts.ts
index 52242ccb..61b982d7 100644
--- a/src/compiler/transformers/ts.ts
+++ b/src/compiler/transformers/ts.ts
@@ -1113,7 +1113,8 @@ namespace ts {
             }

             // Add remaining statements from the body, skipping the super() call if it was found and any (already added) prologue statements
-            addRange(statements, visitNodes(body.statements, visitor, isStatement, superStatementIndex + 1 + prologueStatementCount));
+            const start = superStatementIndex >= 0 ? superStatementIndex + 1 : prologueStatementCount;
+            addRange(statements, visitNodes(body.statements, visitor, isStatement, start));

             // End the lexical environment.
             statements = factory.mergeLexicalEnvironment(statements, endLexicalEnvironment());
diff --git a/src/compiler/utilitiesPublic.ts b/src/compiler/utilitiesPublic.ts
index f2f0c030..229620a1 100644
--- a/src/compiler/utilitiesPublic.ts
+++ b/src/compiler/utilitiesPublic.ts
@@ -932,6 +932,12 @@ namespace ts {
     /**
      * Gets the effective type parameters. If the node was parsed in a
      * JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
+     *
+     * This does *not* return type parameters from a jsdoc reference to a generic type, eg
+     *
+     * type Id = <T>(x: T) => T
+     * /** @type {Id} /
+     * function id(x) { return x }
      */
     export function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[] {
         if (isJSDocSignature(node)) {
diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts
index 12470880..1654c937 100644
--- a/src/lib/dom.generated.d.ts
+++ b/src/lib/dom.generated.d.ts
@@ -13828,11 +13828,11 @@ declare var SubmitEvent: {
  * Available only in secure contexts.
  */
 interface SubtleCrypto {
-    decrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesGcmParams, key: CryptoKey, data: BufferSource): Promise<any>;
+    decrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesGcmParams, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
     deriveBits(algorithm: AlgorithmIdentifier | EcdhKeyDeriveParams | HkdfParams | Pbkdf2Params, baseKey: CryptoKey, length: number): Promise<ArrayBuffer>;
     deriveKey(algorithm: AlgorithmIdentifier | EcdhKeyDeriveParams | HkdfParams | Pbkdf2Params, baseKey: CryptoKey, derivedKeyType: AlgorithmIdentifier | AesDerivedKeyParams | HmacImportParams | HkdfParams | Pbkdf2Params, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey>;
     digest(algorithm: AlgorithmIdentifier, data: BufferSource): Promise<ArrayBuffer>;
-    encrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesGcmParams, key: CryptoKey, data: BufferSource): Promise<any>;
+    encrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesGcmParams, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
     exportKey(format: "jwk", key: CryptoKey): Promise<JsonWebKey>;
     exportKey(format: Exclude<KeyFormat, "jwk">, key: CryptoKey): Promise<ArrayBuffer>;
     generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams, extractable: boolean, keyUsages: ReadonlyArray<KeyUsage>): Promise<CryptoKeyPair>;
diff --git a/src/lib/webworker.generated.d.ts b/src/lib/webworker.generated.d.ts
index 343cb94c..b88d6b74 100644
--- a/src/lib/webworker.generated.d.ts
+++ b/src/lib/webworker.generated.d.ts
@@ -2988,11 +2988,11 @@ declare var StorageManager: {
  * Available only in secure contexts.
  */
 interface SubtleCrypto {
-    decrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesGcmParams, key: CryptoKey, data: BufferSource): Promise<any>;
+    decrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesGcmParams, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
     deriveBits(algorithm: AlgorithmIdentifier | EcdhKeyDeriveParams | HkdfParams | Pbkdf2Params, baseKey: CryptoKey, length: number): Promise<ArrayBuffer>;
     deriveKey(algorithm: AlgorithmIdentifier | EcdhKeyDeriveParams | HkdfParams | Pbkdf2Params, baseKey: CryptoKey, derivedKeyType: AlgorithmIdentifier | AesDerivedKeyParams | HmacImportParams | HkdfParams | Pbkdf2Params, extractable: boolean, keyUsages: KeyUsage[]): Promise<CryptoKey>;
     digest(algorithm: AlgorithmIdentifier, data: BufferSource): Promise<ArrayBuffer>;
-    encrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesGcmParams, key: CryptoKey, data: BufferSource): Promise<any>;
+    encrypt(algorithm: AlgorithmIdentifier | RsaOaepParams | AesCtrParams | AesCbcParams | AesGcmParams, key: CryptoKey, data: BufferSource): Promise<ArrayBuffer>;
     exportKey(format: "jwk", key: CryptoKey): Promise<JsonWebKey>;
     exportKey(format: Exclude<KeyFormat, "jwk">, key: CryptoKey): Promise<ArrayBuffer>;
     generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams, extractable: boolean, keyUsages: ReadonlyArray<KeyUsage>): Promise<CryptoKeyPair>;
diff --git a/src/server/session.ts b/src/server/session.ts
index 0fe57694..d0aaf189 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -344,6 +344,8 @@ namespace ts.server {
     function getDefinitionLocation(defaultProject: Project, initialLocation: DocumentPosition, isForRename: boolean): DocumentPosition | undefined {
         const infos = defaultProject.getLanguageService().getDefinitionAtPosition(initialLocation.fileName, initialLocation.pos, /*searchOtherFilesOnly*/ false, /*stopAtAlias*/ isForRename);
         const info = infos && firstOrUndefined(infos);
+        // Note that the value of `isLocal` may depend on whether or not the checker has run on the containing file
+        // (implying that FAR cascading behavior may depend on request order)
         return info && !info.isLocal ? { fileName: info.fileName, pos: info.textSpan.start } : undefined;
     }

diff --git a/src/services/codefixes/helpers.ts b/src/services/codefixes/helpers.ts
index a4c11fd5..2f5c8703 100644
--- a/src/services/codefixes/helpers.ts
+++ b/src/services/codefixes/helpers.ts
@@ -143,7 +143,7 @@ namespace ts.codefix {
                     break;
                 }

-                const signatures = checker.getSignaturesOfType(type, SignatureKind.Call);
+                const signatures = type.isUnion() ? flatMap(type.types, t => t.getCallSignatures()) : type.getCallSignatures();
                 if (!some(signatures)) {
                     break;
                 }
diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts
index e85246e9..257531c1 100644
--- a/src/services/jsDoc.ts
+++ b/src/services/jsDoc.ts
@@ -357,8 +357,12 @@ namespace ts.JsDoc {
         }

         const { commentOwner, parameters, hasReturn } = commentOwnerInfo;
-        const commentOwnerJSDoc = hasJSDocNodes(commentOwner) && commentOwner.jsDoc ? lastOrUndefined(commentOwner.jsDoc) : undefined;
-        if (commentOwner.getStart(sourceFile) < position || commentOwnerJSDoc && commentOwnerJSDoc !== existingDocComment) {
+        const commentOwnerJsDoc = hasJSDocNodes(commentOwner) && commentOwner.jsDoc ? commentOwner.jsDoc : undefined;
+        const lastJsDoc = lastOrUndefined(commentOwnerJsDoc);
+        if (commentOwner.getStart(sourceFile) < position
+            || lastJsDoc
+                && existingDocComment
+                && lastJsDoc !== existingDocComment) {
             return undefined;
         }

@@ -378,7 +382,11 @@ namespace ts.JsDoc {
         // * if the caret was directly in front of the object, then we add an extra line and indentation.
         const openComment = "/**";
         const closeComment = " */";
-        if (tags) {
+
+        // If any of the existing jsDoc has tags, ignore adding new ones.
+        const hasTag = (commentOwnerJsDoc || []).some(jsDoc => !!jsDoc.tags);
+
+        if (tags && !hasTag) {
             const preamble = openComment + newLine + indentationStr + " * ";
             const endLine = tokenStart === position ? newLine + indentationStr : "";
             const result = preamble + newLine + tags + indentationStr + closeComment + endLine;
diff --git a/src/services/refactors/extractSymbol.ts b/src/services/refactors/extractSymbol.ts
index 6b2ec866..67435b47 100644
--- a/src/services/refactors/extractSymbol.ts
+++ b/src/services/refactors/extractSymbol.ts
@@ -551,7 +551,7 @@ namespace ts.refactor.extractSymbol {
                 const savedPermittedJumps = permittedJumps;
                 switch (node.kind) {
                     case SyntaxKind.IfStatement:
-                        permittedJumps = PermittedJumps.None;
+                        permittedJumps &= ~PermittedJumps.Return;
                         break;
                     case SyntaxKind.TryStatement:
                         // forbid all jumps inside try blocks
diff --git a/src/services/stringCompletions.ts b/src/services/stringCompletions.ts
index a32022f9..cb7260f6 100644
--- a/src/services/stringCompletions.ts
+++ b/src/services/stringCompletions.ts
@@ -167,9 +167,9 @@ namespace ts.Completions.StringCompletions {
             case SyntaxKind.LiteralType: {
                 const grandParent = walkUpParentheses(parent.parent);
                 switch (grandParent.kind) {
+                    case SyntaxKind.ExpressionWithTypeArguments:
                     case SyntaxKind.TypeReference: {
-                        const typeReference = grandParent as TypeReferenceNode;
-                        const typeArgument = findAncestor(parent, n => n.parent === typeReference) as LiteralTypeNode;
+                        const typeArgument = findAncestor(parent, n => n.parent === grandParent) as LiteralTypeNode;
                         if (typeArgument) {
                             return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(typeArgument)), isNewIdentifier: false };
                         }
diff --git a/src/services/types.ts b/src/services/types.ts
index 27c7616b..b9015a73 100644
--- a/src/services/types.ts
+++ b/src/services/types.ts
@@ -1045,7 +1045,12 @@ namespace ts {
         containerKind: ScriptElementKind;
         containerName: string;
         unverified?: boolean;
-        /* @internal */ isLocal?: boolean;
+        /** @internal
+         * Initially, this value is determined syntactically, but it is updated by the checker to cover
+         * cases like declarations that are exported in subsequent statements.  As a result, the value
+         * may be "incomplete" if this span has yet to be checked.
+         */
+        isLocal?: boolean;
         /* @internal */ isAmbient?: boolean;
         /* @internal */ failedAliasResolution?: boolean;
     }
diff --git a/src/testRunner/compilerRunner.ts b/src/testRunner/compilerRunner.ts
index 1d320d66..a6c67a17 100644
--- a/src/testRunner/compilerRunner.ts
+++ b/src/testRunner/compilerRunner.ts
@@ -141,7 +141,8 @@ namespace Harness {
             "preserveConstEnums",
             "skipLibCheck",
             "exactOptionalPropertyTypes",
-            "useUnknownInCatchVariables"
+            "useDefineForClassFields",
+            "useUnknownInCatchVariables",
         ];
         private fileName: string;
         private justName: string;
diff --git a/tests/baselines/reference/api/tsserverlibrary.d.ts b/tests/baselines/reference/api/tsserverlibrary.d.ts
index 23bfc30e..bbc5c384 100644
--- a/tests/baselines/reference/api/tsserverlibrary.d.ts
+++ b/tests/baselines/reference/api/tsserverlibrary.d.ts
@@ -4464,6 +4464,12 @@ declare namespace ts {
     /**
      * Gets the effective type parameters. If the node was parsed in a
      * JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
+     *
+     * This does *not* return type parameters from a jsdoc reference to a generic type, eg
+     *
+     * type Id = <T>(x: T) => T
+     * /** @type {Id} /
+     * function id(x) { return x }
      */
     function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[];
     function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined;
diff --git a/tests/baselines/reference/api/typescript.d.ts b/tests/baselines/reference/api/typescript.d.ts
index 18ef4ee2..f9e5f2d0 100644
--- a/tests/baselines/reference/api/typescript.d.ts
+++ b/tests/baselines/reference/api/typescript.d.ts
@@ -4464,6 +4464,12 @@ declare namespace ts {
     /**
      * Gets the effective type parameters. If the node was parsed in a
      * JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
+     *
+     * This does *not* return type parameters from a jsdoc reference to a generic type, eg
+     *
+     * type Id = <T>(x: T) => T
+     * /** @type {Id} /
+     * function id(x) { return x }
      */
     function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): readonly TypeParameterDeclaration[];
     function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined;
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).errors.txt b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).errors.txt
new file mode 100644
index 00000000..d214ea13
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).errors.txt
@@ -0,0 +1,12 @@
+tests/cases/compiler/classMemberInitializerScoping2.ts(3,9): error TS2301: Initializer of instance member variable 'p' cannot reference identifier 'x' declared in the constructor.
+
+
+==== tests/cases/compiler/classMemberInitializerScoping2.ts (1 errors) ====
+    const x = 1
+    class C {
+        p = x
+            ~
+!!! error TS2301: Initializer of instance member variable 'p' cannot reference identifier 'x' declared in the constructor.
+        constructor(x: string) { }
+    }
+
\ No newline at end of file
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).js b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).js
new file mode 100644
index 00000000..9591c174
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).js
@@ -0,0 +1,15 @@
+//// [classMemberInitializerScoping2.ts]
+const x = 1
+class C {
+    p = x
+    constructor(x: string) { }
+}
+
+
+//// [classMemberInitializerScoping2.js]
+const x = 1;
+class C {
+    constructor(x) {
+        this.p = x;
+    }
+}
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).symbols b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).symbols
new file mode 100644
index 00000000..78c02088
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).symbols
@@ -0,0 +1,14 @@
+=== tests/cases/compiler/classMemberInitializerScoping2.ts ===
+const x = 1
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 0, 5))
+
+class C {
+>C : Symbol(C, Decl(classMemberInitializerScoping2.ts, 0, 11))
+
+    p = x
+>p : Symbol(C.p, Decl(classMemberInitializerScoping2.ts, 1, 9))
+
+    constructor(x: string) { }
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 3, 16))
+}
+
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).types b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).types
new file mode 100644
index 00000000..20cff567
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=false).types
@@ -0,0 +1,16 @@
+=== tests/cases/compiler/classMemberInitializerScoping2.ts ===
+const x = 1
+>x : 1
+>1 : 1
+
+class C {
+>C : C
+
+    p = x
+>p : any
+>x : any
+
+    constructor(x: string) { }
+>x : string
+}
+
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).errors.txt b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).errors.txt
new file mode 100644
index 00000000..d214ea13
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).errors.txt
@@ -0,0 +1,12 @@
+tests/cases/compiler/classMemberInitializerScoping2.ts(3,9): error TS2301: Initializer of instance member variable 'p' cannot reference identifier 'x' declared in the constructor.
+
+
+==== tests/cases/compiler/classMemberInitializerScoping2.ts (1 errors) ====
+    const x = 1
+    class C {
+        p = x
+            ~
+!!! error TS2301: Initializer of instance member variable 'p' cannot reference identifier 'x' declared in the constructor.
+        constructor(x: string) { }
+    }
+
\ No newline at end of file
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).js b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).js
new file mode 100644
index 00000000..c2f4708c
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).js
@@ -0,0 +1,20 @@
+//// [classMemberInitializerScoping2.ts]
+const x = 1
+class C {
+    p = x
+    constructor(x: string) { }
+}
+
+
+//// [classMemberInitializerScoping2.js]
+const x = 1;
+class C {
+    constructor(x) {
+        Object.defineProperty(this, "p", {
+            enumerable: true,
+            configurable: true,
+            writable: true,
+            value: x
+        });
+    }
+}
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).symbols b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).symbols
new file mode 100644
index 00000000..78c02088
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).symbols
@@ -0,0 +1,14 @@
+=== tests/cases/compiler/classMemberInitializerScoping2.ts ===
+const x = 1
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 0, 5))
+
+class C {
+>C : Symbol(C, Decl(classMemberInitializerScoping2.ts, 0, 11))
+
+    p = x
+>p : Symbol(C.p, Decl(classMemberInitializerScoping2.ts, 1, 9))
+
+    constructor(x: string) { }
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 3, 16))
+}
+
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).types b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).types
new file mode 100644
index 00000000..20cff567
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=es2017,usedefineforclassfields=true).types
@@ -0,0 +1,16 @@
+=== tests/cases/compiler/classMemberInitializerScoping2.ts ===
+const x = 1
+>x : 1
+>1 : 1
+
+class C {
+>C : C
+
+    p = x
+>p : any
+>x : any
+
+    constructor(x: string) { }
+>x : string
+}
+
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).errors.txt b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).errors.txt
new file mode 100644
index 00000000..d214ea13
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).errors.txt
@@ -0,0 +1,12 @@
+tests/cases/compiler/classMemberInitializerScoping2.ts(3,9): error TS2301: Initializer of instance member variable 'p' cannot reference identifier 'x' declared in the constructor.
+
+
+==== tests/cases/compiler/classMemberInitializerScoping2.ts (1 errors) ====
+    const x = 1
+    class C {
+        p = x
+            ~
+!!! error TS2301: Initializer of instance member variable 'p' cannot reference identifier 'x' declared in the constructor.
+        constructor(x: string) { }
+    }
+
\ No newline at end of file
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).js b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).js
new file mode 100644
index 00000000..9591c174
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).js
@@ -0,0 +1,15 @@
+//// [classMemberInitializerScoping2.ts]
+const x = 1
+class C {
+    p = x
+    constructor(x: string) { }
+}
+
+
+//// [classMemberInitializerScoping2.js]
+const x = 1;
+class C {
+    constructor(x) {
+        this.p = x;
+    }
+}
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).symbols b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).symbols
new file mode 100644
index 00000000..78c02088
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).symbols
@@ -0,0 +1,14 @@
+=== tests/cases/compiler/classMemberInitializerScoping2.ts ===
+const x = 1
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 0, 5))
+
+class C {
+>C : Symbol(C, Decl(classMemberInitializerScoping2.ts, 0, 11))
+
+    p = x
+>p : Symbol(C.p, Decl(classMemberInitializerScoping2.ts, 1, 9))
+
+    constructor(x: string) { }
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 3, 16))
+}
+
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).types b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).types
new file mode 100644
index 00000000..20cff567
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=false).types
@@ -0,0 +1,16 @@
+=== tests/cases/compiler/classMemberInitializerScoping2.ts ===
+const x = 1
+>x : 1
+>1 : 1
+
+class C {
+>C : C
+
+    p = x
+>p : any
+>x : any
+
+    constructor(x: string) { }
+>x : string
+}
+
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).js b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).js
new file mode 100644
index 00000000..2d008f66
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).js
@@ -0,0 +1,14 @@
+//// [classMemberInitializerScoping2.ts]
+const x = 1
+class C {
+    p = x
+    constructor(x: string) { }
+}
+
+
+//// [classMemberInitializerScoping2.js]
+const x = 1;
+class C {
+    p = x;
+    constructor(x) { }
+}
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).symbols b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).symbols
new file mode 100644
index 00000000..cf486c1e
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).symbols
@@ -0,0 +1,15 @@
+=== tests/cases/compiler/classMemberInitializerScoping2.ts ===
+const x = 1
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 0, 5))
+
+class C {
+>C : Symbol(C, Decl(classMemberInitializerScoping2.ts, 0, 11))
+
+    p = x
+>p : Symbol(C.p, Decl(classMemberInitializerScoping2.ts, 1, 9))
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 0, 5))
+
+    constructor(x: string) { }
+>x : Symbol(x, Decl(classMemberInitializerScoping2.ts, 3, 16))
+}
+
diff --git a/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).types b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).types
new file mode 100644
index 00000000..9e045ca5
--- /dev/null
+++ b/tests/baselines/reference/classMemberInitializerScoping2(target=esnext,usedefineforclassfields=true).types
@@ -0,0 +1,16 @@
+=== tests/cases/compiler/classMemberInitializerScoping2.ts ===
+const x = 1
+>x : 1
+>1 : 1
+
+class C {
+>C : C
+
+    p = x
+>p : number
+>x : 1
+
+    constructor(x: string) { }
+>x : string
+}
+
diff --git a/tests/baselines/reference/evolvingArrayResolvedAssert.errors.txt b/tests/baselines/reference/evolvingArrayResolvedAssert.errors.txt
new file mode 100644
index 00000000..487ffa3a
--- /dev/null
+++ b/tests/baselines/reference/evolvingArrayResolvedAssert.errors.txt
@@ -0,0 +1,18 @@
+tests/cases/compiler/evolvingArrayResolvedAssert.ts(1,5): error TS7034: Variable 'C' implicitly has type 'any[]' in some locations where its type cannot be determined.
+tests/cases/compiler/evolvingArrayResolvedAssert.ts(2,15): error TS7005: Variable 'C' implicitly has an 'any[]' type.
+tests/cases/compiler/evolvingArrayResolvedAssert.ts(3,9): error TS7005: Variable 'C' implicitly has an 'any[]' type.
+
+
+==== tests/cases/compiler/evolvingArrayResolvedAssert.ts (3 errors) ====
+    var C = [];
+        ~
+!!! error TS7034: Variable 'C' implicitly has type 'any[]' in some locations where its type cannot be determined.
+    for (var a in C) {
+                  ~
+!!! error TS7005: Variable 'C' implicitly has an 'any[]' type.
+        if (C.hasOwnProperty(a)) {
+            ~
+!!! error TS7005: Variable 'C' implicitly has an 'any[]' type.
+        }
+    }
+
\ No newline at end of file
diff --git a/tests/baselines/reference/evolvingArrayResolvedAssert.js b/tests/baselines/reference/evolvingArrayResolvedAssert.js
new file mode 100644
index 00000000..4cae93bb
--- /dev/null
+++ b/tests/baselines/reference/evolvingArrayResolvedAssert.js
@@ -0,0 +1,15 @@
+//// [evolvingArrayResolvedAssert.ts]
+var C = [];
+for (var a in C) {
+    if (C.hasOwnProperty(a)) {
+    }
+}
+
+
+//// [evolvingArrayResolvedAssert.js]
+"use strict";
+var C = [];
+for (var a in C) {
+    if (C.hasOwnProperty(a)) {
+    }
+}
diff --git a/tests/baselines/reference/evolvingArrayResolvedAssert.symbols b/tests/baselines/reference/evolvingArrayResolvedAssert.symbols
new file mode 100644
index 00000000..8d52f9e5
--- /dev/null
+++ b/tests/baselines/reference/evolvingArrayResolvedAssert.symbols
@@ -0,0 +1,16 @@
+=== tests/cases/compiler/evolvingArrayResolvedAssert.ts ===
+var C = [];
+>C : Symbol(C, Decl(evolvingArrayResolvedAssert.ts, 0, 3))
+
+for (var a in C) {
+>a : Symbol(a, Decl(evolvingArrayResolvedAssert.ts, 1, 8))
+>C : Symbol(C, Decl(evolvingArrayResolvedAssert.ts, 0, 3))
+
+    if (C.hasOwnProperty(a)) {
+>C.hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.es5.d.ts, --, --))
+>C : Symbol(C, Decl(evolvingArrayResolvedAssert.ts, 0, 3))
+>hasOwnProperty : Symbol(Object.hasOwnProperty, Decl(lib.es5.d.ts, --, --))
+>a : Symbol(a, Decl(evolvingArrayResolvedAssert.ts, 1, 8))
+    }
+}
+
diff --git a/tests/baselines/reference/evolvingArrayResolvedAssert.types b/tests/baselines/reference/evolvingArrayResolvedAssert.types
new file mode 100644
index 00000000..b0524c27
--- /dev/null
+++ b/tests/baselines/reference/evolvingArrayResolvedAssert.types
@@ -0,0 +1,18 @@
+=== tests/cases/compiler/evolvingArrayResolvedAssert.ts ===
+var C = [];
+>C : any[]
+>[] : never[]
+
+for (var a in C) {
+>a : string
+>C : any[]
+
+    if (C.hasOwnProperty(a)) {
+>C.hasOwnProperty(a) : boolean
+>C.hasOwnProperty : (v: PropertyKey) => boolean
+>C : any[]
+>hasOwnProperty : (v: PropertyKey) => boolean
+>a : string
+    }
+}
+
diff --git a/tests/baselines/reference/numberVsBigIntOperations.errors.txt b/tests/baselines/reference/numberVsBigIntOperations.errors.txt
index 42e49eb3..e5ad663d 100644
--- a/tests/baselines/reference/numberVsBigIntOperations.errors.txt
+++ b/tests/baselines/reference/numberVsBigIntOperations.errors.txt
@@ -62,9 +62,11 @@ tests/cases/compiler/numberVsBigIntOperations.ts(61,1): error TS2365: Operator '
 tests/cases/compiler/numberVsBigIntOperations.ts(70,2): error TS2736: Operator '+' cannot be applied to type 'number | bigint'.
 tests/cases/compiler/numberVsBigIntOperations.ts(86,7): error TS1155: 'const' declarations must be initialized.
 tests/cases/compiler/numberVsBigIntOperations.ts(93,7): error TS1155: 'const' declarations must be initialized.
+tests/cases/compiler/numberVsBigIntOperations.ts(98,6): error TS2736: Operator '+' cannot be applied to type 'S'.
+tests/cases/compiler/numberVsBigIntOperations.ts(99,5): error TS2365: Operator '+' cannot be applied to types 'number' and 'S'.

-==== tests/cases/compiler/numberVsBigIntOperations.ts (64 errors) ====
+==== tests/cases/compiler/numberVsBigIntOperations.ts (66 errors) ====
     // Cannot mix bigints and numbers
     let bigInt = 1n, num = 2;
     bigInt = 1n; bigInt = 2; num = 1n; num = 2;
@@ -286,4 +288,15 @@ tests/cases/compiler/numberVsBigIntOperations.ts(93,7): error TS1155: 'const' de
     const bigZeroOrOne: 0n | 1;
           ~~~~~~~~~~~~
 !!! error TS1155: 'const' declarations must be initialized.
-    if (bigZeroOrOne) isOne(bigZeroOrOne);
\ No newline at end of file
+    if (bigZeroOrOne) isOne(bigZeroOrOne);
+
+    type NumberOrBigint = number | bigint;
+    function getKey<S extends NumberOrBigint>(key: S) {
+        +key;   // should error
+         ~~~
+!!! error TS2736: Operator '+' cannot be applied to type 'S'.
+        0 + key;    // should error
+        ~~~~~~~
+!!! error TS2365: Operator '+' cannot be applied to types 'number' and 'S'.
+    }
+
\ No newline at end of file
diff --git a/tests/baselines/reference/numberVsBigIntOperations.js b/tests/baselines/reference/numberVsBigIntOperations.js
index 9d8a4920..3558a073 100644
--- a/tests/baselines/reference/numberVsBigIntOperations.js
+++ b/tests/baselines/reference/numberVsBigIntOperations.js
@@ -92,7 +92,14 @@ else isNumber(zeroOrBigOne);
 const isOne = (x: 1 | 1n) => x;
 if (zeroOrBigOne) isOne(zeroOrBigOne);
 const bigZeroOrOne: 0n | 1;
-if (bigZeroOrOne) isOne(bigZeroOrOne);
+if (bigZeroOrOne) isOne(bigZeroOrOne);
+
+type NumberOrBigint = number | bigint;
+function getKey<S extends NumberOrBigint>(key: S) {
+    +key;   // should error
+    0 + key;    // should error
+}
+

 //// [numberVsBigIntOperations.js]
 // Cannot mix bigints and numbers
@@ -272,3 +279,7 @@ if (zeroOrBigOne)
 const bigZeroOrOne;
 if (bigZeroOrOne)
     isOne(bigZeroOrOne);
+function getKey(key) {
+    +key; // should error
+    0 + key; // should error
+}
diff --git a/tests/baselines/reference/numberVsBigIntOperations.symbols b/tests/baselines/reference/numberVsBigIntOperations.symbols
index 1b164afb..e9f91b8d 100644
--- a/tests/baselines/reference/numberVsBigIntOperations.symbols
+++ b/tests/baselines/reference/numberVsBigIntOperations.symbols
@@ -348,3 +348,20 @@ if (bigZeroOrOne) isOne(bigZeroOrOne);
 >isOne : Symbol(isOne, Decl(numberVsBigIntOperations.ts, 90, 5))
 >bigZeroOrOne : Symbol(bigZeroOrOne, Decl(numberVsBigIntOperations.ts, 92, 5))

+type NumberOrBigint = number | bigint;
+>NumberOrBigint : Symbol(NumberOrBigint, Decl(numberVsBigIntOperations.ts, 93, 38))
+
+function getKey<S extends NumberOrBigint>(key: S) {
+>getKey : Symbol(getKey, Decl(numberVsBigIntOperations.ts, 95, 38))
+>S : Symbol(S, Decl(numberVsBigIntOperations.ts, 96, 16))
+>NumberOrBigint : Symbol(NumberOrBigint, Decl(numberVsBigIntOperations.ts, 93, 38))
+>key : Symbol(key, Decl(numberVsBigIntOperations.ts, 96, 42))
+>S : Symbol(S, Decl(numberVsBigIntOperations.ts, 96, 16))
+
+    +key;   // should error
+>key : Symbol(key, Decl(numberVsBigIntOperations.ts, 96, 42))
+
+    0 + key;    // should error
+>key : Symbol(key, Decl(numberVsBigIntOperations.ts, 96, 42))
+}
+
diff --git a/tests/baselines/reference/numberVsBigIntOperations.types b/tests/baselines/reference/numberVsBigIntOperations.types
index ddb81030..4fc625d3 100644
--- a/tests/baselines/reference/numberVsBigIntOperations.types
+++ b/tests/baselines/reference/numberVsBigIntOperations.types
@@ -727,3 +727,20 @@ if (bigZeroOrOne) isOne(bigZeroOrOne);
 >isOne : (x: 1n | 1) => 1n | 1
 >bigZeroOrOne : 1

+type NumberOrBigint = number | bigint;
+>NumberOrBigint : number | bigint
+
+function getKey<S extends NumberOrBigint>(key: S) {
+>getKey : <S extends NumberOrBigint>(key: S) => void
+>key : S
+
+    +key;   // should error
+>+key : number
+>key : S
+
+    0 + key;    // should error
+>0 + key : any
+>0 : 0
+>key : S
+}
+
diff --git a/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.js b/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.js
index d952cf8b..c4232420 100644
--- a/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.js
+++ b/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.js
@@ -1,6 +1,8 @@
 //// [parameterPropertyInConstructorWithPrologues.ts]
 // https://github.com/microsoft/TypeScript/issues/48671

+class C {}
+
 class Foo1 {
   constructor(private A: string) {
     "ngInject1";
@@ -43,10 +45,65 @@ class Foo6 {
     console.log("hi");
   }
 }
+
+class Foo7 extends C {
+  constructor(
+    private member: boolean,
+  ) {
+    "ngInject1";
+    super();
+    console.log("hi");
+  }
+}
+
+class Foo8 extends C {
+  constructor(
+    private member: boolean,
+  ) {
+    "ngInject1";
+    super();
+    this.m();
+    console.log("hi");
+  }
+
+  m() {}
+}
+
+class Foo9 extends C {
+  constructor() {
+    "ngInject1";
+    "ngInject2";
+    super();
+    this.m();
+    console.log("hi");
+  }
+
+  m() {}
+}

 //// [parameterPropertyInConstructorWithPrologues.js]
 // https://github.com/microsoft/TypeScript/issues/48671
+var __extends = (this && this.__extends) || (function () {
+    var extendStatics = function (d, b) {
+        extendStatics = Object.setPrototypeOf ||
+            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
+        return extendStatics(d, b);
+    };
+    return function (d, b) {
+        if (typeof b !== "function" && b !== null)
+            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
+        extendStatics(d, b);
+        function __() { this.constructor = d; }
+        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+    };
+})();
+var C = /** @class */ (function () {
+    function C() {
+    }
+    return C;
+}());
 var Foo1 = /** @class */ (function () {
     function Foo1(A) {
         "ngInject1";
@@ -102,3 +159,40 @@ var Foo6 = /** @class */ (function () {
     }
     return Foo6;
 }());
+var Foo7 = /** @class */ (function (_super) {
+    __extends(Foo7, _super);
+    function Foo7(member) {
+        "ngInject1";
+        var _this = _super.call(this) || this;
+        _this.member = member;
+        console.log("hi");
+        return _this;
+    }
+    return Foo7;
+}(C));
+var Foo8 = /** @class */ (function (_super) {
+    __extends(Foo8, _super);
+    function Foo8(member) {
+        "ngInject1";
+        var _this = _super.call(this) || this;
+        _this.member = member;
+        _this.m();
+        console.log("hi");
+        return _this;
+    }
+    Foo8.prototype.m = function () { };
+    return Foo8;
+}(C));
+var Foo9 = /** @class */ (function (_super) {
+    __extends(Foo9, _super);
+    function Foo9() {
+        "ngInject1";
+        "ngInject2";
+        var _this = _super.call(this) || this;
+        _this.m();
+        console.log("hi");
+        return _this;
+    }
+    Foo9.prototype.m = function () { };
+    return Foo9;
+}(C));
diff --git a/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.symbols b/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.symbols
index 582bfd76..7e2adfcb 100644
--- a/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.symbols
+++ b/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.symbols
@@ -1,22 +1,25 @@
 === tests/cases/compiler/parameterPropertyInConstructorWithPrologues.ts ===
 // https://github.com/microsoft/TypeScript/issues/48671

+class C {}
+>C : Symbol(C, Decl(parameterPropertyInConstructorWithPrologues.ts, 0, 0))
+
 class Foo1 {
->Foo1 : Symbol(Foo1, Decl(parameterPropertyInConstructorWithPrologues.ts, 0, 0))
+>Foo1 : Symbol(Foo1, Decl(parameterPropertyInConstructorWithPrologues.ts, 2, 10))

   constructor(private A: string) {
->A : Symbol(Foo1.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 3, 14))
+>A : Symbol(Foo1.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 5, 14))

     "ngInject1";
   }
 }

 class Foo2 {
->Foo2 : Symbol(Foo2, Decl(parameterPropertyInConstructorWithPrologues.ts, 6, 1))
+>Foo2 : Symbol(Foo2, Decl(parameterPropertyInConstructorWithPrologues.ts, 8, 1))

   constructor(private A: string, private B: string) {
->A : Symbol(Foo2.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 9, 14))
->B : Symbol(Foo2.B, Decl(parameterPropertyInConstructorWithPrologues.ts, 9, 32))
+>A : Symbol(Foo2.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 11, 14))
+>B : Symbol(Foo2.B, Decl(parameterPropertyInConstructorWithPrologues.ts, 11, 32))

     "ngInject1";
     "ngInject2";
@@ -24,12 +27,12 @@ class Foo2 {
 }

 class Foo3 {
->Foo3 : Symbol(Foo3, Decl(parameterPropertyInConstructorWithPrologues.ts, 13, 1))
+>Foo3 : Symbol(Foo3, Decl(parameterPropertyInConstructorWithPrologues.ts, 15, 1))

   constructor(private A: string, private B: string, private C: string) {
->A : Symbol(Foo3.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 16, 14))
->B : Symbol(Foo3.B, Decl(parameterPropertyInConstructorWithPrologues.ts, 16, 32))
->C : Symbol(Foo3.C, Decl(parameterPropertyInConstructorWithPrologues.ts, 16, 51))
+>A : Symbol(Foo3.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 18, 14))
+>B : Symbol(Foo3.B, Decl(parameterPropertyInConstructorWithPrologues.ts, 18, 32))
+>C : Symbol(Foo3.C, Decl(parameterPropertyInConstructorWithPrologues.ts, 18, 51))

     "ngInject1";
     "ngInject2";
@@ -37,10 +40,10 @@ class Foo3 {
 }

 class Foo4 {
->Foo4 : Symbol(Foo4, Decl(parameterPropertyInConstructorWithPrologues.ts, 20, 1))
+>Foo4 : Symbol(Foo4, Decl(parameterPropertyInConstructorWithPrologues.ts, 22, 1))

   constructor(private A: string) {
->A : Symbol(Foo4.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 23, 14))
+>A : Symbol(Foo4.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 25, 14))

     "ngInject1";
     console.log("hi");
@@ -51,11 +54,11 @@ class Foo4 {
 }

 class Foo5 {
->Foo5 : Symbol(Foo5, Decl(parameterPropertyInConstructorWithPrologues.ts, 27, 1))
+>Foo5 : Symbol(Foo5, Decl(parameterPropertyInConstructorWithPrologues.ts, 29, 1))

   constructor(private A: string, private B: string) {
->A : Symbol(Foo5.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 30, 14))
->B : Symbol(Foo5.B, Decl(parameterPropertyInConstructorWithPrologues.ts, 30, 32))
+>A : Symbol(Foo5.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 32, 14))
+>B : Symbol(Foo5.B, Decl(parameterPropertyInConstructorWithPrologues.ts, 32, 32))

     "ngInject1";
     "ngInject2";
@@ -67,19 +70,92 @@ class Foo5 {
 }

 class Foo6 {
->Foo6 : Symbol(Foo6, Decl(parameterPropertyInConstructorWithPrologues.ts, 35, 1))
+>Foo6 : Symbol(Foo6, Decl(parameterPropertyInConstructorWithPrologues.ts, 37, 1))

   constructor(private A: string, private B: string, private C: string) {
->A : Symbol(Foo6.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 38, 14))
->B : Symbol(Foo6.B, Decl(parameterPropertyInConstructorWithPrologues.ts, 38, 32))
->C : Symbol(Foo6.C, Decl(parameterPropertyInConstructorWithPrologues.ts, 38, 51))
+>A : Symbol(Foo6.A, Decl(parameterPropertyInConstructorWithPrologues.ts, 40, 14))
+>B : Symbol(Foo6.B, Decl(parameterPropertyInConstructorWithPrologues.ts, 40, 32))
+>C : Symbol(Foo6.C, Decl(parameterPropertyInConstructorWithPrologues.ts, 40, 51))
+
+    "ngInject1";
+    "ngInject2";
+    console.log("hi");
+>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
+>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+  }
+}
+
+class Foo7 extends C {
+>Foo7 : Symbol(Foo7, Decl(parameterPropertyInConstructorWithPrologues.ts, 45, 1))
+>C : Symbol(C, Decl(parameterPropertyInConstructorWithPrologues.ts, 0, 0))
+
+  constructor(
+    private member: boolean,
+>member : Symbol(Foo7.member, Decl(parameterPropertyInConstructorWithPrologues.ts, 48, 14))
+
+  ) {
+    "ngInject1";
+    super();
+>super : Symbol(C, Decl(parameterPropertyInConstructorWithPrologues.ts, 0, 0))
+
+    console.log("hi");
+>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
+>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+  }
+}
+
+class Foo8 extends C {
+>Foo8 : Symbol(Foo8, Decl(parameterPropertyInConstructorWithPrologues.ts, 55, 1))
+>C : Symbol(C, Decl(parameterPropertyInConstructorWithPrologues.ts, 0, 0))

+  constructor(
+    private member: boolean,
+>member : Symbol(Foo8.member, Decl(parameterPropertyInConstructorWithPrologues.ts, 58, 14))
+
+  ) {
+    "ngInject1";
+    super();
+>super : Symbol(C, Decl(parameterPropertyInConstructorWithPrologues.ts, 0, 0))
+
+    this.m();
+>this.m : Symbol(Foo8.m, Decl(parameterPropertyInConstructorWithPrologues.ts, 65, 3))
+>this : Symbol(Foo8, Decl(parameterPropertyInConstructorWithPrologues.ts, 55, 1))
+>m : Symbol(Foo8.m, Decl(parameterPropertyInConstructorWithPrologues.ts, 65, 3))
+
+    console.log("hi");
+>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+>console : Symbol(console, Decl(lib.dom.d.ts, --, --))
+>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
+  }
+
+  m() {}
+>m : Symbol(Foo8.m, Decl(parameterPropertyInConstructorWithPrologues.ts, 65, 3))
+}
+
+class Foo9 extends C {
+>Foo9 : Symbol(Foo9, Decl(parameterPropertyInConstructorWithPrologues.ts, 68, 1))
+>C : Symbol(C, Decl(parameterPropertyInConstructorWithPrologues.ts, 0, 0))
+
+  constructor() {
     "ngInject1";
     "ngInject2";
+    super();
+>super : Symbol(C, Decl(parameterPropertyInConstructorWithPrologues.ts, 0, 0))
+
+    this.m();
+>this.m : Symbol(Foo9.m, Decl(parameterPropertyInConstructorWithPrologues.ts, 77, 3))
+>this : Symbol(Foo9, Decl(parameterPropertyInConstructorWithPrologues.ts, 68, 1))
+>m : Symbol(Foo9.m, Decl(parameterPropertyInConstructorWithPrologues.ts, 77, 3))
+
     console.log("hi");
 >console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
 >console : Symbol(console, Decl(lib.dom.d.ts, --, --))
 >log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --))
   }
+
+  m() {}
+>m : Symbol(Foo9.m, Decl(parameterPropertyInConstructorWithPrologues.ts, 77, 3))
 }

diff --git a/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.types b/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.types
index 2f676ee3..857196e3 100644
--- a/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.types
+++ b/tests/baselines/reference/parameterPropertyInConstructorWithPrologues.types
@@ -1,6 +1,9 @@
 === tests/cases/compiler/parameterPropertyInConstructorWithPrologues.ts ===
 // https://github.com/microsoft/TypeScript/issues/48671

+class C {}
+>C : C
+
 class Foo1 {
 >Foo1 : Foo1

@@ -106,3 +109,95 @@ class Foo6 {
   }
 }

+class Foo7 extends C {
+>Foo7 : Foo7
+>C : C
+
+  constructor(
+    private member: boolean,
+>member : boolean
+
+  ) {
+    "ngInject1";
+>"ngInject1" : "ngInject1"
+
+    super();
+>super() : void
+>super : typeof C
+
+    console.log("hi");
+>console.log("hi") : void
+>console.log : (...data: any[]) => void
+>console : Console
+>log : (...data: any[]) => void
+>"hi" : "hi"
+  }
+}
+
+class Foo8 extends C {
+>Foo8 : Foo8
+>C : C
+
+  constructor(
+    private member: boolean,
+>member : boolean
+
+  ) {
+    "ngInject1";
+>"ngInject1" : "ngInject1"
+
+    super();
+>super() : void
+>super : typeof C
+
+    this.m();
+>this.m() : void
+>this.m : () => void
+>this : this
+>m : () => void
+
+    console.log("hi");
+>console.log("hi") : void
+>console.log : (...data: any[]) => void
+>console : Console
+>log : (...data: any[]) => void
+>"hi" : "hi"
+  }
+
+  m() {}
+>m : () => void
+}
+
+class Foo9 extends C {
+>Foo9 : Foo9
+>C : C
+
+  constructor() {
+    "ngInject1";
+>"ngInject1" : "ngInject1"
+
+    "ngInject2";
+>"ngInject2" : "ngInject2"
+
+    super();
+>super() : void
+>super : typeof C
+
+    this.m();
+>this.m() : void
+>this.m : () => void
+>this : this
+>m : () => void
+
+    console.log("hi");
+>console.log("hi") : void
+>console.log : (...data: any[]) => void
+>console : Console
+>log : (...data: any[]) => void
+>"hi" : "hi"
+  }
+
+  m() {}
+>m : () => void
+}
+
diff --git a/tests/baselines/reference/parserSuperExpression2.symbols b/tests/baselines/reference/parserSuperExpression2.symbols
index c382e548..47fff63a 100644
--- a/tests/baselines/reference/parserSuperExpression2.symbols
+++ b/tests/baselines/reference/parserSuperExpression2.symbols
@@ -6,5 +6,6 @@ class C {
 >M : Symbol(C.M, Decl(parserSuperExpression2.ts, 0, 9))

     super<T>(0);
+>T : Symbol(T)
   }
 }
diff --git a/tests/baselines/reference/superWithTypeArgument.symbols b/tests/baselines/reference/superWithTypeArgument.symbols
index 50990b48..eeb59199 100644
--- a/tests/baselines/reference/superWithTypeArgument.symbols
+++ b/tests/baselines/reference/superWithTypeArgument.symbols
@@ -12,5 +12,6 @@ class D<T> extends C {
     constructor() {
         super<T>();
 >super : Symbol(C, Decl(superWithTypeArgument.ts, 0, 0))
+>T : Symbol(T, Decl(superWithTypeArgument.ts, 4, 8))
     }
 }
diff --git a/tests/baselines/reference/superWithTypeArgument2.symbols b/tests/baselines/reference/superWithTypeArgument2.symbols
index 35a371cd..c42450e8 100644
--- a/tests/baselines/reference/superWithTypeArgument2.symbols
+++ b/tests/baselines/reference/superWithTypeArgument2.symbols
@@ -19,6 +19,7 @@ class D<T> extends C<T> {

         super<T>(x);
 >super : Symbol(C, Decl(superWithTypeArgument2.ts, 0, 0))
+>T : Symbol(T, Decl(superWithTypeArgument2.ts, 4, 8))
 >x : Symbol(x, Decl(superWithTypeArgument2.ts, 5, 16))
     }
 }
diff --git a/tests/baselines/reference/superWithTypeArgument3.symbols b/tests/baselines/reference/superWithTypeArgument3.symbols
index a596264a..9a6ff935 100644
--- a/tests/baselines/reference/superWithTypeArgument3.symbols
+++ b/tests/baselines/reference/superWithTypeArgument3.symbols
@@ -23,6 +23,7 @@ class D<T> extends C<T> {
     constructor() {
         super<T>();
 >super : Symbol(C, Decl(superWithTypeArgument3.ts, 0, 0))
+>T : Symbol(T, Decl(superWithTypeArgument3.ts, 5, 8))
     }
     bar() {
 >bar : Symbol(D.bar, Decl(superWithTypeArgument3.ts, 8, 5))
diff --git a/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.js b/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.js
new file mode 100644
index 00000000..2ae16666
--- /dev/null
+++ b/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.js
@@ -0,0 +1,45 @@
+//// [typeTagOnFunctionReferencesGeneric.js]
+/**
+ * @typedef {<T>(m : T) => T} IFn
+ */
+
+/**@type {IFn}*/
+export function inJs(l) {
+    return l;
+}
+inJs(1); // lints error. Why?
+
+/**@type {IFn}*/
+const inJsArrow = (j) => {
+    return j;
+}
+inJsArrow(2); // no error gets linted as expected
+
+
+//// [typeTagOnFunctionReferencesGeneric.js]
+"use strict";
+/**
+ * @typedef {<T>(m : T) => T} IFn
+ */
+exports.__esModule = true;
+exports.inJs = void 0;
+/**@type {IFn}*/
+function inJs(l) {
+    return l;
+}
+exports.inJs = inJs;
+inJs(1); // lints error. Why?
+/**@type {IFn}*/
+var inJsArrow = function (j) {
+    return j;
+};
+inJsArrow(2); // no error gets linted as expected
+
+
+//// [typeTagOnFunctionReferencesGeneric.d.ts]
+/**
+ * @typedef {<T>(m : T) => T} IFn
+ */
+/**@type {IFn}*/
+export function inJs<T>(l: T): T;
+export type IFn = <T>(m: T) => T;
diff --git a/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.symbols b/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.symbols
new file mode 100644
index 00000000..10e9e580
--- /dev/null
+++ b/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.symbols
@@ -0,0 +1,27 @@
+=== tests/cases/conformance/salsa/typeTagOnFunctionReferencesGeneric.js ===
+/**
+ * @typedef {<T>(m : T) => T} IFn
+ */
+
+/**@type {IFn}*/
+export function inJs(l) {
+>inJs : Symbol(inJs, Decl(typeTagOnFunctionReferencesGeneric.js, 0, 0))
+>l : Symbol(l, Decl(typeTagOnFunctionReferencesGeneric.js, 5, 21))
+
+    return l;
+>l : Symbol(l, Decl(typeTagOnFunctionReferencesGeneric.js, 5, 21))
+}
+inJs(1); // lints error. Why?
+>inJs : Symbol(inJs, Decl(typeTagOnFunctionReferencesGeneric.js, 0, 0))
+
+/**@type {IFn}*/
+const inJsArrow = (j) => {
+>inJsArrow : Symbol(inJsArrow, Decl(typeTagOnFunctionReferencesGeneric.js, 11, 5))
+>j : Symbol(j, Decl(typeTagOnFunctionReferencesGeneric.js, 11, 19))
+
+    return j;
+>j : Symbol(j, Decl(typeTagOnFunctionReferencesGeneric.js, 11, 19))
+}
+inJsArrow(2); // no error gets linted as expected
+>inJsArrow : Symbol(inJsArrow, Decl(typeTagOnFunctionReferencesGeneric.js, 11, 5))
+
diff --git a/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.types b/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.types
new file mode 100644
index 00000000..eb4f7183
--- /dev/null
+++ b/tests/baselines/reference/typeTagOnFunctionReferencesGeneric.types
@@ -0,0 +1,32 @@
+=== tests/cases/conformance/salsa/typeTagOnFunctionReferencesGeneric.js ===
+/**
+ * @typedef {<T>(m : T) => T} IFn
+ */
+
+/**@type {IFn}*/
+export function inJs(l) {
+>inJs : <T>(l: T) => T
+>l : T
+
+    return l;
+>l : T
+}
+inJs(1); // lints error. Why?
+>inJs(1) : 1
+>inJs : <T>(l: T) => T
+>1 : 1
+
+/**@type {IFn}*/
+const inJsArrow = (j) => {
+>inJsArrow : IFn
+>(j) => {    return j;} : <T>(j: T) => T
+>j : T
+
+    return j;
+>j : T
+}
+inJsArrow(2); // no error gets linted as expected
+>inJsArrow(2) : 2
+>inJsArrow : IFn
+>2 : 2
+
diff --git a/tests/cases/compiler/classMemberInitializerScoping2.ts b/tests/cases/compiler/classMemberInitializerScoping2.ts
new file mode 100644
index 00000000..583d9f03
--- /dev/null
+++ b/tests/cases/compiler/classMemberInitializerScoping2.ts
@@ -0,0 +1,8 @@
+// @target: es2017,esnext
+// @useDefineForClassFields: true,false
+
+const x = 1
+class C {
+    p = x
+    constructor(x: string) { }
+}
diff --git a/tests/cases/compiler/evolvingArrayResolvedAssert.ts b/tests/cases/compiler/evolvingArrayResolvedAssert.ts
new file mode 100644
index 00000000..7ba37947
--- /dev/null
+++ b/tests/cases/compiler/evolvingArrayResolvedAssert.ts
@@ -0,0 +1,7 @@
+// @strict: true
+
+var C = [];
+for (var a in C) {
+    if (C.hasOwnProperty(a)) {
+    }
+}
diff --git a/tests/cases/compiler/numberVsBigIntOperations.ts b/tests/cases/compiler/numberVsBigIntOperations.ts
index 74b1cea8..f53b3a14 100644
--- a/tests/cases/compiler/numberVsBigIntOperations.ts
+++ b/tests/cases/compiler/numberVsBigIntOperations.ts
@@ -93,4 +93,10 @@ else isNumber(zeroOrBigOne);
 const isOne = (x: 1 | 1n) => x;
 if (zeroOrBigOne) isOne(zeroOrBigOne);
 const bigZeroOrOne: 0n | 1;
-if (bigZeroOrOne) isOne(bigZeroOrOne);
\ No newline at end of file
+if (bigZeroOrOne) isOne(bigZeroOrOne);
+
+type NumberOrBigint = number | bigint;
+function getKey<S extends NumberOrBigint>(key: S) {
+    +key;   // should error
+    0 + key;    // should error
+}
diff --git a/tests/cases/compiler/parameterPropertyInConstructorWithPrologues.ts b/tests/cases/compiler/parameterPropertyInConstructorWithPrologues.ts
index aa6acde1..45b20b36 100644
--- a/tests/cases/compiler/parameterPropertyInConstructorWithPrologues.ts
+++ b/tests/cases/compiler/parameterPropertyInConstructorWithPrologues.ts
@@ -1,5 +1,7 @@
 // https://github.com/microsoft/TypeScript/issues/48671

+class C {}
+
 class Foo1 {
   constructor(private A: string) {
     "ngInject1";
@@ -42,3 +44,38 @@ class Foo6 {
     c…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants