Skip to content

Commit 4705d38

Browse files
authored
Store explicitly declared members ahead of inherited members (#1987)
1 parent 8ac3092 commit 4705d38

File tree

35 files changed

+584
-61
lines changed

35 files changed

+584
-61
lines changed

internal/checker/checker.go

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21351,20 +21351,44 @@ func (c *Checker) getDefaultOrUnknownFromTypeParameter(t *Type) *Type {
2135121351
return core.IfElse(result != nil, result, c.unknownType)
2135221352
}
2135321353

21354-
func (c *Checker) getNamedMembers(members ast.SymbolTable) []*ast.Symbol {
21354+
func (c *Checker) getNamedMembers(members ast.SymbolTable, container *ast.Symbol) []*ast.Symbol {
2135521355
if len(members) == 0 {
2135621356
return nil
2135721357
}
21358+
// For classes and interfaces, we store explicitly declared members ahead of inherited members. This ensures we process
21359+
// explicitly declared members first in type relations, which is beneficial because explicitly declared members are more
21360+
// likely to contain discriminating differences. See for example https://github.com/microsoft/typescript-go/issues/1968.
2135821361
result := make([]*ast.Symbol, 0, len(members))
21362+
var containedCount int
21363+
if container != nil && container.Flags&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) != 0 {
21364+
for id, symbol := range members {
21365+
if c.isNamedMember(symbol, id) && c.isDeclarationContainedBy(symbol, container) {
21366+
result = append(result, symbol)
21367+
}
21368+
}
21369+
containedCount = len(result)
21370+
}
2135921371
for id, symbol := range members {
21360-
if c.isNamedMember(symbol, id) {
21372+
if c.isNamedMember(symbol, id) && (container == nil || container.Flags&(ast.SymbolFlagsClass|ast.SymbolFlagsInterface) == 0 || !c.isDeclarationContainedBy(symbol, container)) {
2136121373
result = append(result, symbol)
2136221374
}
2136321375
}
21364-
c.sortSymbols(result)
21376+
c.sortSymbols(result[:containedCount])
21377+
c.sortSymbols(result[containedCount:])
2136521378
return result
2136621379
}
2136721380

21381+
func (c *Checker) isDeclarationContainedBy(symbol *ast.Symbol, container *ast.Symbol) bool {
21382+
if declaration := symbol.ValueDeclaration; declaration != nil {
21383+
for _, d := range container.Declarations {
21384+
if declaration.Loc.ContainedBy(d.Loc) {
21385+
return true
21386+
}
21387+
}
21388+
}
21389+
return false
21390+
}
21391+
2136821392
func (c *Checker) isNamedMember(symbol *ast.Symbol, id string) bool {
2136921393
return !isReservedMemberName(id) && c.symbolIsValue(symbol)
2137021394
}
@@ -24338,7 +24362,7 @@ func (c *Checker) setStructuredTypeMembers(t *Type, members ast.SymbolTable, cal
2433824362
t.objectFlags |= ObjectFlagsMembersResolved
2433924363
data := t.AsStructuredType()
2434024364
data.members = members
24341-
data.properties = c.getNamedMembers(members)
24365+
data.properties = c.getNamedMembers(members, t.symbol)
2434224366
if len(callSignatures) != 0 {
2434324367
if len(constructSignatures) != 0 {
2434424368
data.signatures = core.Concatenate(callSignatures, constructSignatures)

internal/checker/services.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ func (c *Checker) getAugmentedPropertiesOfType(t *Type) []*ast.Symbol {
271271
}
272272
}
273273
}
274-
return c.getNamedMembers(propsByName)
274+
return c.getNamedMembers(propsByName, nil)
275275
}
276276

277277
func (c *Checker) TryGetMemberInModuleExportsAndProperties(memberName string, moduleSymbol *ast.Symbol) *ast.Symbol {
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//// [tests/cases/compiler/explicitMembersBeforeInherited.ts] ////
2+
3+
=== explicitMembersBeforeInherited.ts ===
4+
// https://github.com/microsoft/typescript-go/issues/1968
5+
6+
type IndentationTree<L> = TopNode<L> | VirtualNode<L> | LineNode<L> | BlankNode<L>;
7+
>IndentationTree : Symbol(IndentationTree, Decl(explicitMembersBeforeInherited.ts, 0, 0))
8+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 2, 21))
9+
>TopNode : Symbol(TopNode, Decl(explicitMembersBeforeInherited.ts, 11, 1))
10+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 2, 21))
11+
>VirtualNode : Symbol(VirtualNode, Decl(explicitMembersBeforeInherited.ts, 7, 1))
12+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 2, 21))
13+
>LineNode : Symbol(LineNode, Decl(explicitMembersBeforeInherited.ts, 15, 1))
14+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 2, 21))
15+
>BlankNode : Symbol(BlankNode, Decl(explicitMembersBeforeInherited.ts, 19, 1))
16+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 2, 21))
17+
18+
type IndentationSubTree<L> = Exclude<IndentationTree<L>, TopNode<L>>;
19+
>IndentationSubTree : Symbol(IndentationSubTree, Decl(explicitMembersBeforeInherited.ts, 2, 83))
20+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 3, 24))
21+
>Exclude : Symbol(Exclude, Decl(lib.es5.d.ts, --, --))
22+
>IndentationTree : Symbol(IndentationTree, Decl(explicitMembersBeforeInherited.ts, 0, 0))
23+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 3, 24))
24+
>TopNode : Symbol(TopNode, Decl(explicitMembersBeforeInherited.ts, 11, 1))
25+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 3, 24))
26+
27+
interface NodeBase<L> {
28+
>NodeBase : Symbol(NodeBase, Decl(explicitMembersBeforeInherited.ts, 3, 69))
29+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 5, 19))
30+
31+
subs: IndentationSubTree<L>[];
32+
>subs : Symbol(NodeBase.subs, Decl(explicitMembersBeforeInherited.ts, 5, 23))
33+
>IndentationSubTree : Symbol(IndentationSubTree, Decl(explicitMembersBeforeInherited.ts, 2, 83))
34+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 5, 19))
35+
}
36+
37+
interface VirtualNode<L> extends NodeBase<L> {
38+
>VirtualNode : Symbol(VirtualNode, Decl(explicitMembersBeforeInherited.ts, 7, 1))
39+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 9, 22))
40+
>NodeBase : Symbol(NodeBase, Decl(explicitMembersBeforeInherited.ts, 3, 69))
41+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 9, 22))
42+
43+
type: 'virtual';
44+
>type : Symbol(VirtualNode.type, Decl(explicitMembersBeforeInherited.ts, 9, 46))
45+
}
46+
47+
interface TopNode<L> extends NodeBase<L> {
48+
>TopNode : Symbol(TopNode, Decl(explicitMembersBeforeInherited.ts, 11, 1))
49+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 13, 18))
50+
>NodeBase : Symbol(NodeBase, Decl(explicitMembersBeforeInherited.ts, 3, 69))
51+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 13, 18))
52+
53+
type: 'top';
54+
>type : Symbol(TopNode.type, Decl(explicitMembersBeforeInherited.ts, 13, 42))
55+
}
56+
57+
interface LineNode<L> extends NodeBase<L> {
58+
>LineNode : Symbol(LineNode, Decl(explicitMembersBeforeInherited.ts, 15, 1))
59+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 17, 19))
60+
>NodeBase : Symbol(NodeBase, Decl(explicitMembersBeforeInherited.ts, 3, 69))
61+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 17, 19))
62+
63+
type: 'line';
64+
>type : Symbol(LineNode.type, Decl(explicitMembersBeforeInherited.ts, 17, 43))
65+
}
66+
67+
interface BlankNode<L> extends NodeBase<L> {
68+
>BlankNode : Symbol(BlankNode, Decl(explicitMembersBeforeInherited.ts, 19, 1))
69+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 21, 20))
70+
>NodeBase : Symbol(NodeBase, Decl(explicitMembersBeforeInherited.ts, 3, 69))
71+
>L : Symbol(L, Decl(explicitMembersBeforeInherited.ts, 21, 20))
72+
73+
type: 'blank';
74+
>type : Symbol(BlankNode.type, Decl(explicitMembersBeforeInherited.ts, 21, 44))
75+
}
76+
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//// [tests/cases/compiler/explicitMembersBeforeInherited.ts] ////
2+
3+
=== explicitMembersBeforeInherited.ts ===
4+
// https://github.com/microsoft/typescript-go/issues/1968
5+
6+
type IndentationTree<L> = TopNode<L> | VirtualNode<L> | LineNode<L> | BlankNode<L>;
7+
>IndentationTree : IndentationTree<L>
8+
9+
type IndentationSubTree<L> = Exclude<IndentationTree<L>, TopNode<L>>;
10+
>IndentationSubTree : IndentationSubTree<L>
11+
12+
interface NodeBase<L> {
13+
subs: IndentationSubTree<L>[];
14+
>subs : IndentationSubTree<L>[]
15+
}
16+
17+
interface VirtualNode<L> extends NodeBase<L> {
18+
type: 'virtual';
19+
>type : "virtual"
20+
}
21+
22+
interface TopNode<L> extends NodeBase<L> {
23+
type: 'top';
24+
>type : "top"
25+
}
26+
27+
interface LineNode<L> extends NodeBase<L> {
28+
type: 'line';
29+
>type : "line"
30+
}
31+
32+
interface BlankNode<L> extends NodeBase<L> {
33+
type: 'blank';
34+
>type : "blank"
35+
}
36+

testdata/baselines/reference/submodule/compiler/arrayAssignmentTest1.errors.txt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
arrayAssignmentTest1.ts(46,5): error TS2741: Property 'IM1' is missing in type 'undefined[]' but required in type 'I1'.
22
arrayAssignmentTest1.ts(47,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C1': IM1, C1M1
3-
arrayAssignmentTest1.ts(48,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': IM1, C1M1, C2M1
3+
arrayAssignmentTest1.ts(48,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': C2M1, IM1, C1M1
44
arrayAssignmentTest1.ts(49,5): error TS2741: Property 'CM3M1' is missing in type 'undefined[]' but required in type 'C3'.
55
arrayAssignmentTest1.ts(60,1): error TS2322: Type 'C3[]' is not assignable to type 'I1[]'.
66
Property 'IM1' is missing in type 'C3' but required in type 'I1'.
@@ -11,9 +11,9 @@ arrayAssignmentTest1.ts(65,1): error TS2322: Type 'C3[]' is not assignable to ty
1111
arrayAssignmentTest1.ts(68,1): error TS2322: Type 'C1[]' is not assignable to type 'C2[]'.
1212
Property 'C2M1' is missing in type 'C1' but required in type 'C2'.
1313
arrayAssignmentTest1.ts(69,1): error TS2322: Type 'I1[]' is not assignable to type 'C2[]'.
14-
Type 'I1' is missing the following properties from type 'C2': C1M1, C2M1
14+
Type 'I1' is missing the following properties from type 'C2': C2M1, C1M1
1515
arrayAssignmentTest1.ts(70,1): error TS2322: Type 'C3[]' is not assignable to type 'C2[]'.
16-
Type 'C3' is missing the following properties from type 'C2': IM1, C1M1, C2M1
16+
Type 'C3' is missing the following properties from type 'C2': C2M1, IM1, C1M1
1717
arrayAssignmentTest1.ts(75,1): error TS2322: Type 'C2[]' is not assignable to type 'C3[]'.
1818
Property 'CM3M1' is missing in type 'C2' but required in type 'C3'.
1919
arrayAssignmentTest1.ts(76,1): error TS2322: Type 'C1[]' is not assignable to type 'C3[]'.
@@ -83,7 +83,7 @@ arrayAssignmentTest1.ts(85,1): error TS2740: Type 'I1' is missing the following
8383
!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C1': IM1, C1M1
8484
var c2_error: C2 = []; // should be an error - is
8585
~~~~~~~~
86-
!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': IM1, C1M1, C2M1
86+
!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': C2M1, IM1, C1M1
8787
var c3_error: C3 = []; // should be an error - is
8888
~~~~~~~~
8989
!!! error TS2741: Property 'CM3M1' is missing in type 'undefined[]' but required in type 'C3'.
@@ -125,11 +125,11 @@ arrayAssignmentTest1.ts(85,1): error TS2740: Type 'I1' is missing the following
125125
arr_c2 = arr_i1; // should be an error - subtype relationship - is
126126
~~~~~~
127127
!!! error TS2322: Type 'I1[]' is not assignable to type 'C2[]'.
128-
!!! error TS2322: Type 'I1' is missing the following properties from type 'C2': C1M1, C2M1
128+
!!! error TS2322: Type 'I1' is missing the following properties from type 'C2': C2M1, C1M1
129129
arr_c2 = arr_c3; // should be an error - is
130130
~~~~~~
131131
!!! error TS2322: Type 'C3[]' is not assignable to type 'C2[]'.
132-
!!! error TS2322: Type 'C3' is missing the following properties from type 'C2': IM1, C1M1, C2M1
132+
!!! error TS2322: Type 'C3' is missing the following properties from type 'C2': C2M1, IM1, C1M1
133133

134134
// "clean up bug" occurs at this point
135135
// if you move these three expressions to another file, they raise an error
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
--- old.arrayAssignmentTest1.errors.txt
2+
+++ new.arrayAssignmentTest1.errors.txt
3+
@@= skipped -0, +0 lines =@@
4+
arrayAssignmentTest1.ts(46,5): error TS2741: Property 'IM1' is missing in type 'undefined[]' but required in type 'I1'.
5+
arrayAssignmentTest1.ts(47,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C1': IM1, C1M1
6+
-arrayAssignmentTest1.ts(48,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': IM1, C1M1, C2M1
7+
+arrayAssignmentTest1.ts(48,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': C2M1, IM1, C1M1
8+
arrayAssignmentTest1.ts(49,5): error TS2741: Property 'CM3M1' is missing in type 'undefined[]' but required in type 'C3'.
9+
arrayAssignmentTest1.ts(60,1): error TS2322: Type 'C3[]' is not assignable to type 'I1[]'.
10+
Property 'IM1' is missing in type 'C3' but required in type 'I1'.
11+
@@= skipped -10, +10 lines =@@
12+
arrayAssignmentTest1.ts(68,1): error TS2322: Type 'C1[]' is not assignable to type 'C2[]'.
13+
Property 'C2M1' is missing in type 'C1' but required in type 'C2'.
14+
arrayAssignmentTest1.ts(69,1): error TS2322: Type 'I1[]' is not assignable to type 'C2[]'.
15+
- Type 'I1' is missing the following properties from type 'C2': C1M1, C2M1
16+
+ Type 'I1' is missing the following properties from type 'C2': C2M1, C1M1
17+
arrayAssignmentTest1.ts(70,1): error TS2322: Type 'C3[]' is not assignable to type 'C2[]'.
18+
- Type 'C3' is missing the following properties from type 'C2': IM1, C1M1, C2M1
19+
+ Type 'C3' is missing the following properties from type 'C2': C2M1, IM1, C1M1
20+
arrayAssignmentTest1.ts(75,1): error TS2322: Type 'C2[]' is not assignable to type 'C3[]'.
21+
Property 'CM3M1' is missing in type 'C2' but required in type 'C3'.
22+
arrayAssignmentTest1.ts(76,1): error TS2322: Type 'C1[]' is not assignable to type 'C3[]'.
23+
@@= skipped -72, +72 lines =@@
24+
!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C1': IM1, C1M1
25+
var c2_error: C2 = []; // should be an error - is
26+
~~~~~~~~
27+
-!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': IM1, C1M1, C2M1
28+
+!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': C2M1, IM1, C1M1
29+
var c3_error: C3 = []; // should be an error - is
30+
~~~~~~~~
31+
!!! error TS2741: Property 'CM3M1' is missing in type 'undefined[]' but required in type 'C3'.
32+
@@= skipped -42, +42 lines =@@
33+
arr_c2 = arr_i1; // should be an error - subtype relationship - is
34+
~~~~~~
35+
!!! error TS2322: Type 'I1[]' is not assignable to type 'C2[]'.
36+
-!!! error TS2322: Type 'I1' is missing the following properties from type 'C2': C1M1, C2M1
37+
+!!! error TS2322: Type 'I1' is missing the following properties from type 'C2': C2M1, C1M1
38+
arr_c2 = arr_c3; // should be an error - is
39+
~~~~~~
40+
!!! error TS2322: Type 'C3[]' is not assignable to type 'C2[]'.
41+
-!!! error TS2322: Type 'C3' is missing the following properties from type 'C2': IM1, C1M1, C2M1
42+
+!!! error TS2322: Type 'C3' is missing the following properties from type 'C2': C2M1, IM1, C1M1
43+
44+
// "clean up bug" occurs at this point
45+
// if you move these three expressions to another file, they raise an error

testdata/baselines/reference/submodule/compiler/chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.errors.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,64): error TS2741: Property 'z' is missing in type 'B' but required in type 'C'.
2-
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,81): error TS2739: Type 'A' is missing the following properties from type 'C': y, z
2+
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,81): error TS2739: Type 'A' is missing the following properties from type 'C': z, y
33

44

55
==== chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts (2 errors) ====
@@ -27,5 +27,5 @@ chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,81): error TS
2727
!!! related TS2728 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts:15:5: 'z' is declared here.
2828
!!! related TS6502 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts:3:27: The expected type comes from the return type of this signature.
2929
~~~~~
30-
!!! error TS2739: Type 'A' is missing the following properties from type 'C': y, z
30+
!!! error TS2739: Type 'A' is missing the following properties from type 'C': z, y
3131
!!! related TS6502 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts:3:27: The expected type comes from the return type of this signature.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--- old.chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.errors.txt
2+
+++ new.chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.errors.txt
3+
@@= skipped -0, +0 lines =@@
4+
chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,64): error TS2741: Property 'z' is missing in type 'B' but required in type 'C'.
5+
-chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,81): error TS2739: Type 'A' is missing the following properties from type 'C': y, z
6+
+chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts(19,81): error TS2739: Type 'A' is missing the following properties from type 'C': z, y
7+
8+
9+
==== chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts (2 errors) ====
10+
@@= skipped -26, +26 lines =@@
11+
!!! related TS2728 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts:15:5: 'z' is declared here.
12+
!!! related TS6502 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts:3:27: The expected type comes from the return type of this signature.
13+
~~~~~
14+
-!!! error TS2739: Type 'A' is missing the following properties from type 'C': y, z
15+
+!!! error TS2739: Type 'A' is missing the following properties from type 'C': z, y
16+
!!! related TS6502 chainedCallsWithTypeParameterConstrainedToOtherTypeParameter.ts:3:27: The expected type comes from the return type of this signature.

testdata/baselines/reference/submodule/compiler/emitClassExpressionInDeclarationFile.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -90,17 +90,17 @@ export declare class FooItem {
9090
export type Constructor<T> = new (...args: any[]) => T;
9191
export declare function WithTags<T extends Constructor<FooItem>>(Base: T): {
9292
new (...args: any[]): {
93+
tags(): void;
9394
foo(): void;
9495
name?: string;
95-
tags(): void;
9696
};
9797
getTags(): void;
9898
} & T;
9999
declare const Test_base: {
100100
new (...args: any[]): {
101+
tags(): void;
101102
foo(): void;
102103
name?: string;
103-
tags(): void;
104104
};
105105
getTags(): void;
106106
} & typeof FooItem;

testdata/baselines/reference/submodule/compiler/emitClassExpressionInDeclarationFile.js.diff

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,4 +25,24 @@
2525
+ tags(c: any): any;
2626
};
2727
};
28-
export declare class FooItem {
28+
export declare class FooItem {
29+
@@= skipped -10, +10 lines =@@
30+
export type Constructor<T> = new (...args: any[]) => T;
31+
export declare function WithTags<T extends Constructor<FooItem>>(Base: T): {
32+
new (...args: any[]): {
33+
+ tags(): void;
34+
foo(): void;
35+
name?: string;
36+
- tags(): void;
37+
};
38+
getTags(): void;
39+
} & T;
40+
declare const Test_base: {
41+
new (...args: any[]): {
42+
+ tags(): void;
43+
foo(): void;
44+
name?: string;
45+
- tags(): void;
46+
};
47+
getTags(): void;
48+
} & typeof FooItem;

0 commit comments

Comments
 (0)