Skip to content

Commit cedcba9

Browse files
authored
Reset partial memberlist on defered circularity to calculate the correct members (#20179)
* Reset partial memberlist on defered circularity to calculate the correct members * Remove return type
1 parent 7ad0d7b commit cedcba9

File tree

6 files changed

+183
-8
lines changed

6 files changed

+183
-8
lines changed

src/compiler/checker.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5123,11 +5123,11 @@ namespace ts {
51235123
return type.resolvedBaseTypes;
51245124
}
51255125

5126-
function resolveBaseTypesOfClass(type: InterfaceType): void {
5127-
type.resolvedBaseTypes = emptyArray;
5126+
function resolveBaseTypesOfClass(type: InterfaceType) {
5127+
type.resolvedBaseTypes = resolvingEmptyArray;
51285128
const baseConstructorType = getApparentType(getBaseConstructorTypeOfClass(type));
51295129
if (!(baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.Any))) {
5130-
return;
5130+
return type.resolvedBaseTypes = emptyArray;
51315131
}
51325132
const baseTypeNode = getBaseTypeNodeOfClass(type);
51335133
const typeArgs = typeArgumentsFromTypeReferenceNode(baseTypeNode);
@@ -5150,24 +5150,31 @@ namespace ts {
51505150
const constructors = getInstantiatedConstructorsForTypeArguments(baseConstructorType, baseTypeNode.typeArguments, baseTypeNode);
51515151
if (!constructors.length) {
51525152
error(baseTypeNode.expression, Diagnostics.No_base_constructor_has_the_specified_number_of_type_arguments);
5153-
return;
5153+
return type.resolvedBaseTypes = emptyArray;
51545154
}
51555155
baseType = getReturnTypeOfSignature(constructors[0]);
51565156
}
51575157

51585158
if (baseType === unknownType) {
5159-
return;
5159+
return type.resolvedBaseTypes = emptyArray;
51605160
}
51615161
if (!isValidBaseType(baseType)) {
51625162
error(baseTypeNode.expression, Diagnostics.Base_constructor_return_type_0_is_not_a_class_or_interface_type, typeToString(baseType));
5163-
return;
5163+
return type.resolvedBaseTypes = emptyArray;
51645164
}
51655165
if (type === baseType || hasBaseType(baseType, type)) {
51665166
error(type.symbol.valueDeclaration, Diagnostics.Type_0_recursively_references_itself_as_a_base_type,
51675167
typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrayAsGenericType));
5168-
return;
5168+
return type.resolvedBaseTypes = emptyArray;
5169+
}
5170+
if (type.resolvedBaseTypes === resolvingEmptyArray) {
5171+
// Circular reference, likely through instantiation of default parameters
5172+
// (otherwise there'd be an error from hasBaseType) - this is fine, but `.members` should be reset
5173+
// as `getIndexedAccessType` via `instantiateType` via `getTypeFromClassOrInterfaceReference` forces a
5174+
// partial instantiation of the members without the base types fully resolved
5175+
(type as Type as ResolvedType).members = undefined;
51695176
}
5170-
type.resolvedBaseTypes = [baseType];
5177+
return type.resolvedBaseTypes = [baseType];
51715178
}
51725179

51735180
function areAllOuterTypeParametersApplied(type: Type): boolean {

src/compiler/utilities.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/* @internal */
44
namespace ts {
55
export const emptyArray: never[] = [] as never[];
6+
export const resolvingEmptyArray: never[] = [] as never[];
67
export const emptyMap: ReadonlyMap<never> = createMap<never>();
78

89
export const externalHelpersModuleNameText = "tslib";
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//// [circularConstraintYieldsAppropriateError.ts]
2+
// https://github.com/Microsoft/TypeScript/issues/16861
3+
class BaseType<T> {
4+
bar: T
5+
}
6+
7+
class NextType<C extends { someProp: any }, T = C['someProp']> extends BaseType<T> {
8+
baz: string;
9+
}
10+
11+
class Foo extends NextType<Foo> {
12+
someProp: {
13+
test: true
14+
}
15+
}
16+
17+
const foo = new Foo();
18+
foo.bar.test
19+
20+
//// [circularConstraintYieldsAppropriateError.js]
21+
var __extends = (this && this.__extends) || (function () {
22+
var extendStatics = Object.setPrototypeOf ||
23+
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
24+
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
25+
return function (d, b) {
26+
extendStatics(d, b);
27+
function __() { this.constructor = d; }
28+
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
29+
};
30+
})();
31+
// https://github.com/Microsoft/TypeScript/issues/16861
32+
var BaseType = /** @class */ (function () {
33+
function BaseType() {
34+
}
35+
return BaseType;
36+
}());
37+
var NextType = /** @class */ (function (_super) {
38+
__extends(NextType, _super);
39+
function NextType() {
40+
return _super !== null && _super.apply(this, arguments) || this;
41+
}
42+
return NextType;
43+
}(BaseType));
44+
var Foo = /** @class */ (function (_super) {
45+
__extends(Foo, _super);
46+
function Foo() {
47+
return _super !== null && _super.apply(this, arguments) || this;
48+
}
49+
return Foo;
50+
}(NextType));
51+
var foo = new Foo();
52+
foo.bar.test;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
=== tests/cases/compiler/circularConstraintYieldsAppropriateError.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/16861
3+
class BaseType<T> {
4+
>BaseType : Symbol(BaseType, Decl(circularConstraintYieldsAppropriateError.ts, 0, 0))
5+
>T : Symbol(T, Decl(circularConstraintYieldsAppropriateError.ts, 1, 15))
6+
7+
bar: T
8+
>bar : Symbol(BaseType.bar, Decl(circularConstraintYieldsAppropriateError.ts, 1, 19))
9+
>T : Symbol(T, Decl(circularConstraintYieldsAppropriateError.ts, 1, 15))
10+
}
11+
12+
class NextType<C extends { someProp: any }, T = C['someProp']> extends BaseType<T> {
13+
>NextType : Symbol(NextType, Decl(circularConstraintYieldsAppropriateError.ts, 3, 1))
14+
>C : Symbol(C, Decl(circularConstraintYieldsAppropriateError.ts, 5, 15))
15+
>someProp : Symbol(someProp, Decl(circularConstraintYieldsAppropriateError.ts, 5, 26))
16+
>T : Symbol(T, Decl(circularConstraintYieldsAppropriateError.ts, 5, 43))
17+
>C : Symbol(C, Decl(circularConstraintYieldsAppropriateError.ts, 5, 15))
18+
>BaseType : Symbol(BaseType, Decl(circularConstraintYieldsAppropriateError.ts, 0, 0))
19+
>T : Symbol(T, Decl(circularConstraintYieldsAppropriateError.ts, 5, 43))
20+
21+
baz: string;
22+
>baz : Symbol(NextType.baz, Decl(circularConstraintYieldsAppropriateError.ts, 5, 84))
23+
}
24+
25+
class Foo extends NextType<Foo> {
26+
>Foo : Symbol(Foo, Decl(circularConstraintYieldsAppropriateError.ts, 7, 1))
27+
>NextType : Symbol(NextType, Decl(circularConstraintYieldsAppropriateError.ts, 3, 1))
28+
>Foo : Symbol(Foo, Decl(circularConstraintYieldsAppropriateError.ts, 7, 1))
29+
30+
someProp: {
31+
>someProp : Symbol(Foo.someProp, Decl(circularConstraintYieldsAppropriateError.ts, 9, 33))
32+
33+
test: true
34+
>test : Symbol(test, Decl(circularConstraintYieldsAppropriateError.ts, 10, 15))
35+
}
36+
}
37+
38+
const foo = new Foo();
39+
>foo : Symbol(foo, Decl(circularConstraintYieldsAppropriateError.ts, 15, 5))
40+
>Foo : Symbol(Foo, Decl(circularConstraintYieldsAppropriateError.ts, 7, 1))
41+
42+
foo.bar.test
43+
>foo.bar.test : Symbol(test, Decl(circularConstraintYieldsAppropriateError.ts, 10, 15))
44+
>foo.bar : Symbol(BaseType.bar, Decl(circularConstraintYieldsAppropriateError.ts, 1, 19))
45+
>foo : Symbol(foo, Decl(circularConstraintYieldsAppropriateError.ts, 15, 5))
46+
>bar : Symbol(BaseType.bar, Decl(circularConstraintYieldsAppropriateError.ts, 1, 19))
47+
>test : Symbol(test, Decl(circularConstraintYieldsAppropriateError.ts, 10, 15))
48+
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
=== tests/cases/compiler/circularConstraintYieldsAppropriateError.ts ===
2+
// https://github.com/Microsoft/TypeScript/issues/16861
3+
class BaseType<T> {
4+
>BaseType : BaseType<T>
5+
>T : T
6+
7+
bar: T
8+
>bar : T
9+
>T : T
10+
}
11+
12+
class NextType<C extends { someProp: any }, T = C['someProp']> extends BaseType<T> {
13+
>NextType : NextType<C, T>
14+
>C : C
15+
>someProp : any
16+
>T : T
17+
>C : C
18+
>BaseType : BaseType<T>
19+
>T : T
20+
21+
baz: string;
22+
>baz : string
23+
}
24+
25+
class Foo extends NextType<Foo> {
26+
>Foo : Foo
27+
>NextType : NextType<Foo, { test: true; }>
28+
>Foo : Foo
29+
30+
someProp: {
31+
>someProp : { test: true; }
32+
33+
test: true
34+
>test : true
35+
>true : true
36+
}
37+
}
38+
39+
const foo = new Foo();
40+
>foo : Foo
41+
>new Foo() : Foo
42+
>Foo : typeof Foo
43+
44+
foo.bar.test
45+
>foo.bar.test : true
46+
>foo.bar : { test: true; }
47+
>foo : Foo
48+
>bar : { test: true; }
49+
>test : true
50+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// https://github.com/Microsoft/TypeScript/issues/16861
2+
class BaseType<T> {
3+
bar: T
4+
}
5+
6+
class NextType<C extends { someProp: any }, T = C['someProp']> extends BaseType<T> {
7+
baz: string;
8+
}
9+
10+
class Foo extends NextType<Foo> {
11+
someProp: {
12+
test: true
13+
}
14+
}
15+
16+
const foo = new Foo();
17+
foo.bar.test

0 commit comments

Comments
 (0)