Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 53 additions & 13 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5552,23 +5552,63 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
(name as string).charCodeAt(2) !== CharacterCodes.hash;
}

function getNamedMembers(members: SymbolTable): Symbol[] {
let result: Symbol[] | undefined;
function getNamedMembers(members: SymbolTable, container: Symbol | undefined): Symbol[] {
if (!TSGO_COMPAT) {
let result: Symbol[] | undefined;
members.forEach((symbol, id) => {
if (isNamedMember(symbol, id)) {
(result || (result = [])).push(symbol);
}
});
return result || emptyArray;
}

if (members.size === 0) {
return emptyArray;
}

// For classes and interfaces, we store explicitly declared members ahead of inherited members. This ensures we process
// explicitly declared members first in type relations, which is beneficial because explicitly declared members are more
// likely to contain discriminating differences. See for example https://github.com/microsoft/typescript-go/issues/1968.
let contained: Symbol[] | undefined;
if (container && container.flags & (SymbolFlags.Class | SymbolFlags.Interface)) {
members.forEach((symbol, id) => {
if (isNamedMember(symbol, id) && isDeclarationContainedBy(symbol, container)) {
contained = append(contained, symbol);
}
});
}

let nonContained: Symbol[] | undefined;
members.forEach((symbol, id) => {
if (isNamedMember(symbol, id)) {
(result || (result = [])).push(symbol);
if (isNamedMember(symbol, id) && (!container || !(container.flags & (SymbolFlags.Class | SymbolFlags.Interface)) || !isDeclarationContainedBy(symbol, container))) {
nonContained = append(nonContained, symbol);
}
});
sortSymbolsIfTSGoCompat(result);
return result || emptyArray;

contained?.sort(compareSymbols);
nonContained?.sort(compareSymbols);
return concatenate(contained, nonContained) || emptyArray;

function isDeclarationContainedBy(symbol: Symbol, container: Symbol): boolean {
const declaration = symbol.valueDeclaration;
if (declaration) {
return some(container.declarations, d => containedBy(declaration, d));
}
return false;

function containedBy(a: Node, b: Node): boolean {
return b.pos <= a.pos && b.end >= a.end;
}
}
}

function isNamedMember(member: Symbol, escapedName: __String) {
return !isReservedMemberName(escapedName) && symbolIsValue(member);
}

function getNamedOrIndexSignatureMembers(members: SymbolTable): Symbol[] {
const result = getNamedMembers(members);
function getNamedOrIndexSignatureMembers(members: SymbolTable, symbol: Symbol): Symbol[] {
const result = getNamedMembers(members, symbol);
const index = getIndexSymbolFromSymbolTable(members);
return index ? concatenate(result, [index]) : result;
}
Expand All @@ -5581,7 +5621,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
resolved.constructSignatures = constructSignatures;
resolved.indexInfos = indexInfos;
// This can loop back to getPropertyOfType() which would crash if `callSignatures` & `constructSignatures` are not initialized.
if (members !== emptySymbols) resolved.properties = getNamedMembers(members);
if (members !== emptySymbols) resolved.properties = getNamedMembers(members, type.symbol);
return resolved;
}

Expand Down Expand Up @@ -13689,7 +13729,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!(type as InterfaceTypeWithDeclaredMembers).declaredProperties) {
const symbol = type.symbol;
const members = getMembersOfSymbol(symbol);
(type as InterfaceTypeWithDeclaredMembers).declaredProperties = getNamedMembers(members);
(type as InterfaceTypeWithDeclaredMembers).declaredProperties = getNamedMembers(members, symbol);
// Start with signatures at empty array in case of recursive types
(type as InterfaceTypeWithDeclaredMembers).declaredCallSignatures = emptyArray;
(type as InterfaceTypeWithDeclaredMembers).declaredConstructSignatures = emptyArray;
Expand Down Expand Up @@ -14565,7 +14605,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
const classType = getDeclaredTypeOfClassOrInterface(symbol);
const baseConstructorType = getBaseConstructorTypeOfClass(classType);
if (baseConstructorType.flags & (TypeFlags.Object | TypeFlags.Intersection | TypeFlags.TypeVariable)) {
members = createSymbolTable(getNamedOrIndexSignatureMembers(members));
members = createSymbolTable(getNamedOrIndexSignatureMembers(members, symbol));
addInheritedMembers(members, getPropertiesOfType(baseConstructorType));
}
else if (baseConstructorType === anyType) {
Expand Down Expand Up @@ -15028,7 +15068,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
break;
}
}
type.resolvedProperties = getNamedMembers(members);
type.resolvedProperties = getNamedMembers(members, type.symbol);
}
return type.resolvedProperties;
}
Expand Down Expand Up @@ -50033,7 +50073,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
}
});
}
return getNamedMembers(propsByName);
return getNamedMembers(propsByName, /*container*/ undefined);
}

function typeHasCallOrConstructSignatures(type: Type): boolean {
Expand Down
12 changes: 6 additions & 6 deletions tests/baselines/reference/arrayAssignmentTest1.errors.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
arrayAssignmentTest1.ts(46,5): error TS2741: Property 'IM1' is missing in type 'undefined[]' but required in type 'I1'.
arrayAssignmentTest1.ts(47,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C1': IM1, C1M1
arrayAssignmentTest1.ts(48,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': IM1, C1M1, C2M1
arrayAssignmentTest1.ts(48,5): error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': C2M1, IM1, C1M1
arrayAssignmentTest1.ts(49,5): error TS2741: Property 'CM3M1' is missing in type 'undefined[]' but required in type 'C3'.
arrayAssignmentTest1.ts(60,1): error TS2322: Type 'C3[]' is not assignable to type 'I1[]'.
Property 'IM1' is missing in type 'C3' but required in type 'I1'.
Expand All @@ -11,9 +11,9 @@ arrayAssignmentTest1.ts(65,1): error TS2322: Type 'C3[]' is not assignable to ty
arrayAssignmentTest1.ts(68,1): error TS2322: Type 'C1[]' is not assignable to type 'C2[]'.
Property 'C2M1' is missing in type 'C1' but required in type 'C2'.
arrayAssignmentTest1.ts(69,1): error TS2322: Type 'I1[]' is not assignable to type 'C2[]'.
Type 'I1' is missing the following properties from type 'C2': C1M1, C2M1
Type 'I1' is missing the following properties from type 'C2': C2M1, C1M1
arrayAssignmentTest1.ts(70,1): error TS2322: Type 'C3[]' is not assignable to type 'C2[]'.
Type 'C3' is missing the following properties from type 'C2': IM1, C1M1, C2M1
Type 'C3' is missing the following properties from type 'C2': C2M1, IM1, C1M1
arrayAssignmentTest1.ts(75,1): error TS2322: Type 'C2[]' is not assignable to type 'C3[]'.
Property 'CM3M1' is missing in type 'C2' but required in type 'C3'.
arrayAssignmentTest1.ts(76,1): error TS2322: Type 'C1[]' is not assignable to type 'C3[]'.
Expand Down Expand Up @@ -83,7 +83,7 @@ arrayAssignmentTest1.ts(85,1): error TS2740: Type 'I1' is missing the following
!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C1': IM1, C1M1
var c2_error: C2 = []; // should be an error - is
~~~~~~~~
!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': IM1, C1M1, C2M1
!!! error TS2739: Type 'undefined[]' is missing the following properties from type 'C2': C2M1, IM1, C1M1
var c3_error: C3 = []; // should be an error - is
~~~~~~~~
!!! error TS2741: Property 'CM3M1' is missing in type 'undefined[]' but required in type 'C3'.
Expand Down Expand Up @@ -125,11 +125,11 @@ arrayAssignmentTest1.ts(85,1): error TS2740: Type 'I1' is missing the following
arr_c2 = arr_i1; // should be an error - subtype relationship - is
~~~~~~
!!! error TS2322: Type 'I1[]' is not assignable to type 'C2[]'.
!!! error TS2322: Type 'I1' is missing the following properties from type 'C2': C1M1, C2M1
!!! error TS2322: Type 'I1' is missing the following properties from type 'C2': C2M1, C1M1
arr_c2 = arr_c3; // should be an error - is
~~~~~~
!!! error TS2322: Type 'C3[]' is not assignable to type 'C2[]'.
!!! error TS2322: Type 'C3' is missing the following properties from type 'C2': IM1, C1M1, C2M1
!!! error TS2322: Type 'C3' is missing the following properties from type 'C2': C2M1, IM1, C1M1

// "clean up bug" occurs at this point
// if you move these three expressions to another file, they raise an error
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ assignmentCompatWithCallSignatures3.ts(80,1): error TS2322: Type '(x: Base[], y:
Types of parameters 'y' and 'y' are incompatible.
Type 'T' is not assignable to type 'Derived2[]'.
Type 'Base[]' is not assignable to type 'Derived2[]'.
Type 'Base' is missing the following properties from type 'Derived2': bar, baz
Type 'Base' is missing the following properties from type 'Derived2': baz, bar
assignmentCompatWithCallSignatures3.ts(83,1): error TS2322: Type '(x: Base[], y: Derived[]) => Derived[]' is not assignable to type '<T extends Array<Derived>>(x: Base[], y: T) => T'.
Type 'Derived[]' is not assignable to type 'T'.
'Derived[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Derived[]'.
Expand Down Expand Up @@ -208,7 +208,7 @@ assignmentCompatWithCallSignatures3.ts(86,1): error TS2322: Type '(x: { a: strin
!!! error TS2322: Types of parameters 'y' and 'y' are incompatible.
!!! error TS2322: Type 'T' is not assignable to type 'Derived2[]'.
!!! error TS2322: Type 'Base[]' is not assignable to type 'Derived2[]'.
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': bar, baz
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': baz, bar
var b13: <T extends Array<Derived>>(x: Array<Base>, y: T) => T;
a13 = b13; // ok
b13 = a13; // ok
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ assignmentCompatWithConstructSignatures3.ts(80,1): error TS2322: Type 'new (x: B
Types of parameters 'y' and 'y' are incompatible.
Type 'T' is not assignable to type 'Derived2[]'.
Type 'Base[]' is not assignable to type 'Derived2[]'.
Type 'Base' is missing the following properties from type 'Derived2': bar, baz
Type 'Base' is missing the following properties from type 'Derived2': baz, bar
assignmentCompatWithConstructSignatures3.ts(83,1): error TS2322: Type 'new (x: Base[], y: Derived[]) => Derived[]' is not assignable to type 'new <T extends Array<Derived>>(x: Base[], y: T) => T'.
Type 'Derived[]' is not assignable to type 'T'.
'Derived[]' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Derived[]'.
Expand Down Expand Up @@ -208,7 +208,7 @@ assignmentCompatWithConstructSignatures3.ts(86,1): error TS2322: Type 'new (x: {
!!! error TS2322: Types of parameters 'y' and 'y' are incompatible.
!!! error TS2322: Type 'T' is not assignable to type 'Derived2[]'.
!!! error TS2322: Type 'Base[]' is not assignable to type 'Derived2[]'.
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': bar, baz
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': baz, bar
var b13: new <T extends Array<Derived>>(x: Array<Base>, y: T) => T;
a13 = b13; // ok
b13 = a13; // ok
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ assignmentCompatWithNumericIndexer.ts(14,1): error TS2322: Type 'A' is not assig
Property 'bar' is missing in type 'Base' but required in type 'Derived'.
assignmentCompatWithNumericIndexer.ts(18,1): error TS2322: Type 'A' is not assignable to type '{ [x: number]: Derived2; }'.
'number' index signatures are incompatible.
Type 'Base' is missing the following properties from type 'Derived2': bar, baz
Type 'Base' is missing the following properties from type 'Derived2': baz, bar
assignmentCompatWithNumericIndexer.ts(32,9): error TS2322: Type '{ [x: number]: Derived; }' is not assignable to type 'A<T>'.
'number' index signatures are incompatible.
Type 'Derived' is not assignable to type 'T'.
Expand All @@ -19,7 +19,7 @@ assignmentCompatWithNumericIndexer.ts(36,9): error TS2322: Type '{ [x: number]:
assignmentCompatWithNumericIndexer.ts(37,9): error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived2; }'.
'number' index signatures are incompatible.
Type 'T' is not assignable to type 'Derived2'.
Type 'Base' is missing the following properties from type 'Derived2': bar, baz
Type 'Base' is missing the following properties from type 'Derived2': baz, bar


==== assignmentCompatWithNumericIndexer.ts (6 errors) ====
Expand Down Expand Up @@ -49,7 +49,7 @@ assignmentCompatWithNumericIndexer.ts(37,9): error TS2322: Type 'A<T>' is not as
~~
!!! error TS2322: Type 'A' is not assignable to type '{ [x: number]: Derived2; }'.
!!! error TS2322: 'number' index signatures are incompatible.
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': bar, baz
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': baz, bar

module Generics {
class A<T extends Base> {
Expand Down Expand Up @@ -89,7 +89,7 @@ assignmentCompatWithNumericIndexer.ts(37,9): error TS2322: Type 'A<T>' is not as
!!! error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived2; }'.
!!! error TS2322: 'number' index signatures are incompatible.
!!! error TS2322: Type 'T' is not assignable to type 'Derived2'.
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': bar, baz
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': baz, bar

var b3: { [x: number]: T; }
a = b3; // ok
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ assignmentCompatWithNumericIndexer2.ts(14,1): error TS2322: Type 'A' is not assi
Property 'bar' is missing in type 'Base' but required in type 'Derived'.
assignmentCompatWithNumericIndexer2.ts(18,1): error TS2322: Type 'A' is not assignable to type '{ [x: number]: Derived2; }'.
'number' index signatures are incompatible.
Type 'Base' is missing the following properties from type 'Derived2': bar, baz
Type 'Base' is missing the following properties from type 'Derived2': baz, bar
assignmentCompatWithNumericIndexer2.ts(32,9): error TS2322: Type '{ [x: number]: Derived; }' is not assignable to type 'A<T>'.
'number' index signatures are incompatible.
Type 'Derived' is not assignable to type 'T'.
Expand All @@ -19,7 +19,7 @@ assignmentCompatWithNumericIndexer2.ts(36,9): error TS2322: Type '{ [x: number]:
assignmentCompatWithNumericIndexer2.ts(37,9): error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived2; }'.
'number' index signatures are incompatible.
Type 'T' is not assignable to type 'Derived2'.
Type 'Base' is missing the following properties from type 'Derived2': bar, baz
Type 'Base' is missing the following properties from type 'Derived2': baz, bar


==== assignmentCompatWithNumericIndexer2.ts (6 errors) ====
Expand Down Expand Up @@ -49,7 +49,7 @@ assignmentCompatWithNumericIndexer2.ts(37,9): error TS2322: Type 'A<T>' is not a
~~
!!! error TS2322: Type 'A' is not assignable to type '{ [x: number]: Derived2; }'.
!!! error TS2322: 'number' index signatures are incompatible.
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': bar, baz
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': baz, bar

module Generics {
interface A<T extends Base> {
Expand Down Expand Up @@ -89,7 +89,7 @@ assignmentCompatWithNumericIndexer2.ts(37,9): error TS2322: Type 'A<T>' is not a
!!! error TS2322: Type 'A<T>' is not assignable to type '{ [x: number]: Derived2; }'.
!!! error TS2322: 'number' index signatures are incompatible.
!!! error TS2322: Type 'T' is not assignable to type 'Derived2'.
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': bar, baz
!!! error TS2322: Type 'Base' is missing the following properties from type 'Derived2': baz, bar

var b3: { [x: number]: T; }
a = b3; // ok
Expand Down
Loading