Skip to content

Commit 2d472a4

Browse files
committed
Swap from instantiable type to structure type, fix inference
1 parent ddf4c06 commit 2d472a4

17 files changed

+112
-72
lines changed

src/compiler/checker.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7776,10 +7776,18 @@ namespace ts {
77767776
else if (type.flags & TypeFlags.Intersection) {
77777777
resolveIntersectionTypeMembers(<IntersectionType>type);
77787778
}
7779+
else if (type.flags & TypeFlags.StructuralTag) {
7780+
resolveStructuralTagTypeMembers(<StructuralTagType>type);
7781+
}
77797782
}
77807783
return <ResolvedType>type;
77817784
}
77827785

7786+
function resolveStructuralTagTypeMembers(type: StructuralTagType) {
7787+
// Explicitly do nothing - structured tags, despite "containing structure" (in their argument), do not have any visible structure.
7788+
setStructuredTypeMembers(type, emptySymbols, emptyArray, emptyArray, /*stringIndexInfo*/ undefined, /*numberIndexInfo*/ undefined);
7789+
}
7790+
77837791
/** Return properties of an object type or an empty array for other types */
77847792
function getPropertiesOfObjectType(type: Type): Symbol[] {
77857793
if (type.flags & TypeFlags.Object) {
@@ -11435,7 +11443,7 @@ namespace ts {
1143511443

1143611444
function instantiateSymbol(symbol: Symbol, mapper: TypeMapper): Symbol {
1143711445
const links = getSymbolLinks(symbol);
11438-
if (links.type && !maybeTypeOfKind(links.type, TypeFlags.Object | TypeFlags.Instantiable)) {
11446+
if (links.type && !maybeTypeOfKind(links.type, TypeFlags.Object | TypeFlags.Instantiable | TypeFlags.StructuralTag)) {
1143911447
// If the type of the symbol is already resolved, and if that type could not possibly
1144011448
// be affected by instantiation, simply return the symbol itself.
1144111449
return symbol;
@@ -15477,6 +15485,7 @@ namespace ts {
1547715485
function couldContainTypeVariables(type: Type): boolean {
1547815486
const objectFlags = getObjectFlags(type);
1547915487
return !!(type.flags & TypeFlags.Instantiable ||
15488+
type.flags & TypeFlags.StructuralTag && couldContainTypeVariables((type as StructuralTagType).type) ||
1548015489
objectFlags & ObjectFlags.Reference && forEach((<TypeReference>type).typeArguments, couldContainTypeVariables) ||
1548115490
objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral) && type.symbol.declarations ||
1548215491
objectFlags & ObjectFlags.Mapped ||
@@ -15812,6 +15821,12 @@ namespace ts {
1581215821
else if (target.flags & TypeFlags.UnionOrIntersection) {
1581315822
inferToMultipleTypes(source, (<UnionOrIntersectionType>target).types, target.flags);
1581415823
}
15824+
else if (target.flags & TypeFlags.StructuralTag && source.flags & TypeFlags.Intersection) {
15825+
const tagsOnly = getIntersectionType(filter((source as IntersectionType).types, t => !!(t.flags & TypeFlags.StructuralTag)));
15826+
if (tagsOnly !== source) {
15827+
inferFromTypes(tagsOnly, target);
15828+
}
15829+
}
1581515830
else if (source.flags & TypeFlags.Union) {
1581615831
// Source is a union or intersection type, infer from each constituent type
1581715832
const sourceTypes = (<UnionOrIntersectionType>source).types;
@@ -19329,7 +19344,7 @@ namespace ts {
1932919344
// are classified as instantiable (i.e. it doesn't instantiate object types), and (b) it performs
1933019345
// no reductions on instantiated union types.
1933119346
function instantiateInstantiableTypes(type: Type, mapper: TypeMapper): Type {
19332-
if (type.flags & TypeFlags.Instantiable) {
19347+
if (type.flags & (TypeFlags.Instantiable | TypeFlags.StructuralTag)) {
1933319348
return instantiateType(type, mapper);
1933419349
}
1933519350
if (type.flags & TypeFlags.Union) {
@@ -20017,7 +20032,7 @@ namespace ts {
2001720032
return isValidSpreadType(constraint);
2001820033
}
2001920034
}
20020-
return !!(type.flags & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.InstantiableNonPrimitive) ||
20035+
return !!(type.flags & (TypeFlags.Any | TypeFlags.NonPrimitive | TypeFlags.Object | TypeFlags.StructuralTag | TypeFlags.InstantiableNonPrimitive) ||
2002120036
getFalsyFlags(type) & TypeFlags.DefinitelyFalsy && isValidSpreadType(removeDefinitelyFalsyTypes(type)) ||
2002220037
type.flags & TypeFlags.UnionOrIntersection && every((<UnionOrIntersectionType>type).types, isValidSpreadType));
2002320038
}

src/compiler/types.ts

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4014,9 +4014,9 @@ namespace ts {
40144014
/* @internal */
40154015
DisjointDomains = NonPrimitive | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbolLike | VoidLike | Null,
40164016
UnionOrIntersection = Union | Intersection,
4017-
StructuredType = Object | Union | Intersection,
4017+
StructuredType = Object | Union | Intersection | StructuralTag,
40184018
TypeVariable = TypeParameter | IndexedAccess,
4019-
InstantiableNonPrimitive = TypeVariable | Conditional | Substitution | StructuralTag,
4019+
InstantiableNonPrimitive = TypeVariable | Conditional | Substitution,
40204020
InstantiablePrimitive = Index,
40214021
Instantiable = InstantiableNonPrimitive | InstantiablePrimitive,
40224022
StructuredOrInstantiable = StructuredType | Instantiable,
@@ -4268,7 +4268,7 @@ namespace ts {
42684268
resolvedApparentType: Type;
42694269
}
42704270

4271-
export type StructuredType = ObjectType | UnionType | IntersectionType;
4271+
export type StructuredType = ObjectType | UnionType | IntersectionType | StructuralTagType;
42724272

42734273
/* @internal */
42744274
// An instantiated anonymous type has a target and a mapper
@@ -4435,8 +4435,14 @@ namespace ts {
44354435
}
44364436

44374437
// Structual tag type, or a `tag T` (TypeFlags.StructuralTag)
4438-
export interface StructuralTagType extends InstantiableType {
4438+
export interface StructuralTagType extends Type {
44394439
type: Type;
4440+
/* @internal */ members?: SymbolTable; // Always emptySymbols
4441+
/* @internal */ properties?: Symbol[]; // Always emptyArray
4442+
/* @internal */ callSignatures?: ReadonlyArray<Signature>; // Always emptyArray
4443+
/* @internal */ constructSignatures?: ReadonlyArray<Signature>; // Always emptyArray
4444+
/* @internal */ stringIndexInfo?: undefined;
4445+
/* @internal */ numberIndexInfo?: undefined;
44404446
}
44414447

44424448
/* @internal */

tests/baselines/reference/api/tsserverlibrary.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,11 +2266,11 @@ declare namespace ts {
22662266
ESSymbolLike = 12288,
22672267
VoidLike = 49152,
22682268
UnionOrIntersection = 3145728,
2269-
StructuredType = 3670016,
2269+
StructuredType = 137887744,
22702270
TypeVariable = 8650752,
2271-
InstantiableNonPrimitive = 193200128,
2271+
InstantiableNonPrimitive = 58982400,
22722272
InstantiablePrimitive = 4194304,
2273-
Instantiable = 197394432,
2273+
Instantiable = 63176704,
22742274
StructuredOrInstantiable = 201064448,
22752275
Narrowable = 268188671,
22762276
NotUnionOrUnit = 67637251,
@@ -2373,7 +2373,7 @@ declare namespace ts {
23732373
}
23742374
export interface IntersectionType extends UnionOrIntersectionType {
23752375
}
2376-
export type StructuredType = ObjectType | UnionType | IntersectionType;
2376+
export type StructuredType = ObjectType | UnionType | IntersectionType | StructuralTagType;
23772377
export interface EvolvingArrayType extends ObjectType {
23782378
elementType: Type;
23792379
finalArrayType?: Type;
@@ -2417,7 +2417,7 @@ declare namespace ts {
24172417
typeVariable: TypeVariable;
24182418
substitute: Type;
24192419
}
2420-
export interface StructuralTagType extends InstantiableType {
2420+
export interface StructuralTagType extends Type {
24212421
type: Type;
24222422
}
24232423
export enum SignatureKind {

tests/baselines/reference/api/typescript.d.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,11 +2266,11 @@ declare namespace ts {
22662266
ESSymbolLike = 12288,
22672267
VoidLike = 49152,
22682268
UnionOrIntersection = 3145728,
2269-
StructuredType = 3670016,
2269+
StructuredType = 137887744,
22702270
TypeVariable = 8650752,
2271-
InstantiableNonPrimitive = 193200128,
2271+
InstantiableNonPrimitive = 58982400,
22722272
InstantiablePrimitive = 4194304,
2273-
Instantiable = 197394432,
2273+
Instantiable = 63176704,
22742274
StructuredOrInstantiable = 201064448,
22752275
Narrowable = 268188671,
22762276
NotUnionOrUnit = 67637251,
@@ -2373,7 +2373,7 @@ declare namespace ts {
23732373
}
23742374
export interface IntersectionType extends UnionOrIntersectionType {
23752375
}
2376-
export type StructuredType = ObjectType | UnionType | IntersectionType;
2376+
export type StructuredType = ObjectType | UnionType | IntersectionType | StructuralTagType;
23772377
export interface EvolvingArrayType extends ObjectType {
23782378
elementType: Type;
23792379
finalArrayType?: Type;
@@ -2417,7 +2417,7 @@ declare namespace ts {
24172417
typeVariable: TypeVariable;
24182418
substitute: Type;
24192419
}
2420-
export interface StructuralTagType extends InstantiableType {
2420+
export interface StructuralTagType extends Type {
24212421
type: Type;
24222422
}
24232423
export enum SignatureKind {

tests/baselines/reference/structuralTagTypesControlFlow.errors.txt

Lines changed: 8 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,13 @@ tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(37
88
Type '{ x: number; }' is not assignable to type 'BrandB'.
99
tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(38,27): error TS2345: Argument of type '{ x: number; }' is not assignable to parameter of type 'tag ({ BrandA: void; } & { BrandB: void; })'.
1010
tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(64,29): error TS2345: Argument of type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to parameter of type 'AbsolutePath'.
11-
Type '"/a/b/c"' is not assignable to type 'AbsolutePath'.
12-
Type '"/a/b/c"' is not assignable to type 'tag { AbsolutePath: void; }'.
13-
Type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to type 'tag { AbsolutePath: void; }'.
14-
Type '"/a/b/c"' is not assignable to type 'tag { AbsolutePath: void; }'.
11+
Type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to type 'tag { AbsolutePath: void; }'.
1512
tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(66,39): error TS2345: Argument of type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to parameter of type 'NormalizedAbsolutePath'.
16-
Type '"/a/b/c"' is not assignable to type 'NormalizedAbsolutePath'.
17-
Type '"/a/b/c"' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
18-
Type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
19-
Type '"/a/b/c"' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
13+
Type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
2014
tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(71,31): error TS2345: Argument of type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to parameter of type 'NormalizedPath'.
21-
Type '"/a/b/c"' is not assignable to type 'NormalizedPath'.
22-
Type '"/a/b/c"' is not assignable to type 'tag { NormalizedPath: void; }'.
23-
Type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to type 'tag { NormalizedPath: void; }'.
24-
Type '"/a/b/c"' is not assignable to type 'tag { NormalizedPath: void; }'.
15+
Type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to type 'tag { NormalizedPath: void; }'.
2516
tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(74,39): error TS2345: Argument of type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to parameter of type 'NormalizedAbsolutePath'.
26-
Type '"/a/b/c"' is not assignable to type 'NormalizedAbsolutePath'.
27-
Type '"/a/b/c"' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
28-
Type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
29-
Type '"/a/b/c"' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
17+
Type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
3018
tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(77,31): error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'NormalizedPath'.
3119
Type '"/a/b/c"' is not assignable to type 'tag { NormalizedPath: void; }'.
3220
tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(78,29): error TS2345: Argument of type '"/a/b/c"' is not assignable to parameter of type 'AbsolutePath'.
@@ -120,38 +108,26 @@ tests/cases/conformance/types/structuralTags/structuralTagTypesControlFlow.ts(80
120108
consumeAbsolutePath(p); // err
121109
~
122110
!!! error TS2345: Argument of type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to parameter of type 'AbsolutePath'.
123-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'AbsolutePath'.
124-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'tag { AbsolutePath: void; }'.
125-
!!! error TS2345: Type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to type 'tag { AbsolutePath: void; }'.
126-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'tag { AbsolutePath: void; }'.
111+
!!! error TS2345: Type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to type 'tag { AbsolutePath: void; }'.
127112
consumeNormalizedOrAbsolutePath(p);
128113
consumeNormalizedAbsolutePath(p); // err
129114
~
130115
!!! error TS2345: Argument of type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to parameter of type 'NormalizedAbsolutePath'.
131-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'NormalizedAbsolutePath'.
132-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
133-
!!! error TS2345: Type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
134-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
116+
!!! error TS2345: Type '"/a/b/c" & tag { NormalizedPath: void; }' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
135117
}
136118
}
137119
else {
138120
if (isAbsolutePath(p)) {
139121
consumeNormalizedPath(p); // err
140122
~
141123
!!! error TS2345: Argument of type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to parameter of type 'NormalizedPath'.
142-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'NormalizedPath'.
143-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'tag { NormalizedPath: void; }'.
144-
!!! error TS2345: Type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to type 'tag { NormalizedPath: void; }'.
145-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'tag { NormalizedPath: void; }'.
124+
!!! error TS2345: Type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to type 'tag { NormalizedPath: void; }'.
146125
consumeAbsolutePath(p);
147126
consumeNormalizedOrAbsolutePath(p);
148127
consumeNormalizedAbsolutePath(p); // err
149128
~
150129
!!! error TS2345: Argument of type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to parameter of type 'NormalizedAbsolutePath'.
151-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'NormalizedAbsolutePath'.
152-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
153-
!!! error TS2345: Type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
154-
!!! error TS2345: Type '"/a/b/c"' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
130+
!!! error TS2345: Type '"/a/b/c" & tag { AbsolutePath: void; }' is not assignable to type 'tag ({ NormalizedPath: void; } & { AbsolutePath: void; })'.
155131
}
156132
else {
157133
consumeNormalizedPath(p); // err

tests/baselines/reference/structuralTagTypesErr1.errors.txt

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,7 @@
11
tests/cases/conformance/types/structuralTags/structuralTagTypesErr1.ts(18,1): error TS2322: Type 'number & tag { y: any; }' is not assignable to type 'number & tag { x: any; }'.
2-
Type 'number' is not assignable to type 'number & tag { x: any; }'.
3-
Type 'number' is not assignable to type 'tag { x: any; }'.
4-
Type 'number & tag { y: any; }' is not assignable to type 'tag { x: any; }'.
5-
Type 'number' is not assignable to type 'tag { x: any; }'.
2+
Type 'number & tag { y: any; }' is not assignable to type 'tag { x: any; }'.
63
tests/cases/conformance/types/structuralTags/structuralTagTypesErr1.ts(19,1): error TS2322: Type 'number & tag { x: any; }' is not assignable to type 'number & tag { y: any; }'.
7-
Type 'number' is not assignable to type 'number & tag { y: any; }'.
8-
Type 'number' is not assignable to type 'tag { y: any; }'.
9-
Type 'number & tag { x: any; }' is not assignable to type 'tag { y: any; }'.
10-
Type 'number' is not assignable to type 'tag { y: any; }'.
4+
Type 'number & tag { x: any; }' is not assignable to type 'tag { y: any; }'.
115
tests/cases/conformance/types/structuralTags/structuralTagTypesErr1.ts(21,1): error TS2322: Type 'number' is not assignable to type 'number & tag { x: any; }'.
126
Type 'number' is not assignable to type 'tag { x: any; }'.
137
tests/cases/conformance/types/structuralTags/structuralTagTypesErr1.ts(22,1): error TS2322: Type 'number' is not assignable to type 'number & tag { y: any; }'.
@@ -39,17 +33,11 @@ tests/cases/conformance/types/structuralTags/structuralTagTypesErr1.ts(25,1): er
3933
a.x = a.y; // err
4034
~~~
4135
!!! error TS2322: Type 'number & tag { y: any; }' is not assignable to type 'number & tag { x: any; }'.
42-
!!! error TS2322: Type 'number' is not assignable to type 'number & tag { x: any; }'.
43-
!!! error TS2322: Type 'number' is not assignable to type 'tag { x: any; }'.
44-
!!! error TS2322: Type 'number & tag { y: any; }' is not assignable to type 'tag { x: any; }'.
45-
!!! error TS2322: Type 'number' is not assignable to type 'tag { x: any; }'.
36+
!!! error TS2322: Type 'number & tag { y: any; }' is not assignable to type 'tag { x: any; }'.
4637
a.y = a.x; // err
4738
~~~
4839
!!! error TS2322: Type 'number & tag { x: any; }' is not assignable to type 'number & tag { y: any; }'.
49-
!!! error TS2322: Type 'number' is not assignable to type 'number & tag { y: any; }'.
50-
!!! error TS2322: Type 'number' is not assignable to type 'tag { y: any; }'.
51-
!!! error TS2322: Type 'number & tag { x: any; }' is not assignable to type 'tag { y: any; }'.
52-
!!! error TS2322: Type 'number' is not assignable to type 'tag { y: any; }'.
40+
!!! error TS2322: Type 'number & tag { x: any; }' is not assignable to type 'tag { y: any; }'.
5341

5442
a.x = b.y; // err
5543
~~~
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
//// [structuraltagConditonalExtract.ts]
2+
type GetTag<T> = T extends tag infer U ? U : never
3+
type ThatTag = string & tag {x: number};
4+
5+
type WhichTag = GetTag<ThatTag>;
6+
7+
const obj: WhichTag = {x: 12}; // should be OK
8+
9+
//// [structuraltagConditonalExtract.js]
10+
var obj = { x: 12 }; // should be OK

0 commit comments

Comments
 (0)