Skip to content

Commit 3519af0

Browse files
authored
Fix crash pulling on global types before they're initialized (#46471)
* Add failing test * Dumb fix * Compute error message info more lazily * One more laziness
1 parent 6b6665e commit 3519af0

File tree

6 files changed

+114
-10
lines changed

6 files changed

+114
-10
lines changed

src/compiler/checker.ts

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3275,21 +3275,40 @@ namespace ts {
32753275
const namespaceName = getFullyQualifiedName(namespace);
32763276
const declarationName = declarationNameToString(right);
32773277
const suggestionForNonexistentModule = getSuggestedSymbolForNonexistentModule(right, namespace);
3278-
const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type));
3279-
const containingQualifiedName = isQualifiedName(name) && getContainingQualifiedNameNode(name);
3280-
const canSuggestTypeof = containingQualifiedName && !isTypeOfExpression(containingQualifiedName.parent) && tryGetQualifiedNameAsValue(containingQualifiedName);
32813278
if (suggestionForNonexistentModule) {
32823279
error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestionForNonexistentModule));
3280+
return undefined;
32833281
}
3284-
else if (canSuggestTypeof) {
3285-
error(containingQualifiedName, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, entityNameToString(containingQualifiedName));
3286-
}
3287-
else if (meaning & SymbolFlags.Namespace && exportedTypeSymbol && isQualifiedName(name.parent)) {
3288-
error(name.parent.right, Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1, symbolToString(exportedTypeSymbol), unescapeLeadingUnderscores(name.parent.right.escapedText));
3282+
3283+
const containingQualifiedName = isQualifiedName(name) && getContainingQualifiedNameNode(name);
3284+
const canSuggestTypeof = globalObjectType // <-- can't pull on types if global types aren't initialized yet
3285+
&& (meaning & SymbolFlags.Type)
3286+
&& containingQualifiedName
3287+
&& !isTypeOfExpression(containingQualifiedName.parent)
3288+
&& tryGetQualifiedNameAsValue(containingQualifiedName);
3289+
if (canSuggestTypeof) {
3290+
error(
3291+
containingQualifiedName,
3292+
Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0,
3293+
entityNameToString(containingQualifiedName)
3294+
);
3295+
return undefined;
32893296
}
3290-
else {
3291-
error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName);
3297+
3298+
if (meaning & SymbolFlags.Namespace && isQualifiedName(name.parent)) {
3299+
const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type));
3300+
if (exportedTypeSymbol) {
3301+
error(
3302+
name.parent.right,
3303+
Diagnostics.Cannot_access_0_1_because_0_is_a_type_but_not_a_namespace_Did_you_mean_to_retrieve_the_type_of_the_property_1_in_0_with_0_1,
3304+
symbolToString(exportedTypeSymbol),
3305+
unescapeLeadingUnderscores(name.parent.right.escapedText)
3306+
);
3307+
return undefined;
3308+
}
32923309
}
3310+
3311+
error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName);
32933312
}
32943313
return undefined;
32953314
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/globals.ts(5,22): error TS2694: Namespace 'globals' has no exported member 'toString'.
2+
3+
4+
==== /globals.ts (1 errors) ====
5+
namespace globals {
6+
export type Foo = {};
7+
export const Bar = {};
8+
}
9+
import Foo = globals.toString.Blah;
10+
~~~~~~~~
11+
!!! error TS2694: Namespace 'globals' has no exported member 'toString'.
12+
13+
==== /index.ts (0 errors) ====
14+
const Foo = {};
15+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
//// [tests/cases/compiler/importEqualsError45874.ts] ////
2+
3+
//// [globals.ts]
4+
namespace globals {
5+
export type Foo = {};
6+
export const Bar = {};
7+
}
8+
import Foo = globals.toString.Blah;
9+
10+
//// [index.ts]
11+
const Foo = {};
12+
13+
14+
//// [globals.js]
15+
var globals;
16+
(function (globals) {
17+
globals.Bar = {};
18+
})(globals || (globals = {}));
19+
var Foo = globals.toString.Blah;
20+
//// [index.js]
21+
var Foo = {};
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
=== /globals.ts ===
2+
namespace globals {
3+
>globals : Symbol(globals, Decl(globals.ts, 0, 0))
4+
5+
export type Foo = {};
6+
>Foo : Symbol(Foo, Decl(globals.ts, 0, 19))
7+
8+
export const Bar = {};
9+
>Bar : Symbol(Bar, Decl(globals.ts, 2, 14))
10+
}
11+
import Foo = globals.toString.Blah;
12+
>Foo : Symbol(Foo, Decl(globals.ts, 3, 1))
13+
>globals : Symbol(globals, Decl(globals.ts, 0, 0))
14+
15+
=== /index.ts ===
16+
const Foo = {};
17+
>Foo : Symbol(Foo, Decl(index.ts, 0, 5))
18+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
=== /globals.ts ===
2+
namespace globals {
3+
>globals : typeof globals
4+
5+
export type Foo = {};
6+
>Foo : Foo
7+
8+
export const Bar = {};
9+
>Bar : {}
10+
>{} : {}
11+
}
12+
import Foo = globals.toString.Blah;
13+
>Foo : any
14+
>globals : typeof globals
15+
>toString : any
16+
>Blah : any
17+
18+
=== /index.ts ===
19+
const Foo = {};
20+
>Foo : {}
21+
>{} : {}
22+
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// @Filename: /globals.ts
2+
namespace globals {
3+
export type Foo = {};
4+
export const Bar = {};
5+
}
6+
import Foo = globals.toString.Blah;
7+
8+
// @Filename: /index.ts
9+
const Foo = {};

0 commit comments

Comments
 (0)