Skip to content

Commit eee1602

Browse files
committed
Merge pull request #861 from Microsoft/unionTypesLS
Lanugage Service support for union types
2 parents c9a42c1 + 04e5309 commit eee1602

12 files changed

+395
-105
lines changed

src/compiler/checker.ts

+27-4
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ module ts {
8888
symbolToString: symbolToString,
8989
symbolToDisplayParts: symbolToDisplayParts,
9090
getAugmentedPropertiesOfApparentType: getAugmentedPropertiesOfApparentType,
91-
getRootSymbol: getRootSymbol,
91+
getRootSymbols: getRootSymbols,
9292
getContextualType: getContextualType,
9393
getFullyQualifiedName: getFullyQualifiedName,
9494
getResolvedSignature: getResolvedSignature,
@@ -2144,6 +2144,14 @@ module ts {
21442144
}
21452145
var symbol = <TransientSymbol>createSymbol(SymbolFlags.UnionProperty | SymbolFlags.Transient, prop.name);
21462146
symbol.unionType = type;
2147+
2148+
symbol.declarations = [];
2149+
for (var i = 0; i < types.length; i++) {
2150+
var s = getPropertyOfType(types[i], prop.name);
2151+
if (s.declarations)
2152+
symbol.declarations.push.apply(symbol.declarations, s.declarations);
2153+
}
2154+
21472155
members[prop.name] = symbol;
21482156
});
21492157
var callSignatures = getUnionSignatures(types, SignatureKind.Call);
@@ -3635,7 +3643,8 @@ module ts {
36353643
}
36363644

36373645
function getBestCommonType(types: Type[], contextualType: Type): Type {
3638-
return contextualType && isSupertypeOfEach(contextualType, types) ? contextualType : getUnionType(types); }
3646+
return contextualType && isSupertypeOfEach(contextualType, types) ? contextualType : getUnionType(types);
3647+
}
36393648

36403649
function isTypeOfObjectLiteral(type: Type): boolean {
36413650
return (type.flags & TypeFlags.Anonymous) && type.symbol && (type.symbol.flags & SymbolFlags.ObjectLiteral) ? true : false;
@@ -7928,8 +7937,22 @@ module ts {
79287937
}
79297938
}
79307939

7931-
function getRootSymbol(symbol: Symbol) {
7932-
return ((symbol.flags & SymbolFlags.Transient) && getSymbolLinks(symbol).target) || symbol;
7940+
function getRootSymbols(symbol: Symbol): Symbol[] {
7941+
if (symbol.flags & SymbolFlags.UnionProperty) {
7942+
var symbols: Symbol[] = [];
7943+
var name = symbol.name;
7944+
forEach(getSymbolLinks(symbol).unionType.types, t => {
7945+
symbols.push(getPropertyOfType(getApparentType(t), name));
7946+
});
7947+
return symbols;
7948+
}
7949+
else if (symbol.flags & SymbolFlags.Transient) {
7950+
var target = getSymbolLinks(symbol).target;
7951+
if (target) {
7952+
return [target];
7953+
}
7954+
}
7955+
return [symbol];
79337956
}
79347957

79357958
// Emitter support

src/compiler/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -653,7 +653,7 @@ module ts {
653653
symbolToDisplayParts(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): SymbolDisplayPart[];
654654
getFullyQualifiedName(symbol: Symbol): string;
655655
getAugmentedPropertiesOfApparentType(type: Type): Symbol[];
656-
getRootSymbol(symbol: Symbol): Symbol;
656+
getRootSymbols(symbol: Symbol): Symbol[];
657657
getContextualType(node: Node): Type;
658658
getResolvedSignature(node: CallExpression, candidatesOutArray?: Signature[]): Signature;
659659

src/services/services.ts

+128-91
Large diffs are not rendered by default.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
///<reference path="fourslash.ts" />
2+
3+
////interface One {
4+
//// commonProperty: number;
5+
//// commonFunction(): number;
6+
////}
7+
////
8+
////interface Two {
9+
//// commonProperty: string
10+
//// commonFunction(): number;
11+
////}
12+
////
13+
////var x : One | Two;
14+
////
15+
////x./**/
16+
17+
goTo.marker();
18+
verify.memberListContains("commonProperty", "string | number", undefined, undefined, "property");
19+
verify.memberListContains("commonFunction", "() => number", undefined, undefined, "method");
20+
verify.memberListCount(2);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
///<reference path="fourslash.ts" />
2+
3+
////interface One {
4+
//// commonProperty: number;
5+
//// commonFunction(): number;
6+
////}
7+
////
8+
////interface Two {
9+
//// commonProperty: string
10+
//// commonFunction(): number;
11+
////}
12+
////
13+
////var x : One | Two;
14+
////
15+
////x.commonProperty./**/
16+
17+
goTo.marker();
18+
verify.memberListContains("toString", "() => string", undefined, undefined, "method");
19+
verify.memberListCount(1);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
////interface One {
4+
//// /*propertyDefinition1*/commonProperty: number;
5+
//// commonFunction(): number;
6+
////}
7+
////
8+
////interface Two {
9+
//// /*propertyDefinition2*/commonProperty: string
10+
//// commonFunction(): number;
11+
////}
12+
////
13+
////var x : One | Two;
14+
////
15+
////x./*propertyReference*/commonProperty;
16+
////x./*3*/commonFunction;
17+
18+
goTo.marker("propertyReference");
19+
goTo.definition(0);
20+
verify.caretAtMarker("propertyDefinition1");
21+
22+
goTo.marker("propertyReference");
23+
goTo.definition(1);
24+
verify.caretAtMarker("propertyDefinition2");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/// <reference path='fourslash.ts' />
2+
////interface HasAOrB {
3+
//// /*propertyDefinition1*/a: string;
4+
//// b: string;
5+
////}
6+
////
7+
////interface One {
8+
//// common: { /*propertyDefinition2*/a : number; };
9+
////}
10+
////
11+
////interface Two {
12+
//// common: HasAOrB;
13+
////}
14+
////
15+
////var x : One | Two;
16+
////
17+
////x.common./*propertyReference*/a;
18+
19+
goTo.marker("propertyReference");
20+
goTo.definition(0);
21+
verify.caretAtMarker("propertyDefinition1");
22+
23+
goTo.marker("propertyReference");
24+
goTo.definition(1);
25+
verify.caretAtMarker("propertyDefinition2");
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/// <reference path="fourslash.ts"/>
2+
3+
////interface One {
4+
//// commonProperty: number;
5+
//// commonFunction(): number;
6+
////}
7+
////
8+
////interface Two {
9+
//// commonProperty: string
10+
//// commonFunction(): number;
11+
////}
12+
////
13+
////var /*1*/x : One | Two;
14+
////
15+
////x./*2*/commonProperty;
16+
////x./*3*/commonFunction;
17+
18+
19+
goTo.marker("1");
20+
verify.quickInfoIs("One | Two", "", "x", "var");
21+
22+
23+
goTo.marker("2");
24+
verify.quickInfoIs("string | number", "", "commonProperty", "property");
25+
26+
goTo.marker("3");
27+
verify.quickInfoIs("() => number", "", "commonFunction", "method");

tests/cases/fourslash/referencesForContextuallyTypedObjectLiteralProperties.ts

+9-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
/// <reference path='fourslash.ts'/>
2-
1+
/// <reference path='fourslash.ts'/>
2+
33
////interface IFoo { /*1*/xy: number; }
44
////
55
////// Assignment
@@ -23,10 +23,10 @@
2323
////var w: IFoo = { /*4*/xy: undefined };
2424
////
2525
////// Untped -- should not be included
26-
////var u = { xy: 0 };
27-
28-
29-
test.markers().forEach((m) => {
30-
goTo.position(m.position, m.fileName);
31-
verify.referencesCountIs(9);
32-
});
26+
////var u = { xy: 0 };
27+
28+
29+
test.markers().forEach((m) => {
30+
goTo.position(m.position, m.fileName);
31+
verify.referencesCountIs(9);
32+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
////interface A {
4+
//// a: number;
5+
//// common: string;
6+
////}
7+
////
8+
////interface B {
9+
//// b: number;
10+
//// common: number;
11+
////}
12+
////
13+
////// Assignment
14+
////var v1: A | B = { a: 0, /*1*/common: "" };
15+
////var v2: A | B = { b: 0, /*2*/common: 3 };
16+
////
17+
////// Function call
18+
////function consumer(f: A | B) { }
19+
////consumer({ a: 0, b: 0, /*3*/common: 1 });
20+
////
21+
////// Type cast
22+
////var c = <A | B> { /*4*/common: 0, b: 0 };
23+
////
24+
////// Array literal
25+
////var ar: Array<A|B> = [{ a: 0, /*5*/common: "" }, { b: 0, /*6*/common: 0 }];
26+
////
27+
////// Nested object literal
28+
////var ob: { aorb: A|B } = { aorb: { b: 0, /*7*/common: 0 } };
29+
////
30+
////// Widened type
31+
////var w: A|B = { a:0, /*8*/common: undefined };
32+
////
33+
////// Untped -- should not be included
34+
////var u1 = { a: 0, b: 0, common: "" };
35+
////var u2 = { b: 0, common: 0 };
36+
37+
test.markers().forEach((m) => {
38+
goTo.position(m.position, m.fileName);
39+
verify.referencesCountIs(10); // 8 contextually typed common, and 2 in definition (A.common, B.common)
40+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
////interface A {
4+
//// a: number;
5+
//// common: string;
6+
////}
7+
////
8+
////interface B {
9+
//// /*1*/b: number;
10+
//// common: number;
11+
////}
12+
////
13+
////// Assignment
14+
////var v1: A | B = { a: 0, common: "" };
15+
////var v2: A | B = { /*2*/b: 0, common: 3 };
16+
////
17+
////// Function call
18+
////function consumer(f: A | B) { }
19+
////consumer({ a: 0, /*3*/b: 0, common: 1 });
20+
////
21+
////// Type cast
22+
////var c = <A | B> { common: 0, /*4*/b: 0 };
23+
////
24+
////// Array literal
25+
////var ar: Array<A|B> = [{ a: 0, common: "" }, { /*5*/b: 0, common: 0 }];
26+
////
27+
////// Nested object literal
28+
////var ob: { aorb: A|B } = { aorb: { /*6*/b: 0, common: 0 } };
29+
////
30+
////// Widened type
31+
////var w: A|B = { /*7*/b:undefined, common: undefined };
32+
////
33+
////// Untped -- should not be included
34+
////var u1 = { a: 0, b: 0, common: "" };
35+
////var u2 = { b: 0, common: 0 };
36+
37+
test.markers().forEach((m) => {
38+
goTo.position(m.position, m.fileName);
39+
verify.referencesCountIs(7);
40+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/// <reference path='fourslash.ts'/>
2+
3+
////interface One {
4+
//// common: { /*1*/a: number; };
5+
////}
6+
////
7+
////interface Base {
8+
//// /*2*/a: string;
9+
//// b: string;
10+
////}
11+
////
12+
////interface HasAOrB extends Base {
13+
//// /*3*/a: string;
14+
//// b: string;
15+
////}
16+
////
17+
////interface Two {
18+
//// common: HasAOrB;
19+
////}
20+
////
21+
////var x : One | Two;
22+
////
23+
////x.common./*4*/a;
24+
25+
goTo.marker("1");
26+
verify.referencesCountIs(2); // One.common.a, x.common.a
27+
28+
goTo.marker("2");
29+
verify.referencesCountIs(3); // Base.a, HasAOrB.a, x.common.a
30+
31+
goTo.marker("3");
32+
verify.referencesCountIs(3); // Base.a, HasAOrB.a, x.common.a
33+
34+
goTo.marker("4");
35+
verify.referencesCountIs(4); // One.common.a, Base.a, HasAOrB.a, x.common.a

0 commit comments

Comments
 (0)