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
This commit is contained in:
Andrew Branch 2021-10-25 10:53:41 -07:00 committed by GitHub
parent 6b6665e6ae
commit 3519af0bab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 114 additions and 10 deletions

View file

@ -3275,21 +3275,40 @@ namespace ts {
const namespaceName = getFullyQualifiedName(namespace);
const declarationName = declarationNameToString(right);
const suggestionForNonexistentModule = getSuggestedSymbolForNonexistentModule(right, namespace);
const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type));
const containingQualifiedName = isQualifiedName(name) && getContainingQualifiedNameNode(name);
const canSuggestTypeof = containingQualifiedName && !isTypeOfExpression(containingQualifiedName.parent) && tryGetQualifiedNameAsValue(containingQualifiedName);
if (suggestionForNonexistentModule) {
error(right, Diagnostics._0_has_no_exported_member_named_1_Did_you_mean_2, namespaceName, declarationName, symbolToString(suggestionForNonexistentModule));
return undefined;
}
else if (canSuggestTypeof) {
error(containingQualifiedName, Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0, entityNameToString(containingQualifiedName));
const containingQualifiedName = isQualifiedName(name) && getContainingQualifiedNameNode(name);
const canSuggestTypeof = globalObjectType // <-- can't pull on types if global types aren't initialized yet
&& (meaning & SymbolFlags.Type)
&& containingQualifiedName
&& !isTypeOfExpression(containingQualifiedName.parent)
&& tryGetQualifiedNameAsValue(containingQualifiedName);
if (canSuggestTypeof) {
error(
containingQualifiedName,
Diagnostics._0_refers_to_a_value_but_is_being_used_as_a_type_here_Did_you_mean_typeof_0,
entityNameToString(containingQualifiedName)
);
return undefined;
}
else if (meaning & SymbolFlags.Namespace && exportedTypeSymbol && isQualifiedName(name.parent)) {
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));
}
else {
error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName);
if (meaning & SymbolFlags.Namespace && isQualifiedName(name.parent)) {
const exportedTypeSymbol = getMergedSymbol(getSymbol(getExportsOfSymbol(namespace), right.escapedText, SymbolFlags.Type));
if (exportedTypeSymbol) {
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)
);
return undefined;
}
}
error(right, Diagnostics.Namespace_0_has_no_exported_member_1, namespaceName, declarationName);
}
return undefined;
}

View file

@ -0,0 +1,15 @@
/globals.ts(5,22): error TS2694: Namespace 'globals' has no exported member 'toString'.
==== /globals.ts (1 errors) ====
namespace globals {
export type Foo = {};
export const Bar = {};
}
import Foo = globals.toString.Blah;
~~~~~~~~
!!! error TS2694: Namespace 'globals' has no exported member 'toString'.
==== /index.ts (0 errors) ====
const Foo = {};

View file

@ -0,0 +1,21 @@
//// [tests/cases/compiler/importEqualsError45874.ts] ////
//// [globals.ts]
namespace globals {
export type Foo = {};
export const Bar = {};
}
import Foo = globals.toString.Blah;
//// [index.ts]
const Foo = {};
//// [globals.js]
var globals;
(function (globals) {
globals.Bar = {};
})(globals || (globals = {}));
var Foo = globals.toString.Blah;
//// [index.js]
var Foo = {};

View file

@ -0,0 +1,18 @@
=== /globals.ts ===
namespace globals {
>globals : Symbol(globals, Decl(globals.ts, 0, 0))
export type Foo = {};
>Foo : Symbol(Foo, Decl(globals.ts, 0, 19))
export const Bar = {};
>Bar : Symbol(Bar, Decl(globals.ts, 2, 14))
}
import Foo = globals.toString.Blah;
>Foo : Symbol(Foo, Decl(globals.ts, 3, 1))
>globals : Symbol(globals, Decl(globals.ts, 0, 0))
=== /index.ts ===
const Foo = {};
>Foo : Symbol(Foo, Decl(index.ts, 0, 5))

View file

@ -0,0 +1,22 @@
=== /globals.ts ===
namespace globals {
>globals : typeof globals
export type Foo = {};
>Foo : Foo
export const Bar = {};
>Bar : {}
>{} : {}
}
import Foo = globals.toString.Blah;
>Foo : any
>globals : typeof globals
>toString : any
>Blah : any
=== /index.ts ===
const Foo = {};
>Foo : {}
>{} : {}

View file

@ -0,0 +1,9 @@
// @Filename: /globals.ts
namespace globals {
export type Foo = {};
export const Bar = {};
}
import Foo = globals.toString.Blah;
// @Filename: /index.ts
const Foo = {};