Skip to content

Commit b38d95f

Browse files
committed
Preserve aliases in tags better, add global Tag alias, distribute tags into unions
1 parent f37aeab commit b38d95f

22 files changed

+953
-103
lines changed

Diff for: src/compiler/checker.ts

+40-4
Original file line numberDiff line numberDiff line change
@@ -631,7 +631,7 @@ namespace ts {
631631
const literalTypes = createMap<LiteralType>();
632632
const indexedAccessTypes = createMap<IndexedAccessType>();
633633
const substitutionTypes = createMap<SubstitutionType>();
634-
const structuralTags = createMap<StructuralTagType>();
634+
const structuralTags = createMap<Type>();
635635
const evolvingArrayTypes: EvolvingArrayType[] = [];
636636
const undefinedProperties = createMap<Symbol>() as UnderscoreEscapedMap<Symbol>;
637637

@@ -3801,8 +3801,33 @@ namespace ts {
38013801
return typeToTypeNodeHelper((<SubstitutionType>type).typeVariable, context);
38023802
}
38033803
if (type.flags & TypeFlags.StructuralTag) {
3804+
const innerType = (type as StructuralTagType).type;
3805+
if (innerType.flags & TypeFlags.Intersection) {
3806+
// If some inner type of the intersection has an alias when hoisted out, (attempt to) hoist out all of the aliasable things
3807+
if (some((innerType as IntersectionType).types, t => !!getStructuralTagForType(t).aliasSymbol)) {
3808+
const aliasingTypes: Type[] = [];
3809+
const nonAliasingTypes: Type[] = [];
3810+
for (const t of (innerType as IntersectionType).types) {
3811+
const taggedVersion = getStructuralTagForType(t);
3812+
if (taggedVersion.aliasSymbol && (context.flags & NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope || isTypeSymbolAccessible(taggedVersion.aliasSymbol, context.enclosingDeclaration))) {
3813+
aliasingTypes.push(taggedVersion);
3814+
}
3815+
else {
3816+
nonAliasingTypes.push(t);
3817+
}
3818+
}
3819+
if (length(aliasingTypes)) {
3820+
if (length(nonAliasingTypes)) {
3821+
aliasingTypes.push(getStructuralTagForType(getIntersectionType(nonAliasingTypes)));
3822+
}
3823+
// Do note: this can make an intersection become nested within another intersection - this _is_ handled correctly
3824+
// during emit, so is fine (and honestly is more clear, since it groups all the tags together)
3825+
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, map(aliasingTypes, t => typeToTypeNodeHelper(t, context)));
3826+
}
3827+
}
3828+
}
38043829
context.approximateLength += 4;
3805-
return createTypeOperatorNode(SyntaxKind.TagKeyword, typeToTypeNodeHelper((type as StructuralTagType).type, context));
3830+
return createTypeOperatorNode(SyntaxKind.TagKeyword, typeToTypeNodeHelper(innerType, context));
38063831
}
38073832

38083833
return Debug.fail("Should be unreachable.");
@@ -9980,14 +10005,17 @@ namespace ts {
998010005
includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type), tagSet);
998110006
}
998210007
if (isTopLevel && tagSet.size) {
9983-
let tag: StructuralTagType;
10008+
let tag: Type;
998410009
if (tagSet.size === 1) {
998510010
tag = tagSet.values().next().value;
998610011
}
998710012
else {
998810013
const tagTypes: Type[] = [];
998910014
tagSet.forEach(t => tagTypes.push(t.type));
999010015
tag = getStructuralTagForType(getIntersectionType(tagTypes));
10016+
if (tag.flags & TypeFlags.Union) {
10017+
includes |= TypeFlags.Union;
10018+
}
999110019
}
999210020
typeSet.set(tag.id.toString(), tag);
999310021
}
@@ -10310,11 +10338,19 @@ namespace ts {
1031010338
return type;
1031110339
}
1031210340

10313-
function getStructuralTagForType(type: Type, aliasSymbol?: Symbol, aliasTypeArguments?: readonly Type[]) {
10341+
function getStructuralTagForType(type: Type, aliasSymbol?: Symbol | number, aliasTypeArguments?: readonly Type[]) {
10342+
if (typeof aliasSymbol === "number") {
10343+
aliasSymbol = undefined;
10344+
}
1031410345
const tid = "" + getTypeId(type);
1031510346
if (structuralTags.has(tid)) {
1031610347
return structuralTags.get(tid)!;
1031710348
}
10349+
if (type.flags & TypeFlags.Union) {
10350+
const union = getUnionType(map((type as UnionType).types, getStructuralTagForType), UnionReduction.Subtype, aliasSymbol, aliasTypeArguments);
10351+
structuralTags.set(tid, union);
10352+
return union;
10353+
}
1031810354
const tag = createType(TypeFlags.StructuralTag) as StructuralTagType;
1031910355
tag.type = type;
1032010356
tag.aliasSymbol = aliasSymbol;

Diff for: src/harness/fourslash.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4672,6 +4672,7 @@ namespace FourSlashInterface {
46724672
typeEntry("ReturnType"),
46734673
typeEntry("InstanceType"),
46744674
interfaceEntry("ThisType"),
4675+
typeEntry("Tag"),
46754676
varEntry("ArrayBuffer"),
46764677
interfaceEntry("ArrayBufferTypes"),
46774678
typeEntry("ArrayBufferLike"),

Diff for: src/lib/es5.d.ts

+7
Original file line numberDiff line numberDiff line change
@@ -1478,6 +1478,13 @@ type InstanceType<T extends new (...args: any) => any> = T extends new (...args:
14781478
*/
14791479
interface ThisType<T> { }
14801480

1481+
/**
1482+
* Constructs a structural tag over property name(s) `K`
1483+
*/
1484+
type Tag<K extends keyof any> = tag {
1485+
[_ in K]: void;
1486+
};
1487+
14811488
/**
14821489
* Represents a raw buffer of binary data, which is used to store data for the
14831490
* different typed arrays. ArrayBuffers cannot be read from or written to directly,

Diff for: tests/baselines/reference/numericLiteralTypes1.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,17 @@ function assertNever(x: never): never {
6666
throw new Error("Unexpected value");
6767
}
6868

69-
type Tag = 0 | 1 | 2;
69+
type NumericTag = 0 | 1 | 2;
7070

71-
function f10(x: Tag) {
71+
function f10(x: NumericTag) {
7272
switch (x) {
7373
case 0: return "a";
7474
case 1: return "b";
7575
case 2: return "c";
7676
}
7777
}
7878

79-
function f11(x: Tag) {
79+
function f11(x: NumericTag) {
8080
switch (x) {
8181
case 0: return "a";
8282
case 1: return "b";
@@ -85,7 +85,7 @@ function f11(x: Tag) {
8585
return assertNever(x);
8686
}
8787

88-
function f12(x: Tag) {
88+
function f12(x: NumericTag) {
8989
if (x) {
9090
x;
9191
}
@@ -94,7 +94,7 @@ function f12(x: Tag) {
9494
}
9595
}
9696

97-
function f13(x: Tag) {
97+
function f13(x: NumericTag) {
9898
if (x === 0 || x === 2) {
9999
x;
100100
}

Diff for: tests/baselines/reference/numericLiteralTypes1.symbols

+11-11
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,13 @@ function assertNever(x: never): never {
221221
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
222222
}
223223

224-
type Tag = 0 | 1 | 2;
225-
>Tag : Symbol(Tag, Decl(numericLiteralTypes1.ts, 65, 1))
224+
type NumericTag = 0 | 1 | 2;
225+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes1.ts, 65, 1))
226226

227-
function f10(x: Tag) {
228-
>f10 : Symbol(f10, Decl(numericLiteralTypes1.ts, 67, 21))
227+
function f10(x: NumericTag) {
228+
>f10 : Symbol(f10, Decl(numericLiteralTypes1.ts, 67, 28))
229229
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 69, 13))
230-
>Tag : Symbol(Tag, Decl(numericLiteralTypes1.ts, 65, 1))
230+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes1.ts, 65, 1))
231231

232232
switch (x) {
233233
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 69, 13))
@@ -238,10 +238,10 @@ function f10(x: Tag) {
238238
}
239239
}
240240

241-
function f11(x: Tag) {
241+
function f11(x: NumericTag) {
242242
>f11 : Symbol(f11, Decl(numericLiteralTypes1.ts, 75, 1))
243243
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 77, 13))
244-
>Tag : Symbol(Tag, Decl(numericLiteralTypes1.ts, 65, 1))
244+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes1.ts, 65, 1))
245245

246246
switch (x) {
247247
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 77, 13))
@@ -255,10 +255,10 @@ function f11(x: Tag) {
255255
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 77, 13))
256256
}
257257

258-
function f12(x: Tag) {
258+
function f12(x: NumericTag) {
259259
>f12 : Symbol(f12, Decl(numericLiteralTypes1.ts, 84, 1))
260260
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 86, 13))
261-
>Tag : Symbol(Tag, Decl(numericLiteralTypes1.ts, 65, 1))
261+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes1.ts, 65, 1))
262262

263263
if (x) {
264264
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 86, 13))
@@ -272,10 +272,10 @@ function f12(x: Tag) {
272272
}
273273
}
274274

275-
function f13(x: Tag) {
275+
function f13(x: NumericTag) {
276276
>f13 : Symbol(f13, Decl(numericLiteralTypes1.ts, 93, 1))
277277
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 95, 13))
278-
>Tag : Symbol(Tag, Decl(numericLiteralTypes1.ts, 65, 1))
278+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes1.ts, 65, 1))
279279

280280
if (x === 0 || x === 2) {
281281
>x : Symbol(x, Decl(numericLiteralTypes1.ts, 95, 13))

Diff for: tests/baselines/reference/numericLiteralTypes1.types

+6-6
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,10 @@ function assertNever(x: never): never {
259259
>"Unexpected value" : "Unexpected value"
260260
}
261261

262-
type Tag = 0 | 1 | 2;
263-
>Tag : 0 | 1 | 2
262+
type NumericTag = 0 | 1 | 2;
263+
>NumericTag : 0 | 1 | 2
264264

265-
function f10(x: Tag) {
265+
function f10(x: NumericTag) {
266266
>f10 : (x: 0 | 1 | 2) => "a" | "b" | "c"
267267
>x : 0 | 1 | 2
268268

@@ -283,7 +283,7 @@ function f10(x: Tag) {
283283
}
284284
}
285285

286-
function f11(x: Tag) {
286+
function f11(x: NumericTag) {
287287
>f11 : (x: 0 | 1 | 2) => "a" | "b" | "c"
288288
>x : 0 | 1 | 2
289289

@@ -308,7 +308,7 @@ function f11(x: Tag) {
308308
>x : never
309309
}
310310

311-
function f12(x: Tag) {
311+
function f12(x: NumericTag) {
312312
>f12 : (x: 0 | 1 | 2) => void
313313
>x : 0 | 1 | 2
314314

@@ -324,7 +324,7 @@ function f12(x: Tag) {
324324
}
325325
}
326326

327-
function f13(x: Tag) {
327+
function f13(x: NumericTag) {
328328
>f13 : (x: 0 | 1 | 2) => void
329329
>x : 0 | 1 | 2
330330

Diff for: tests/baselines/reference/numericLiteralTypes2.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,17 @@ function assertNever(x: never): never {
6666
throw new Error("Unexpected value");
6767
}
6868

69-
type Tag = 0 | 1 | 2;
69+
type NumericTag = 0 | 1 | 2;
7070

71-
function f10(x: Tag) {
71+
function f10(x: NumericTag) {
7272
switch (x) {
7373
case 0: return "a";
7474
case 1: return "b";
7575
case 2: return "c";
7676
}
7777
}
7878

79-
function f11(x: Tag) {
79+
function f11(x: NumericTag) {
8080
switch (x) {
8181
case 0: return "a";
8282
case 1: return "b";
@@ -85,7 +85,7 @@ function f11(x: Tag) {
8585
return assertNever(x);
8686
}
8787

88-
function f12(x: Tag) {
88+
function f12(x: NumericTag) {
8989
if (x) {
9090
x;
9191
}
@@ -94,7 +94,7 @@ function f12(x: Tag) {
9494
}
9595
}
9696

97-
function f13(x: Tag) {
97+
function f13(x: NumericTag) {
9898
if (x === 0 || x === 2) {
9999
x;
100100
}

Diff for: tests/baselines/reference/numericLiteralTypes2.symbols

+11-11
Original file line numberDiff line numberDiff line change
@@ -221,13 +221,13 @@ function assertNever(x: never): never {
221221
>Error : Symbol(Error, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --))
222222
}
223223

224-
type Tag = 0 | 1 | 2;
225-
>Tag : Symbol(Tag, Decl(numericLiteralTypes2.ts, 65, 1))
224+
type NumericTag = 0 | 1 | 2;
225+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes2.ts, 65, 1))
226226

227-
function f10(x: Tag) {
228-
>f10 : Symbol(f10, Decl(numericLiteralTypes2.ts, 67, 21))
227+
function f10(x: NumericTag) {
228+
>f10 : Symbol(f10, Decl(numericLiteralTypes2.ts, 67, 28))
229229
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 69, 13))
230-
>Tag : Symbol(Tag, Decl(numericLiteralTypes2.ts, 65, 1))
230+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes2.ts, 65, 1))
231231

232232
switch (x) {
233233
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 69, 13))
@@ -238,10 +238,10 @@ function f10(x: Tag) {
238238
}
239239
}
240240

241-
function f11(x: Tag) {
241+
function f11(x: NumericTag) {
242242
>f11 : Symbol(f11, Decl(numericLiteralTypes2.ts, 75, 1))
243243
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 77, 13))
244-
>Tag : Symbol(Tag, Decl(numericLiteralTypes2.ts, 65, 1))
244+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes2.ts, 65, 1))
245245

246246
switch (x) {
247247
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 77, 13))
@@ -255,10 +255,10 @@ function f11(x: Tag) {
255255
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 77, 13))
256256
}
257257

258-
function f12(x: Tag) {
258+
function f12(x: NumericTag) {
259259
>f12 : Symbol(f12, Decl(numericLiteralTypes2.ts, 84, 1))
260260
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 86, 13))
261-
>Tag : Symbol(Tag, Decl(numericLiteralTypes2.ts, 65, 1))
261+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes2.ts, 65, 1))
262262

263263
if (x) {
264264
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 86, 13))
@@ -272,10 +272,10 @@ function f12(x: Tag) {
272272
}
273273
}
274274

275-
function f13(x: Tag) {
275+
function f13(x: NumericTag) {
276276
>f13 : Symbol(f13, Decl(numericLiteralTypes2.ts, 93, 1))
277277
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 95, 13))
278-
>Tag : Symbol(Tag, Decl(numericLiteralTypes2.ts, 65, 1))
278+
>NumericTag : Symbol(NumericTag, Decl(numericLiteralTypes2.ts, 65, 1))
279279

280280
if (x === 0 || x === 2) {
281281
>x : Symbol(x, Decl(numericLiteralTypes2.ts, 95, 13))

Diff for: tests/baselines/reference/numericLiteralTypes2.types

+6-6
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,10 @@ function assertNever(x: never): never {
259259
>"Unexpected value" : "Unexpected value"
260260
}
261261

262-
type Tag = 0 | 1 | 2;
263-
>Tag : 0 | 1 | 2
262+
type NumericTag = 0 | 1 | 2;
263+
>NumericTag : 0 | 1 | 2
264264

265-
function f10(x: Tag) {
265+
function f10(x: NumericTag) {
266266
>f10 : (x: 0 | 1 | 2) => "a" | "b" | "c"
267267
>x : 0 | 1 | 2
268268

@@ -283,7 +283,7 @@ function f10(x: Tag) {
283283
}
284284
}
285285

286-
function f11(x: Tag) {
286+
function f11(x: NumericTag) {
287287
>f11 : (x: 0 | 1 | 2) => "a" | "b" | "c"
288288
>x : 0 | 1 | 2
289289

@@ -308,7 +308,7 @@ function f11(x: Tag) {
308308
>x : never
309309
}
310310

311-
function f12(x: Tag) {
311+
function f12(x: NumericTag) {
312312
>f12 : (x: 0 | 1 | 2) => void
313313
>x : 0 | 1 | 2
314314

@@ -324,7 +324,7 @@ function f12(x: Tag) {
324324
}
325325
}
326326

327-
function f13(x: Tag) {
327+
function f13(x: NumericTag) {
328328
>f13 : (x: 0 | 1 | 2) => void
329329
>x : 0 | 1 | 2
330330

0 commit comments

Comments
 (0)