Exclude typeof this from check in isConstantReference (#52680)

This commit is contained in:
Anders Hejlsberg 2023-02-09 07:06:09 -08:00 committed by GitHub
parent 1c822c42a4
commit 57ebd99ff2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 204 additions and 4 deletions

View File

@ -26091,10 +26091,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
function isConstantReference(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.Identifier: {
const symbol = getResolvedSymbol(node as Identifier);
return isConstVariable(symbol) || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol);
}
case SyntaxKind.Identifier:
if (!isThisInTypeQuery(node)) {
const symbol = getResolvedSymbol(node as Identifier);
return isConstVariable(symbol) || isParameterOrCatchClauseVariable(symbol) && !isSymbolAssigned(symbol);
}
break;
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
// The resolvedSymbol property is initialized by checkPropertyAccess or checkElementAccess before we get here.

View File

@ -0,0 +1,77 @@
=== tests/cases/compiler/thisInTypeQuery.ts ===
// Repros from #52672
function assert(condition: unknown): asserts condition {
>assert : Symbol(assert, Decl(thisInTypeQuery.ts, 0, 0))
>condition : Symbol(condition, Decl(thisInTypeQuery.ts, 2, 16))
>condition : Symbol(condition, Decl(thisInTypeQuery.ts, 2, 16))
if (!condition) {
>condition : Symbol(condition, Decl(thisInTypeQuery.ts, 2, 16))
throw new Error();
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
}
}
class MyClass {
>MyClass : Symbol(MyClass, Decl(thisInTypeQuery.ts, 6, 1))
private map = {
>map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
my_key: 'example_value'
>my_key : Symbol(my_key, Decl(thisInTypeQuery.ts, 9, 19))
};
runTypeFails() {
>runTypeFails : Symbol(MyClass.runTypeFails, Decl(thisInTypeQuery.ts, 11, 6))
const params = null as any as { a: { key: string } } | null;
>params : Symbol(params, Decl(thisInTypeQuery.ts, 14, 13))
>a : Symbol(a, Decl(thisInTypeQuery.ts, 14, 39))
>key : Symbol(key, Decl(thisInTypeQuery.ts, 14, 44))
assert(params);
>assert : Symbol(assert, Decl(thisInTypeQuery.ts, 0, 0))
>params : Symbol(params, Decl(thisInTypeQuery.ts, 14, 13))
type Key = keyof typeof this.map;
>Key : Symbol(Key, Decl(thisInTypeQuery.ts, 15, 23))
>this.map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
>this : Symbol(MyClass, Decl(thisInTypeQuery.ts, 6, 1))
>map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
this.map[params.a.key as Key];
>this.map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
>this : Symbol(MyClass, Decl(thisInTypeQuery.ts, 6, 1))
>map : Symbol(MyClass.map, Decl(thisInTypeQuery.ts, 8, 15))
>params.a.key : Symbol(key, Decl(thisInTypeQuery.ts, 14, 44))
>params.a : Symbol(a, Decl(thisInTypeQuery.ts, 14, 39))
>params : Symbol(params, Decl(thisInTypeQuery.ts, 14, 13))
>a : Symbol(a, Decl(thisInTypeQuery.ts, 14, 39))
>key : Symbol(key, Decl(thisInTypeQuery.ts, 14, 44))
>Key : Symbol(Key, Decl(thisInTypeQuery.ts, 15, 23))
}
}
class C {
>C : Symbol(C, Decl(thisInTypeQuery.ts, 19, 1))
foo() {
>foo : Symbol(C.foo, Decl(thisInTypeQuery.ts, 21, 9))
const x = !!true;
>x : Symbol(x, Decl(thisInTypeQuery.ts, 23, 9))
if (x) {
>x : Symbol(x, Decl(thisInTypeQuery.ts, 23, 9))
type T0 = typeof this;
>T0 : Symbol(T0, Decl(thisInTypeQuery.ts, 24, 12))
>this : Symbol(C, Decl(thisInTypeQuery.ts, 19, 1))
}
}
}

View File

@ -0,0 +1,89 @@
=== tests/cases/compiler/thisInTypeQuery.ts ===
// Repros from #52672
function assert(condition: unknown): asserts condition {
>assert : (condition: unknown) => asserts condition
>condition : unknown
if (!condition) {
>!condition : boolean
>condition : unknown
throw new Error();
>new Error() : Error
>Error : ErrorConstructor
}
}
class MyClass {
>MyClass : MyClass
private map = {
>map : { my_key: string; }
>{ my_key: 'example_value' } : { my_key: string; }
my_key: 'example_value'
>my_key : string
>'example_value' : "example_value"
};
runTypeFails() {
>runTypeFails : () => void
const params = null as any as { a: { key: string } } | null;
>params : { a: { key: string;}; } | null
>null as any as { a: { key: string } } | null : { a: { key: string;}; } | null
>null as any : any
>null : null
>a : { key: string; }
>key : string
>null : null
assert(params);
>assert(params) : void
>assert : (condition: unknown) => asserts condition
>params : { a: { key: string; }; } | null
type Key = keyof typeof this.map;
>Key : "my_key"
>this.map : { my_key: string; }
>this : this
>map : { my_key: string; }
this.map[params.a.key as Key];
>this.map[params.a.key as Key] : string
>this.map : { my_key: string; }
>this : this
>map : { my_key: string; }
>params.a.key as Key : "my_key"
>params.a.key : string
>params.a : { key: string; }
>params : { a: { key: string; }; }
>a : { key: string; }
>key : string
}
}
class C {
>C : C
foo() {
>foo : () => void
const x = !!true;
>x : true
>!!true : true
>!true : false
>true : true
if (x) {
>x : true
type T0 = typeof this;
>T0 : this
>this : this
}
}
}

View File

@ -0,0 +1,32 @@
// @strict: true
// @noEmit: true
// Repros from #52672
function assert(condition: unknown): asserts condition {
if (!condition) {
throw new Error();
}
}
class MyClass {
private map = {
my_key: 'example_value'
};
runTypeFails() {
const params = null as any as { a: { key: string } } | null;
assert(params);
type Key = keyof typeof this.map;
this.map[params.a.key as Key];
}
}
class C {
foo() {
const x = !!true;
if (x) {
type T0 = typeof this;
}
}
}