From a31a65f25aaf5182e9a0e5cd73bc594b1e8bf9ab Mon Sep 17 00:00:00 2001 From: Ivo Gabe de Wolff Date: Thu, 20 Aug 2015 08:23:55 +0200 Subject: [PATCH 1/2] Allow intersections in arithmetics and element access --- src/compiler/checker.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 23baadd076223..0899f3f4f0cc0 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9645,13 +9645,15 @@ namespace ts { return false; } - // Return true if type has the given flags, or is a union or intersection type composed of types that all have those flags. + // Return true if type has the given flags, + // is a union type composed of types that all have those flags, + // or an intersection type that contains (at least) one type that has those flags. function allConstituentTypesHaveKind(type: Type, kind: TypeFlags): boolean { if (type.flags & kind) { return true; } - if (type.flags & TypeFlags.UnionOrIntersection) { - let types = (type).types; + if (type.flags & TypeFlags.Union) { + let types = (type).types; for (let current of types) { if (!(current.flags & kind)) { return false; @@ -9659,6 +9661,14 @@ namespace ts { } return true; } + if (type.flags & TypeFlags.Intersection) { + let types = (type).types; + for (let current of types) { + if (current.flags & kind) { + return true; + } + } + } return false; } From 34da8c2730decc47b0f1620110781e474fa7f9a5 Mon Sep 17 00:00:00 2001 From: Ivo Gabe de Wolff Date: Thu, 20 Aug 2015 08:24:11 +0200 Subject: [PATCH 2/2] Add tests --- .../reference/intersectionArithmetic.js | 33 +++++++++ .../reference/intersectionArithmetic.symbols | 54 ++++++++++++++ .../reference/intersectionArithmetic.types | 72 +++++++++++++++++++ .../reference/intersectionElementAccess.js | 23 ++++++ .../intersectionElementAccess.symbols | 40 +++++++++++ .../reference/intersectionElementAccess.types | 43 +++++++++++ .../intersection/intersectionArithmetic.ts | 16 +++++ .../intersection/intersectionElementAccess.ts | 12 ++++ 8 files changed, 293 insertions(+) create mode 100644 tests/baselines/reference/intersectionArithmetic.js create mode 100644 tests/baselines/reference/intersectionArithmetic.symbols create mode 100644 tests/baselines/reference/intersectionArithmetic.types create mode 100644 tests/baselines/reference/intersectionElementAccess.js create mode 100644 tests/baselines/reference/intersectionElementAccess.symbols create mode 100644 tests/baselines/reference/intersectionElementAccess.types create mode 100644 tests/cases/conformance/types/intersection/intersectionArithmetic.ts create mode 100644 tests/cases/conformance/types/intersection/intersectionElementAccess.ts diff --git a/tests/baselines/reference/intersectionArithmetic.js b/tests/baselines/reference/intersectionArithmetic.js new file mode 100644 index 0000000000000..38cc70f3a7b1f --- /dev/null +++ b/tests/baselines/reference/intersectionArithmetic.js @@ -0,0 +1,33 @@ +//// [intersectionArithmetic.ts] +let numberObject: number & { foo: any }; +let stringObject: string & { foo: any }; +let numberString: number & string; + +let a = numberObject + 1; +let b = stringObject + 1; +let c = numberObject + ''; +let d = stringObject + ''; +let e = numberObject + stringObject; + +let f = numberString + 1; +let g = numberString + ''; +let h = numberString + numberString; + +let i = numberObject * 2; +let j = numberString * 2; + + +//// [intersectionArithmetic.js] +var numberObject; +var stringObject; +var numberString; +var a = numberObject + 1; +var b = stringObject + 1; +var c = numberObject + ''; +var d = stringObject + ''; +var e = numberObject + stringObject; +var f = numberString + 1; +var g = numberString + ''; +var h = numberString + numberString; +var i = numberObject * 2; +var j = numberString * 2; diff --git a/tests/baselines/reference/intersectionArithmetic.symbols b/tests/baselines/reference/intersectionArithmetic.symbols new file mode 100644 index 0000000000000..27e83dd1bfda5 --- /dev/null +++ b/tests/baselines/reference/intersectionArithmetic.symbols @@ -0,0 +1,54 @@ +=== tests/cases/conformance/types/intersection/intersectionArithmetic.ts === +let numberObject: number & { foo: any }; +>numberObject : Symbol(numberObject, Decl(intersectionArithmetic.ts, 0, 3)) +>foo : Symbol(foo, Decl(intersectionArithmetic.ts, 0, 28)) + +let stringObject: string & { foo: any }; +>stringObject : Symbol(stringObject, Decl(intersectionArithmetic.ts, 1, 3)) +>foo : Symbol(foo, Decl(intersectionArithmetic.ts, 1, 28)) + +let numberString: number & string; +>numberString : Symbol(numberString, Decl(intersectionArithmetic.ts, 2, 3)) + +let a = numberObject + 1; +>a : Symbol(a, Decl(intersectionArithmetic.ts, 4, 3)) +>numberObject : Symbol(numberObject, Decl(intersectionArithmetic.ts, 0, 3)) + +let b = stringObject + 1; +>b : Symbol(b, Decl(intersectionArithmetic.ts, 5, 3)) +>stringObject : Symbol(stringObject, Decl(intersectionArithmetic.ts, 1, 3)) + +let c = numberObject + ''; +>c : Symbol(c, Decl(intersectionArithmetic.ts, 6, 3)) +>numberObject : Symbol(numberObject, Decl(intersectionArithmetic.ts, 0, 3)) + +let d = stringObject + ''; +>d : Symbol(d, Decl(intersectionArithmetic.ts, 7, 3)) +>stringObject : Symbol(stringObject, Decl(intersectionArithmetic.ts, 1, 3)) + +let e = numberObject + stringObject; +>e : Symbol(e, Decl(intersectionArithmetic.ts, 8, 3)) +>numberObject : Symbol(numberObject, Decl(intersectionArithmetic.ts, 0, 3)) +>stringObject : Symbol(stringObject, Decl(intersectionArithmetic.ts, 1, 3)) + +let f = numberString + 1; +>f : Symbol(f, Decl(intersectionArithmetic.ts, 10, 3)) +>numberString : Symbol(numberString, Decl(intersectionArithmetic.ts, 2, 3)) + +let g = numberString + ''; +>g : Symbol(g, Decl(intersectionArithmetic.ts, 11, 3)) +>numberString : Symbol(numberString, Decl(intersectionArithmetic.ts, 2, 3)) + +let h = numberString + numberString; +>h : Symbol(h, Decl(intersectionArithmetic.ts, 12, 3)) +>numberString : Symbol(numberString, Decl(intersectionArithmetic.ts, 2, 3)) +>numberString : Symbol(numberString, Decl(intersectionArithmetic.ts, 2, 3)) + +let i = numberObject * 2; +>i : Symbol(i, Decl(intersectionArithmetic.ts, 14, 3)) +>numberObject : Symbol(numberObject, Decl(intersectionArithmetic.ts, 0, 3)) + +let j = numberString * 2; +>j : Symbol(j, Decl(intersectionArithmetic.ts, 15, 3)) +>numberString : Symbol(numberString, Decl(intersectionArithmetic.ts, 2, 3)) + diff --git a/tests/baselines/reference/intersectionArithmetic.types b/tests/baselines/reference/intersectionArithmetic.types new file mode 100644 index 0000000000000..23ec29dad0710 --- /dev/null +++ b/tests/baselines/reference/intersectionArithmetic.types @@ -0,0 +1,72 @@ +=== tests/cases/conformance/types/intersection/intersectionArithmetic.ts === +let numberObject: number & { foo: any }; +>numberObject : number & { foo: any; } +>foo : any + +let stringObject: string & { foo: any }; +>stringObject : string & { foo: any; } +>foo : any + +let numberString: number & string; +>numberString : number & string + +let a = numberObject + 1; +>a : number +>numberObject + 1 : number +>numberObject : number & { foo: any; } +>1 : number + +let b = stringObject + 1; +>b : string +>stringObject + 1 : string +>stringObject : string & { foo: any; } +>1 : number + +let c = numberObject + ''; +>c : string +>numberObject + '' : string +>numberObject : number & { foo: any; } +>'' : string + +let d = stringObject + ''; +>d : string +>stringObject + '' : string +>stringObject : string & { foo: any; } +>'' : string + +let e = numberObject + stringObject; +>e : string +>numberObject + stringObject : string +>numberObject : number & { foo: any; } +>stringObject : string & { foo: any; } + +let f = numberString + 1; +>f : number +>numberString + 1 : number +>numberString : number & string +>1 : number + +let g = numberString + ''; +>g : string +>numberString + '' : string +>numberString : number & string +>'' : string + +let h = numberString + numberString; +>h : number +>numberString + numberString : number +>numberString : number & string +>numberString : number & string + +let i = numberObject * 2; +>i : number +>numberObject * 2 : number +>numberObject : number & { foo: any; } +>2 : number + +let j = numberString * 2; +>j : number +>numberString * 2 : number +>numberString : number & string +>2 : number + diff --git a/tests/baselines/reference/intersectionElementAccess.js b/tests/baselines/reference/intersectionElementAccess.js new file mode 100644 index 0000000000000..e61b602ca3f05 --- /dev/null +++ b/tests/baselines/reference/intersectionElementAccess.js @@ -0,0 +1,23 @@ +//// [intersectionElementAccess.ts] +let numberObject: number & { foo: any }; +let stringObject: string & { foo: any }; +let numberString: number & string; + +let object: { + [ index: number ]: { stringIndexer: any, numberIndexer: any }, + [ key: string]: { stringIndexer: any } +} + +let a = object[numberObject]; +let b = object[stringObject]; +let c = object[numberString]; + + +//// [intersectionElementAccess.js] +var numberObject; +var stringObject; +var numberString; +var object; +var a = object[numberObject]; +var b = object[stringObject]; +var c = object[numberString]; diff --git a/tests/baselines/reference/intersectionElementAccess.symbols b/tests/baselines/reference/intersectionElementAccess.symbols new file mode 100644 index 0000000000000..cca71266c56e4 --- /dev/null +++ b/tests/baselines/reference/intersectionElementAccess.symbols @@ -0,0 +1,40 @@ +=== tests/cases/conformance/types/intersection/intersectionElementAccess.ts === +let numberObject: number & { foo: any }; +>numberObject : Symbol(numberObject, Decl(intersectionElementAccess.ts, 0, 3)) +>foo : Symbol(foo, Decl(intersectionElementAccess.ts, 0, 28)) + +let stringObject: string & { foo: any }; +>stringObject : Symbol(stringObject, Decl(intersectionElementAccess.ts, 1, 3)) +>foo : Symbol(foo, Decl(intersectionElementAccess.ts, 1, 28)) + +let numberString: number & string; +>numberString : Symbol(numberString, Decl(intersectionElementAccess.ts, 2, 3)) + +let object: { +>object : Symbol(object, Decl(intersectionElementAccess.ts, 4, 3)) + + [ index: number ]: { stringIndexer: any, numberIndexer: any }, +>index : Symbol(index, Decl(intersectionElementAccess.ts, 5, 2)) +>stringIndexer : Symbol(stringIndexer, Decl(intersectionElementAccess.ts, 5, 21)) +>numberIndexer : Symbol(numberIndexer, Decl(intersectionElementAccess.ts, 5, 41)) + + [ key: string]: { stringIndexer: any } +>key : Symbol(key, Decl(intersectionElementAccess.ts, 6, 2)) +>stringIndexer : Symbol(stringIndexer, Decl(intersectionElementAccess.ts, 6, 18)) +} + +let a = object[numberObject]; +>a : Symbol(a, Decl(intersectionElementAccess.ts, 9, 3)) +>object : Symbol(object, Decl(intersectionElementAccess.ts, 4, 3)) +>numberObject : Symbol(numberObject, Decl(intersectionElementAccess.ts, 0, 3)) + +let b = object[stringObject]; +>b : Symbol(b, Decl(intersectionElementAccess.ts, 10, 3)) +>object : Symbol(object, Decl(intersectionElementAccess.ts, 4, 3)) +>stringObject : Symbol(stringObject, Decl(intersectionElementAccess.ts, 1, 3)) + +let c = object[numberString]; +>c : Symbol(c, Decl(intersectionElementAccess.ts, 11, 3)) +>object : Symbol(object, Decl(intersectionElementAccess.ts, 4, 3)) +>numberString : Symbol(numberString, Decl(intersectionElementAccess.ts, 2, 3)) + diff --git a/tests/baselines/reference/intersectionElementAccess.types b/tests/baselines/reference/intersectionElementAccess.types new file mode 100644 index 0000000000000..533d608912eb0 --- /dev/null +++ b/tests/baselines/reference/intersectionElementAccess.types @@ -0,0 +1,43 @@ +=== tests/cases/conformance/types/intersection/intersectionElementAccess.ts === +let numberObject: number & { foo: any }; +>numberObject : number & { foo: any; } +>foo : any + +let stringObject: string & { foo: any }; +>stringObject : string & { foo: any; } +>foo : any + +let numberString: number & string; +>numberString : number & string + +let object: { +>object : { [key: string]: { stringIndexer: any; }; [index: number]: { stringIndexer: any; numberIndexer: any; }; } + + [ index: number ]: { stringIndexer: any, numberIndexer: any }, +>index : number +>stringIndexer : any +>numberIndexer : any + + [ key: string]: { stringIndexer: any } +>key : string +>stringIndexer : any +} + +let a = object[numberObject]; +>a : { stringIndexer: any; numberIndexer: any; } +>object[numberObject] : { stringIndexer: any; numberIndexer: any; } +>object : { [key: string]: { stringIndexer: any; }; [index: number]: { stringIndexer: any; numberIndexer: any; }; } +>numberObject : number & { foo: any; } + +let b = object[stringObject]; +>b : { stringIndexer: any; } +>object[stringObject] : { stringIndexer: any; } +>object : { [key: string]: { stringIndexer: any; }; [index: number]: { stringIndexer: any; numberIndexer: any; }; } +>stringObject : string & { foo: any; } + +let c = object[numberString]; +>c : { stringIndexer: any; numberIndexer: any; } +>object[numberString] : { stringIndexer: any; numberIndexer: any; } +>object : { [key: string]: { stringIndexer: any; }; [index: number]: { stringIndexer: any; numberIndexer: any; }; } +>numberString : number & string + diff --git a/tests/cases/conformance/types/intersection/intersectionArithmetic.ts b/tests/cases/conformance/types/intersection/intersectionArithmetic.ts new file mode 100644 index 0000000000000..e832fc091be21 --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionArithmetic.ts @@ -0,0 +1,16 @@ +let numberObject: number & { foo: any }; +let stringObject: string & { foo: any }; +let numberString: number & string; + +let a = numberObject + 1; +let b = stringObject + 1; +let c = numberObject + ''; +let d = stringObject + ''; +let e = numberObject + stringObject; + +let f = numberString + 1; +let g = numberString + ''; +let h = numberString + numberString; + +let i = numberObject * 2; +let j = numberString * 2; diff --git a/tests/cases/conformance/types/intersection/intersectionElementAccess.ts b/tests/cases/conformance/types/intersection/intersectionElementAccess.ts new file mode 100644 index 0000000000000..5d106670ff8be --- /dev/null +++ b/tests/cases/conformance/types/intersection/intersectionElementAccess.ts @@ -0,0 +1,12 @@ +let numberObject: number & { foo: any }; +let stringObject: string & { foo: any }; +let numberString: number & string; + +let object: { + [ index: number ]: { stringIndexer: any, numberIndexer: any }, + [ key: string]: { stringIndexer: any } +} + +let a = object[numberObject]; +let b = object[stringObject]; +let c = object[numberString];