Skip to content

Fix(50161): Instantiation expressions trigger incorrect error messages #52373

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

Merged
merged 9 commits into from
Jan 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44696,7 +44696,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
return node.parent.kind === SyntaxKind.TypeReference;
}

function isHeritageClauseElementIdentifier(node: Node): boolean {
function isInNameOfExpressionWithTypeArguments(node: Node): boolean {
while (node.parent.kind === SyntaxKind.PropertyAccessExpression) {
node = node.parent;
}
Expand Down Expand Up @@ -44822,11 +44822,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
name = name.parent as QualifiedName | PropertyAccessEntityNameExpression | JSDocMemberName;
}

if (isHeritageClauseElementIdentifier(name)) {
if (isInNameOfExpressionWithTypeArguments(name)) {
let meaning = SymbolFlags.None;
// In an interface or class, we're definitely interested in a type.
if (name.parent.kind === SyntaxKind.ExpressionWithTypeArguments) {
meaning = SymbolFlags.Type;
// An 'ExpressionWithTypeArguments' may appear in type space (interface Foo extends Bar<T>),
// value space (return foo<T>), or both(class Foo extends Bar<T>); ensure the meaning matches.
meaning = isPartOfTypeNode(name) ? SymbolFlags.Type : SymbolFlags.Value;

// In a class 'extends' clause we are also looking for a value.
if (isExpressionWithTypeArgumentsInClassExtendsClause(name.parent)) {
Expand Down
1 change: 1 addition & 0 deletions src/testRunner/tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,4 @@ import "./unittests/tsserver/typingsInstaller";
import "./unittests/tsserver/versionCache";
import "./unittests/tsserver/watchEnvironment";
import "./unittests/debugDeprecation";
import "./unittests/tsserver/inconsistentErrorInEditor";
41 changes: 41 additions & 0 deletions src/testRunner/unittests/tsserver/inconsistentErrorInEditor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as ts from "../../_namespaces/ts";
import {
createServerHost,
} from "../virtualFileSystemWithWatch";
import {
baselineTsserverLogs,
createLoggerWithInMemoryLogs,
createSession,
verifyGetErrRequest,
} from "./helpers";
describe("unittests:: tsserver:: inconsistentErrorInEditor", () => {
it("should not error", () => {
const host = createServerHost([]);
const session = createSession(host, { canUseEvents: true, noGetErrOnBackgroundUpdate: true, logger: createLoggerWithInMemoryLogs(host) });
session.executeCommandSeq<ts.server.protocol.UpdateOpenRequest>({
command: ts.server.protocol.CommandTypes.UpdateOpen,
arguments: {
changedFiles: [],
closedFiles: [],
openFiles: [
{
file: "^/untitled/ts-nul-authority/Untitled-1",
fileContent: "export function foo<U>() {\r\n /*$*/return bar<U>;\r\n}\r\n\r\nexport function bar<T>(x: T) {\r\n return x;\r\n}\r\n\r\nlet x = foo()(42);",
scriptKindName: "TS"
}
]
}
});
session.executeCommandSeq<ts.server.protocol.EncodedSemanticClassificationsRequest>({
command: ts.server.protocol.CommandTypes.EncodedSemanticClassificationsFull,
arguments: {
file: "^/untitled/ts-nul-authority/Untitled-1",
start: 0,
length: 128,
format: "2020"
}
});
verifyGetErrRequest({ session, host, files: ["^/untitled/ts-nul-authority/Untitled-1"] });
baselineTsserverLogs("inconsistentErrorInEditor", "should not error", session);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ interface Base<T, U> {
// Error, no Base constructor function
class D0 extends Base<string, string> {
>D0 : Symbol(D0, Decl(classExtendingClassLikeType.ts, 3, 1))
>Base : Symbol(Base, Decl(classExtendingClassLikeType.ts, 0, 0))
}

interface BaseConstructor {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ interface I {
}
class C extends I { } // error
>C : Symbol(C, Decl(classExtendsEveryObjectType.ts, 2, 1))
>I : Symbol(I, Decl(classExtendsEveryObjectType.ts, 0, 0))

class C2 extends { foo: string; } { } // error
>C2 : Symbol(C2, Decl(classExtendsEveryObjectType.ts, 3, 21))
Expand Down
2 changes: 0 additions & 2 deletions tests/baselines/reference/classExtendsInterface.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ interface Comparable {}

class A extends Comparable {}
>A : Symbol(A, Decl(classExtendsInterface.ts, 0, 23))
>Comparable : Symbol(Comparable, Decl(classExtendsInterface.ts, 0, 0))

class B implements Comparable {}
>B : Symbol(B, Decl(classExtendsInterface.ts, 1, 29))
Expand All @@ -17,7 +16,6 @@ interface Comparable2<T> {}
class A2<T> extends Comparable2<T> {}
>A2 : Symbol(A2, Decl(classExtendsInterface.ts, 4, 27))
>T : Symbol(T, Decl(classExtendsInterface.ts, 5, 9))
>Comparable2 : Symbol(Comparable2, Decl(classExtendsInterface.ts, 2, 32))
>T : Symbol(T, Decl(classExtendsInterface.ts, 5, 9))

class B2<T> implements Comparable2<T> {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,12 @@ module M {
}
class C1 extends M.I1 {}
>C1 : Symbol(C1, Decl(classExtendsInterfaceInModule.ts, 3, 1))
>M.I1 : Symbol(M.I1, Decl(classExtendsInterfaceInModule.ts, 0, 10))
>M : Symbol(M, Decl(classExtendsInterfaceInModule.ts, 0, 0))
>I1 : Symbol(M.I1, Decl(classExtendsInterfaceInModule.ts, 0, 10))

class C2<T> extends M.I2<T> {}
>C2 : Symbol(C2, Decl(classExtendsInterfaceInModule.ts, 4, 24))
>T : Symbol(T, Decl(classExtendsInterfaceInModule.ts, 5, 9))
>M.I2 : Symbol(M.I2, Decl(classExtendsInterfaceInModule.ts, 1, 24))
>M : Symbol(M, Decl(classExtendsInterfaceInModule.ts, 0, 0))
>I2 : Symbol(M.I2, Decl(classExtendsInterfaceInModule.ts, 1, 24))
>T : Symbol(T, Decl(classExtendsInterfaceInModule.ts, 5, 9))

module Mod {
Expand All @@ -36,9 +32,7 @@ module Mod {

class D extends Mod.Nested.I {}
>D : Symbol(D, Decl(classExtendsInterfaceInModule.ts, 11, 1))
>Mod.Nested.I : Symbol(Mod.Nested.I, Decl(classExtendsInterfaceInModule.ts, 8, 26))
>Mod.Nested : Symbol(Mod.Nested, Decl(classExtendsInterfaceInModule.ts, 7, 12))
>Mod : Symbol(Mod, Decl(classExtendsInterfaceInModule.ts, 5, 30))
>Nested : Symbol(Mod.Nested, Decl(classExtendsInterfaceInModule.ts, 7, 12))
>I : Symbol(Mod.Nested.I, Decl(classExtendsInterfaceInModule.ts, 8, 26))

Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ var g = function f(x: I): I { var y: I; return y; }

class D extends I {
>D : Symbol(D, Decl(genericTypeReferenceWithoutTypeArgument2.ts, 17, 51))
>I : Symbol(I, Decl(genericTypeReferenceWithoutTypeArgument2.ts, 0, 0))
}

interface U extends I {}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,239 @@
Info 0 [00:00:02.000] Provided types map file "/a/lib/typesMap.json" doesn't exist
Info 1 [00:00:03.000] request:
{
"command": "updateOpen",
"arguments": {
"changedFiles": [],
"closedFiles": [],
"openFiles": [
{
"file": "^/untitled/ts-nul-authority/Untitled-1",
"fileContent": "export function foo<U>() {\r\n /*$*/return bar<U>;\r\n}\r\n\r\nexport function bar<T>(x: T) {\r\n return x;\r\n}\r\n\r\nlet x = foo()(42);",
"scriptKindName": "TS"
}
]
},
"seq": 1,
"type": "request"
}
Before request

PolledWatches::

FsWatches::

FsWatchesRecursive::

Info 2 [00:00:04.000] Search path: ^/untitled/ts-nul-authority
Info 3 [00:00:05.000] For info: ^/untitled/ts-nul-authority/Untitled-1 :: No config files found.
Info 4 [00:00:06.000] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
Info 5 [00:00:07.000] FileWatcher:: Added:: WatchInfo: /a/lib/lib.d.ts 500 undefined Project: /dev/null/inferredProject1* WatchType: Missing file
Info 6 [00:00:08.000] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* Version: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
Info 7 [00:00:09.000] Project '/dev/null/inferredProject1*' (Inferred)
Info 8 [00:00:10.000] Files (1)
^/untitled/ts-nul-authority/Untitled-1


^/untitled/ts-nul-authority/Untitled-1
Root file specified for compilation

Info 9 [00:00:11.000] -----------------------------------------------
Info 10 [00:00:12.000] Project '/dev/null/inferredProject1*' (Inferred)
Info 10 [00:00:13.000] Files (1)

Info 10 [00:00:14.000] -----------------------------------------------
Info 10 [00:00:15.000] Open files:
Info 10 [00:00:16.000] FileName: ^/untitled/ts-nul-authority/Untitled-1 ProjectRootPath: undefined
Info 10 [00:00:17.000] Projects: /dev/null/inferredProject1*
After request

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

Info 10 [00:00:18.000] response:
{
"response": true,
"responseRequired": true
}
Info 11 [00:00:19.000] request:
{
"command": "encodedSemanticClassifications-full",
"arguments": {
"file": "^/untitled/ts-nul-authority/Untitled-1",
"start": 0,
"length": 128,
"format": "2020"
},
"seq": 2,
"type": "request"
}
Before request

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

After request

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

Info 12 [00:00:20.000] response:
{
"response": {
"spans": [
16,
3,
2817,
20,
1,
1281,
44,
3,
2816,
48,
1,
1280,
74,
3,
2817,
78,
1,
1281,
81,
1,
1793,
84,
1,
1280,
101,
1,
1792,
114,
1,
2049,
118,
3,
2816
],
"endOfLineState": 0
},
"responseRequired": true
}
Info 13 [00:00:21.000] request:
{
"command": "geterr",
"arguments": {
"delay": 0,
"files": [
"^/untitled/ts-nul-authority/Untitled-1"
]
},
"seq": 3,
"type": "request"
}
Before request

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

After request

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

Info 14 [00:00:22.000] response:
{
"responseRequired": false
}
Before checking timeout queue length (1) and running

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

Info 15 [00:00:23.000] event:
{"seq":0,"type":"event","event":"syntaxDiag","body":{"file":"^/untitled/ts-nul-authority/Untitled-1","diagnostics":[]}}
After checking timeout queue length (1) and running

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

Before running immediate callbacks and checking length (1)

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

Info 16 [00:00:24.000] event:
{"seq":0,"type":"event","event":"semanticDiag","body":{"file":"^/untitled/ts-nul-authority/Untitled-1","diagnostics":[]}}
Before running immediate callbacks and checking length (1)

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

Before running immediate callbacks and checking length (1)

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::

Info 17 [00:00:25.000] event:
{"seq":0,"type":"event","event":"suggestionDiag","body":{"file":"^/untitled/ts-nul-authority/Untitled-1","diagnostics":[{"start":{"line":9,"offset":5},"end":{"line":9,"offset":6},"text":"'x' is declared but its value is never read.","code":6133,"category":"suggestion","reportsUnnecessary":true}]}}
Info 18 [00:00:26.000] event:
{"seq":0,"type":"event","event":"requestCompleted","body":{"request_seq":3}}
Before running immediate callbacks and checking length (1)

PolledWatches::
/a/lib/lib.d.ts:
{"pollingInterval":500}

FsWatches::

FsWatchesRecursive::