From f2e30f66936d4e4192aa0bb32049d7e64db10f59 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 00:04:20 -0800 Subject: [PATCH 01/12] Allow union and intersection as targets for object spread and rest, and distribute spread&rest over unions --- src/compiler/checker.ts | 31 ++++- .../restIntersectionOrIntersection.js | 29 +++++ .../restIntersectionOrIntersection.symbols | 38 ++++++ .../restIntersectionOrIntersection.types | 38 ++++++ .../restInvalidArgumentType.errors.txt | 110 +++++++++++++++++ .../reference/restInvalidArgumentType.js | 115 ++++++++++++++++++ .../baselines/reference/spreadIntersection.js | 23 ++++ .../reference/spreadIntersection.symbols | 26 ++++ .../reference/spreadIntersection.types | 29 +++++ .../spreadInvalidArgumentType.errors.txt | 110 +++++++++++++++++ .../reference/spreadInvalidArgumentType.js | 114 +++++++++++++++++ tests/baselines/reference/spreadUnion.js | 28 +++++ tests/baselines/reference/spreadUnion.symbols | 38 ++++++ tests/baselines/reference/spreadUnion.types | 42 +++++++ .../restIntersectionOrIntersection.ts | 10 ++ .../cases/compiler/restInvalidArgumentType.ts | 59 +++++++++ tests/cases/compiler/spreadIntersection.ts | 7 ++ .../compiler/spreadInvalidArgumentType.ts | 59 +++++++++ tests/cases/compiler/spreadUnion.ts | 10 ++ 19 files changed, 911 insertions(+), 5 deletions(-) create mode 100644 tests/baselines/reference/restIntersectionOrIntersection.js create mode 100644 tests/baselines/reference/restIntersectionOrIntersection.symbols create mode 100644 tests/baselines/reference/restIntersectionOrIntersection.types create mode 100644 tests/baselines/reference/restInvalidArgumentType.errors.txt create mode 100644 tests/baselines/reference/restInvalidArgumentType.js create mode 100644 tests/baselines/reference/spreadIntersection.js create mode 100644 tests/baselines/reference/spreadIntersection.symbols create mode 100644 tests/baselines/reference/spreadIntersection.types create mode 100644 tests/baselines/reference/spreadInvalidArgumentType.errors.txt create mode 100644 tests/baselines/reference/spreadInvalidArgumentType.js create mode 100644 tests/baselines/reference/spreadUnion.js create mode 100644 tests/baselines/reference/spreadUnion.symbols create mode 100644 tests/baselines/reference/spreadUnion.types create mode 100644 tests/cases/compiler/restIntersectionOrIntersection.ts create mode 100644 tests/cases/compiler/restInvalidArgumentType.ts create mode 100644 tests/cases/compiler/spreadIntersection.ts create mode 100644 tests/cases/compiler/spreadInvalidArgumentType.ts create mode 100644 tests/cases/compiler/spreadUnion.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 527735a3b0f4a..e937f6d9b973d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3054,7 +3054,10 @@ namespace ts { } function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { - Debug.assert(!!(source.flags & TypeFlags.Object), "Rest types only support object types right now."); + if (source.flags & TypeFlags.Union) { + return getUnionType(map((source).types, t => getRestType(t, properties, symbol))); + } + const members = createMap(); const names = createMap(); for (const name of properties) { @@ -3095,7 +3098,7 @@ namespace ts { let type: Type; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { - if (!(parentType.flags & TypeFlags.Object)) { + if (isInvalidValidSpreadType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } @@ -6102,11 +6105,19 @@ namespace ts { * this function should be called in a left folding style, with left = previous result of getSpreadType * and right = the new element to be spread. */ - function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): ResolvedType | IntrinsicType { - Debug.assert(!!(left.flags & (TypeFlags.Object | TypeFlags.Any)) && !!(right.flags & (TypeFlags.Object | TypeFlags.Any)), "Only object types may be spread."); + function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): Type { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } + + if (left.flags & TypeFlags.Union) { + return getUnionType(map((left).types, t => getSpreadType(t, right, isFromObjectLiteral))); + } + + if (right.flags & TypeFlags.Union) { + return getUnionType(map((right).types, t => getSpreadType(left, t, isFromObjectLiteral))); + } + const members = createMap(); const skippedPrivateMembers = createMap(); let stringIndexInfo: IndexInfo; @@ -11438,7 +11449,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadAssignment).expression); - if (!(type.flags & (TypeFlags.Object | TypeFlags.Any))) { + if (!(type.flags & TypeFlags.Any) && isInvalidValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } @@ -11516,6 +11527,16 @@ namespace ts { } } + function isInvalidValidSpreadType(type: Type): boolean { + if (type.flags & TypeFlags.Object) { + return isGenericMappedType(type); + } + else if (type.flags & TypeFlags.UnionOrIntersection) { + return forEach((type).types, isInvalidValidSpreadType); + } + return true; + } + function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { checkJsxOpeningLikeElement(node); return jsxElementType || anyType; diff --git a/tests/baselines/reference/restIntersectionOrIntersection.js b/tests/baselines/reference/restIntersectionOrIntersection.js new file mode 100644 index 0000000000000..a60a5acbd9328 --- /dev/null +++ b/tests/baselines/reference/restIntersectionOrIntersection.js @@ -0,0 +1,29 @@ +//// [restIntersectionOrIntersection.ts] +var intersection: { x: number, y: number } & { w: string, z: string }; +var union: { a: number, c: boolean } | { a: string, b: string }; + + +var rest1: { y: number, w: string, z: string }; +var {x, ...rest1 } = intersection; + +var rest2: { c: boolean } | { b: string }; +var {a, ...rest2 } = union; + + + +//// [restIntersectionOrIntersection.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var intersection; +var union; +var rest1; +var x = intersection.x, rest1 = __rest(intersection, ["x"]); +var rest2; +var a = union.a, rest2 = __rest(union, ["a"]); diff --git a/tests/baselines/reference/restIntersectionOrIntersection.symbols b/tests/baselines/reference/restIntersectionOrIntersection.symbols new file mode 100644 index 0000000000000..f2eb4f16014f0 --- /dev/null +++ b/tests/baselines/reference/restIntersectionOrIntersection.symbols @@ -0,0 +1,38 @@ +=== tests/cases/compiler/restIntersectionOrIntersection.ts === +var intersection: { x: number, y: number } & { w: string, z: string }; +>intersection : Symbol(intersection, Decl(restIntersectionOrIntersection.ts, 0, 3)) +>x : Symbol(x, Decl(restIntersectionOrIntersection.ts, 0, 19)) +>y : Symbol(y, Decl(restIntersectionOrIntersection.ts, 0, 30)) +>w : Symbol(w, Decl(restIntersectionOrIntersection.ts, 0, 46)) +>z : Symbol(z, Decl(restIntersectionOrIntersection.ts, 0, 57)) + +var union: { a: number, c: boolean } | { a: string, b: string }; +>union : Symbol(union, Decl(restIntersectionOrIntersection.ts, 1, 3)) +>a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 1, 12)) +>c : Symbol(c, Decl(restIntersectionOrIntersection.ts, 1, 23)) +>a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 1, 40)) +>b : Symbol(b, Decl(restIntersectionOrIntersection.ts, 1, 51)) + + +var rest1: { y: number, w: string, z: string }; +>rest1 : Symbol(rest1, Decl(restIntersectionOrIntersection.ts, 4, 3), Decl(restIntersectionOrIntersection.ts, 5, 7)) +>y : Symbol(y, Decl(restIntersectionOrIntersection.ts, 4, 12)) +>w : Symbol(w, Decl(restIntersectionOrIntersection.ts, 4, 23)) +>z : Symbol(z, Decl(restIntersectionOrIntersection.ts, 4, 34)) + +var {x, ...rest1 } = intersection; +>x : Symbol(x, Decl(restIntersectionOrIntersection.ts, 5, 5)) +>rest1 : Symbol(rest1, Decl(restIntersectionOrIntersection.ts, 4, 3), Decl(restIntersectionOrIntersection.ts, 5, 7)) +>intersection : Symbol(intersection, Decl(restIntersectionOrIntersection.ts, 0, 3)) + +var rest2: { c: boolean } | { b: string }; +>rest2 : Symbol(rest2, Decl(restIntersectionOrIntersection.ts, 7, 3), Decl(restIntersectionOrIntersection.ts, 8, 7)) +>c : Symbol(c, Decl(restIntersectionOrIntersection.ts, 7, 12)) +>b : Symbol(b, Decl(restIntersectionOrIntersection.ts, 7, 29)) + +var {a, ...rest2 } = union; +>a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 8, 5)) +>rest2 : Symbol(rest2, Decl(restIntersectionOrIntersection.ts, 7, 3), Decl(restIntersectionOrIntersection.ts, 8, 7)) +>union : Symbol(union, Decl(restIntersectionOrIntersection.ts, 1, 3)) + + diff --git a/tests/baselines/reference/restIntersectionOrIntersection.types b/tests/baselines/reference/restIntersectionOrIntersection.types new file mode 100644 index 0000000000000..c87769ff3ccdf --- /dev/null +++ b/tests/baselines/reference/restIntersectionOrIntersection.types @@ -0,0 +1,38 @@ +=== tests/cases/compiler/restIntersectionOrIntersection.ts === +var intersection: { x: number, y: number } & { w: string, z: string }; +>intersection : { x: number; y: number; } & { w: string; z: string; } +>x : number +>y : number +>w : string +>z : string + +var union: { a: number, c: boolean } | { a: string, b: string }; +>union : { a: number; c: boolean; } | { a: string; b: string; } +>a : number +>c : boolean +>a : string +>b : string + + +var rest1: { y: number, w: string, z: string }; +>rest1 : { y: number; w: string; z: string; } +>y : number +>w : string +>z : string + +var {x, ...rest1 } = intersection; +>x : number +>rest1 : { y: number; w: string; z: string; } +>intersection : { x: number; y: number; } & { w: string; z: string; } + +var rest2: { c: boolean } | { b: string }; +>rest2 : { c: boolean; } | { b: string; } +>c : boolean +>b : string + +var {a, ...rest2 } = union; +>a : string | number +>rest2 : { c: boolean; } | { b: string; } +>union : { a: number; c: boolean; } | { a: string; b: string; } + + diff --git a/tests/baselines/reference/restInvalidArgumentType.errors.txt b/tests/baselines/reference/restInvalidArgumentType.errors.txt new file mode 100644 index 0000000000000..e7cf1ba6f9fc1 --- /dev/null +++ b/tests/baselines/reference/restInvalidArgumentType.errors.txt @@ -0,0 +1,110 @@ +tests/cases/compiler/restInvalidArgumentType.ts(31,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(33,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(35,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(36,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(38,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(41,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(42,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(44,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(45,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(47,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(48,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(50,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(51,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(55,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(56,13): error TS2700: Rest types may only be created from object types. +tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types may only be created from object types. + + +==== tests/cases/compiler/restInvalidArgumentType.ts (16 errors) ==== + enum E { v1, v2 }; + + function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var {...r1} = p1; // Error, generic type paramterre + ~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r2} = p2; // OK + var {...r3} = t; // Error, generic type paramter + ~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r4} = i; // Error, index access + ~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r5} = k; // Error, index + ~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r6} = mapped_generic; // Error, generic mapped object type + ~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r7} = mapped; // OK, non-generic mapped type + + var {...r8} = union_generic; // Error, union with generic type parameter + ~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r9} = union_primitive; // Error, union with generic type parameter + ~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r10} = intersection_generic; // Error, intersection with generic type parameter + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r11} = intersection_premitive; // Error, intersection with generic type parameter + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r12} = num; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r13} = str; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r14} = u; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r15} = n; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + var {...r18} = literal_number; // Error + ~~~ +!!! error TS2700: Rest types may only be created from object types. + + var {...r19} = e; // Error, enum + ~~~ +!!! error TS2700: Rest types may only be created from object types. + } \ No newline at end of file diff --git a/tests/baselines/reference/restInvalidArgumentType.js b/tests/baselines/reference/restInvalidArgumentType.js new file mode 100644 index 0000000000000..23b46a2f7756f --- /dev/null +++ b/tests/baselines/reference/restInvalidArgumentType.js @@ -0,0 +1,115 @@ +//// [restInvalidArgumentType.ts] +enum E { v1, v2 }; + +function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var {...r1} = p1; // Error, generic type paramterre + var {...r2} = p2; // OK + var {...r3} = t; // Error, generic type paramter + + var {...r4} = i; // Error, index access + var {...r5} = k; // Error, index + + var {...r6} = mapped_generic; // Error, generic mapped object type + var {...r7} = mapped; // OK, non-generic mapped type + + var {...r8} = union_generic; // Error, union with generic type parameter + var {...r9} = union_primitive; // Error, union with generic type parameter + + var {...r10} = intersection_generic; // Error, intersection with generic type parameter + var {...r11} = intersection_premitive; // Error, intersection with generic type parameter + + var {...r12} = num; // Error + var {...r13} = str; // Error + + var {...r14} = u; // Error + var {...r15} = n; // Error + + var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + var {...r18} = literal_number; // Error + + var {...r19} = e; // Error, enum +} + +//// [restInvalidArgumentType.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var E; +(function (E) { + E[E["v1"] = 0] = "v1"; + E[E["v2"] = 1] = "v2"; +})(E || (E = {})); +; +function f(p1, p2) { + var t; + var i; + var k; + var mapped_generic; + var mapped; + var union_generic; + var union_primitive; + var intersection_generic; + var intersection_premitive; + var num; + var str; + var u; + var n; + var a; + var literal_string; + var literal_number; + var e; + var r1 = __rest(p1, []); // Error, generic type paramterre + var r2 = __rest(p2, []); // OK + var r3 = __rest(t, []); // Error, generic type paramter + var r4 = __rest(i, []); // Error, index access + var r5 = __rest(k, []); // Error, index + var r6 = __rest(mapped_generic, []); // Error, generic mapped object type + var r7 = __rest(mapped, []); // OK, non-generic mapped type + var r8 = __rest(union_generic, []); // Error, union with generic type parameter + var r9 = __rest(union_primitive, []); // Error, union with generic type parameter + var r10 = __rest(intersection_generic, []); // Error, intersection with generic type parameter + var r11 = __rest(intersection_premitive, []); // Error, intersection with generic type parameter + var r12 = __rest(num, []); // Error + var r13 = __rest(str, []); // Error + var r14 = __rest(u, []); // Error + var r15 = __rest(n, []); // Error + var r16 = __rest(a, []); // OK + var r17 = __rest(literal_string, []); // Error + var r18 = __rest(literal_number, []); // Error + var r19 = __rest(e, []); // Error, enum +} diff --git a/tests/baselines/reference/spreadIntersection.js b/tests/baselines/reference/spreadIntersection.js new file mode 100644 index 0000000000000..b3fa9f0c2fbc1 --- /dev/null +++ b/tests/baselines/reference/spreadIntersection.js @@ -0,0 +1,23 @@ +//// [spreadIntersection.ts] +var intersection: { a: number } & { b: string }; + +var o1: { a: number, b: string }; +var o1 = { ...intersection }; + +var o2: { a: number, b: string, c: boolean }; +var o2 = { ...intersection, c: false }; + +//// [spreadIntersection.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var intersection; +var o1; +var o1 = __assign({}, intersection); +var o2; +var o2 = __assign({}, intersection, { c: false }); diff --git a/tests/baselines/reference/spreadIntersection.symbols b/tests/baselines/reference/spreadIntersection.symbols new file mode 100644 index 0000000000000..1f6b3c12de16c --- /dev/null +++ b/tests/baselines/reference/spreadIntersection.symbols @@ -0,0 +1,26 @@ +=== tests/cases/compiler/spreadIntersection.ts === +var intersection: { a: number } & { b: string }; +>intersection : Symbol(intersection, Decl(spreadIntersection.ts, 0, 3)) +>a : Symbol(a, Decl(spreadIntersection.ts, 0, 19)) +>b : Symbol(b, Decl(spreadIntersection.ts, 0, 35)) + +var o1: { a: number, b: string }; +>o1 : Symbol(o1, Decl(spreadIntersection.ts, 2, 3), Decl(spreadIntersection.ts, 3, 3)) +>a : Symbol(a, Decl(spreadIntersection.ts, 2, 9)) +>b : Symbol(b, Decl(spreadIntersection.ts, 2, 20)) + +var o1 = { ...intersection }; +>o1 : Symbol(o1, Decl(spreadIntersection.ts, 2, 3), Decl(spreadIntersection.ts, 3, 3)) +>intersection : Symbol(intersection, Decl(spreadIntersection.ts, 0, 3)) + +var o2: { a: number, b: string, c: boolean }; +>o2 : Symbol(o2, Decl(spreadIntersection.ts, 5, 3), Decl(spreadIntersection.ts, 6, 3)) +>a : Symbol(a, Decl(spreadIntersection.ts, 5, 9)) +>b : Symbol(b, Decl(spreadIntersection.ts, 5, 20)) +>c : Symbol(c, Decl(spreadIntersection.ts, 5, 31)) + +var o2 = { ...intersection, c: false }; +>o2 : Symbol(o2, Decl(spreadIntersection.ts, 5, 3), Decl(spreadIntersection.ts, 6, 3)) +>intersection : Symbol(intersection, Decl(spreadIntersection.ts, 0, 3)) +>c : Symbol(c, Decl(spreadIntersection.ts, 6, 27)) + diff --git a/tests/baselines/reference/spreadIntersection.types b/tests/baselines/reference/spreadIntersection.types new file mode 100644 index 0000000000000..c3c6b99adeede --- /dev/null +++ b/tests/baselines/reference/spreadIntersection.types @@ -0,0 +1,29 @@ +=== tests/cases/compiler/spreadIntersection.ts === +var intersection: { a: number } & { b: string }; +>intersection : { a: number; } & { b: string; } +>a : number +>b : string + +var o1: { a: number, b: string }; +>o1 : { a: number; b: string; } +>a : number +>b : string + +var o1 = { ...intersection }; +>o1 : { a: number; b: string; } +>{ ...intersection } : { a: number; b: string; } +>intersection : { a: number; } & { b: string; } + +var o2: { a: number, b: string, c: boolean }; +>o2 : { a: number; b: string; c: boolean; } +>a : number +>b : string +>c : boolean + +var o2 = { ...intersection, c: false }; +>o2 : { a: number; b: string; c: boolean; } +>{ ...intersection, c: false } : { c: boolean; a: number; b: string; } +>intersection : { a: number; } & { b: string; } +>c : boolean +>false : false + diff --git a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt new file mode 100644 index 0000000000000..34356e538131f --- /dev/null +++ b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt @@ -0,0 +1,110 @@ +tests/cases/compiler/spreadInvalidArgumentType.ts(31,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(33,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(35,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(36,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(38,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(41,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(42,16): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(44,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(45,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(47,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(48,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(50,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(51,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(55,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(56,17): error TS2698: Spread types may only be created from object types. +tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread types may only be created from object types. + + +==== tests/cases/compiler/spreadInvalidArgumentType.ts (16 errors) ==== + enum E { v1, v2 }; + + function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var o1 = { ...p1 }; // Error, generic type paramterre + ~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // Error, generic type paramter + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o4 = { ...i }; // Error, index access + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o5 = { ...k }; // Error, index + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o6 = { ...mapped_generic }; // Error, generic mapped object type + ~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o7 = { ...mapped }; // OK, non-generic mapped type + + var o8 = { ...union_generic }; // Error, union with generic type parameter + ~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o9 = { ...union_primitive }; // Error, union with generic type parameter + ~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter + ~~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o12 = { ...num }; // Error + ~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o13 = { ...str }; // Error + ~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o14 = { ...u }; // Error + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o15 = { ...n }; // Error + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + var o18 = { ...literal_number }; // Error + ~~~~~~~~~~~~~~~~~ +!!! error TS2698: Spread types may only be created from object types. + + var o19 = { ...e }; // Error, enum + ~~~~ +!!! error TS2698: Spread types may only be created from object types. + } \ No newline at end of file diff --git a/tests/baselines/reference/spreadInvalidArgumentType.js b/tests/baselines/reference/spreadInvalidArgumentType.js new file mode 100644 index 0000000000000..ecea599842e9a --- /dev/null +++ b/tests/baselines/reference/spreadInvalidArgumentType.js @@ -0,0 +1,114 @@ +//// [spreadInvalidArgumentType.ts] +enum E { v1, v2 }; + +function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var o1 = { ...p1 }; // Error, generic type paramterre + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // Error, generic type paramter + + var o4 = { ...i }; // Error, index access + var o5 = { ...k }; // Error, index + + var o6 = { ...mapped_generic }; // Error, generic mapped object type + var o7 = { ...mapped }; // OK, non-generic mapped type + + var o8 = { ...union_generic }; // Error, union with generic type parameter + var o9 = { ...union_primitive }; // Error, union with generic type parameter + + var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter + var o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter + + var o12 = { ...num }; // Error + var o13 = { ...str }; // Error + + var o14 = { ...u }; // Error + var o15 = { ...n }; // Error + + var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + var o18 = { ...literal_number }; // Error + + var o19 = { ...e }; // Error, enum +} + +//// [spreadInvalidArgumentType.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var E; +(function (E) { + E[E["v1"] = 0] = "v1"; + E[E["v2"] = 1] = "v2"; +})(E || (E = {})); +; +function f(p1, p2) { + var t; + var i; + var k; + var mapped_generic; + var mapped; + var union_generic; + var union_primitive; + var intersection_generic; + var intersection_premitive; + var num; + var str; + var u; + var n; + var a; + var literal_string; + var literal_number; + var e; + var o1 = __assign({}, p1); // Error, generic type paramterre + var o2 = __assign({}, p2); // OK + var o3 = __assign({}, t); // Error, generic type paramter + var o4 = __assign({}, i); // Error, index access + var o5 = __assign({}, k); // Error, index + var o6 = __assign({}, mapped_generic); // Error, generic mapped object type + var o7 = __assign({}, mapped); // OK, non-generic mapped type + var o8 = __assign({}, union_generic); // Error, union with generic type parameter + var o9 = __assign({}, union_primitive); // Error, union with generic type parameter + var o10 = __assign({}, intersection_generic); // Error, intersection with generic type parameter + var o11 = __assign({}, intersection_premitive); // Error, intersection with generic type parameter + var o12 = __assign({}, num); // Error + var o13 = __assign({}, str); // Error + var o14 = __assign({}, u); // Error + var o15 = __assign({}, n); // Error + var o16 = __assign({}, a); // OK + var o17 = __assign({}, literal_string); // Error + var o18 = __assign({}, literal_number); // Error + var o19 = __assign({}, e); // Error, enum +} diff --git a/tests/baselines/reference/spreadUnion.js b/tests/baselines/reference/spreadUnion.js new file mode 100644 index 0000000000000..2691a3acdcc22 --- /dev/null +++ b/tests/baselines/reference/spreadUnion.js @@ -0,0 +1,28 @@ +//// [spreadUnion.ts] +var union: { a: number } | { b: string }; + +var o3: { a: number } | { b: string }; +var o3 = { ...union }; + +var o4: { a: boolean } | { b: string , a: boolean}; +var o4 = { ...union, a: false }; + +var o5: { a: number } | { b: string } | { a: number, b: string }; +var o5 = { ...union, ...union }; + +//// [spreadUnion.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var union; +var o3; +var o3 = __assign({}, union); +var o4; +var o4 = __assign({}, union, { a: false }); +var o5; +var o5 = __assign({}, union, union); diff --git a/tests/baselines/reference/spreadUnion.symbols b/tests/baselines/reference/spreadUnion.symbols new file mode 100644 index 0000000000000..40a63d56d49c8 --- /dev/null +++ b/tests/baselines/reference/spreadUnion.symbols @@ -0,0 +1,38 @@ +=== tests/cases/compiler/spreadUnion.ts === +var union: { a: number } | { b: string }; +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 0, 12)) +>b : Symbol(b, Decl(spreadUnion.ts, 0, 28)) + +var o3: { a: number } | { b: string }; +>o3 : Symbol(o3, Decl(spreadUnion.ts, 2, 3), Decl(spreadUnion.ts, 3, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 2, 9)) +>b : Symbol(b, Decl(spreadUnion.ts, 2, 25)) + +var o3 = { ...union }; +>o3 : Symbol(o3, Decl(spreadUnion.ts, 2, 3), Decl(spreadUnion.ts, 3, 3)) +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) + +var o4: { a: boolean } | { b: string , a: boolean}; +>o4 : Symbol(o4, Decl(spreadUnion.ts, 5, 3), Decl(spreadUnion.ts, 6, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 5, 9)) +>b : Symbol(b, Decl(spreadUnion.ts, 5, 26)) +>a : Symbol(a, Decl(spreadUnion.ts, 5, 38)) + +var o4 = { ...union, a: false }; +>o4 : Symbol(o4, Decl(spreadUnion.ts, 5, 3), Decl(spreadUnion.ts, 6, 3)) +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 6, 21)) + +var o5: { a: number } | { b: string } | { a: number, b: string }; +>o5 : Symbol(o5, Decl(spreadUnion.ts, 8, 3), Decl(spreadUnion.ts, 9, 3)) +>a : Symbol(a, Decl(spreadUnion.ts, 8, 9)) +>b : Symbol(b, Decl(spreadUnion.ts, 8, 25)) +>a : Symbol(a, Decl(spreadUnion.ts, 8, 41)) +>b : Symbol(b, Decl(spreadUnion.ts, 8, 52)) + +var o5 = { ...union, ...union }; +>o5 : Symbol(o5, Decl(spreadUnion.ts, 8, 3), Decl(spreadUnion.ts, 9, 3)) +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) +>union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) + diff --git a/tests/baselines/reference/spreadUnion.types b/tests/baselines/reference/spreadUnion.types new file mode 100644 index 0000000000000..9e5ac1cffd555 --- /dev/null +++ b/tests/baselines/reference/spreadUnion.types @@ -0,0 +1,42 @@ +=== tests/cases/compiler/spreadUnion.ts === +var union: { a: number } | { b: string }; +>union : { a: number; } | { b: string; } +>a : number +>b : string + +var o3: { a: number } | { b: string }; +>o3 : { a: number; } | { b: string; } +>a : number +>b : string + +var o3 = { ...union }; +>o3 : { a: number; } | { b: string; } +>{ ...union } : { a: number; } | { b: string; } +>union : { a: number; } | { b: string; } + +var o4: { a: boolean } | { b: string , a: boolean}; +>o4 : { a: boolean; } | { b: string; a: boolean; } +>a : boolean +>b : string +>a : boolean + +var o4 = { ...union, a: false }; +>o4 : { a: boolean; } | { b: string; a: boolean; } +>{ ...union, a: false } : { a: boolean; } | { a: boolean; b: string; } +>union : { a: number; } | { b: string; } +>a : boolean +>false : false + +var o5: { a: number } | { b: string } | { a: number, b: string }; +>o5 : { a: number; } | { b: string; } | { a: number; b: string; } +>a : number +>b : string +>a : number +>b : string + +var o5 = { ...union, ...union }; +>o5 : { a: number; } | { b: string; } | { a: number; b: string; } +>{ ...union, ...union } : { a: number; } | { b: string; a: number; } | { a: number; b: string; } | { b: string; } +>union : { a: number; } | { b: string; } +>union : { a: number; } | { b: string; } + diff --git a/tests/cases/compiler/restIntersectionOrIntersection.ts b/tests/cases/compiler/restIntersectionOrIntersection.ts new file mode 100644 index 0000000000000..6d06ed5ebc263 --- /dev/null +++ b/tests/cases/compiler/restIntersectionOrIntersection.ts @@ -0,0 +1,10 @@ +var intersection: { x: number, y: number } & { w: string, z: string }; +var union: { a: number, c: boolean } | { a: string, b: string }; + + +var rest1: { y: number, w: string, z: string }; +var {x, ...rest1 } = intersection; + +var rest2: { c: boolean } | { b: string }; +var {a, ...rest2 } = union; + diff --git a/tests/cases/compiler/restInvalidArgumentType.ts b/tests/cases/compiler/restInvalidArgumentType.ts new file mode 100644 index 0000000000000..7f7037bbb333d --- /dev/null +++ b/tests/cases/compiler/restInvalidArgumentType.ts @@ -0,0 +1,59 @@ +enum E { v1, v2 }; + +function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var {...r1} = p1; // Error, generic type paramterre + var {...r2} = p2; // OK + var {...r3} = t; // Error, generic type paramter + + var {...r4} = i; // Error, index access + var {...r5} = k; // Error, index + + var {...r6} = mapped_generic; // Error, generic mapped object type + var {...r7} = mapped; // OK, non-generic mapped type + + var {...r8} = union_generic; // Error, union with generic type parameter + var {...r9} = union_primitive; // Error, union with generic type parameter + + var {...r10} = intersection_generic; // Error, intersection with generic type parameter + var {...r11} = intersection_premitive; // Error, intersection with generic type parameter + + var {...r12} = num; // Error + var {...r13} = str; // Error + + var {...r14} = u; // Error + var {...r15} = n; // Error + + var {...r16} = a; // OK + + var {...r17} = literal_string; // Error + var {...r18} = literal_number; // Error + + var {...r19} = e; // Error, enum +} \ No newline at end of file diff --git a/tests/cases/compiler/spreadIntersection.ts b/tests/cases/compiler/spreadIntersection.ts new file mode 100644 index 0000000000000..3b397dc40cc0d --- /dev/null +++ b/tests/cases/compiler/spreadIntersection.ts @@ -0,0 +1,7 @@ +var intersection: { a: number } & { b: string }; + +var o1: { a: number, b: string }; +var o1 = { ...intersection }; + +var o2: { a: number, b: string, c: boolean }; +var o2 = { ...intersection, c: false }; \ No newline at end of file diff --git a/tests/cases/compiler/spreadInvalidArgumentType.ts b/tests/cases/compiler/spreadInvalidArgumentType.ts new file mode 100644 index 0000000000000..bb8f4894711f9 --- /dev/null +++ b/tests/cases/compiler/spreadInvalidArgumentType.ts @@ -0,0 +1,59 @@ +enum E { v1, v2 }; + +function f(p1: T, p2: T[]) { + var t: T; + + var i: T["b"]; + var k: keyof T; + + var mapped_generic: {[P in keyof T]: T[P]}; + var mapped: {[P in "b"]: T[P]}; + + var union_generic: T | { a: number }; + var union_primitive: { a: number } | number; + + var intersection_generic: T & { a: number }; + var intersection_premitive: { a: number } | string; + + var num: number; + var str: number; + + var u: undefined; + var n: null; + + var a: any; + + var literal_string: "string"; + var literal_number: 42; + + var e: E; + + var o1 = { ...p1 }; // Error, generic type paramterre + var o2 = { ...p2 }; // OK + var o3 = { ...t }; // Error, generic type paramter + + var o4 = { ...i }; // Error, index access + var o5 = { ...k }; // Error, index + + var o6 = { ...mapped_generic }; // Error, generic mapped object type + var o7 = { ...mapped }; // OK, non-generic mapped type + + var o8 = { ...union_generic }; // Error, union with generic type parameter + var o9 = { ...union_primitive }; // Error, union with generic type parameter + + var o10 = { ...intersection_generic }; // Error, intersection with generic type parameter + var o11 = { ...intersection_premitive }; // Error, intersection with generic type parameter + + var o12 = { ...num }; // Error + var o13 = { ...str }; // Error + + var o14 = { ...u }; // Error + var o15 = { ...n }; // Error + + var o16 = { ...a }; // OK + + var o17 = { ...literal_string }; // Error + var o18 = { ...literal_number }; // Error + + var o19 = { ...e }; // Error, enum +} \ No newline at end of file diff --git a/tests/cases/compiler/spreadUnion.ts b/tests/cases/compiler/spreadUnion.ts new file mode 100644 index 0000000000000..ef8440122ed2b --- /dev/null +++ b/tests/cases/compiler/spreadUnion.ts @@ -0,0 +1,10 @@ +var union: { a: number } | { b: string }; + +var o3: { a: number } | { b: string }; +var o3 = { ...union }; + +var o4: { a: boolean } | { b: string , a: boolean}; +var o4 = { ...union, a: false }; + +var o5: { a: number } | { b: string } | { a: number, b: string }; +var o5 = { ...union, ...union }; \ No newline at end of file From 5c10764d9bafbc8fc056b380c597d00ced22e8b9 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 00:13:04 -0800 Subject: [PATCH 02/12] Fix function name --- src/compiler/checker.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index e937f6d9b973d..5b3f789732b85 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3098,7 +3098,7 @@ namespace ts { let type: Type; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { - if (isInvalidValidSpreadType(parentType)) { + if (isInvalidSpreadType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } @@ -11449,7 +11449,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadAssignment).expression); - if (!(type.flags & TypeFlags.Any) && isInvalidValidSpreadType(type)) { + if (!(type.flags & TypeFlags.Any) && isInvalidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } @@ -11527,12 +11527,12 @@ namespace ts { } } - function isInvalidValidSpreadType(type: Type): boolean { + function isInvalidSpreadType(type: Type): boolean { if (type.flags & TypeFlags.Object) { return isGenericMappedType(type); } else if (type.flags & TypeFlags.UnionOrIntersection) { - return forEach((type).types, isInvalidValidSpreadType); + return forEach((type).types, isInvalidSpreadType); } return true; } From 5c4f145d6adb073e9f1dd9aeaaa6ac85da76f09e Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 10:36:55 -0800 Subject: [PATCH 03/12] Change name of the function --- src/compiler/checker.ts | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5b3f789732b85..47ea4442e9e3c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3098,7 +3098,7 @@ namespace ts { let type: Type; if (pattern.kind === SyntaxKind.ObjectBindingPattern) { if (declaration.dotDotDotToken) { - if (isInvalidSpreadType(parentType)) { + if (!isValidSpreadType(parentType)) { error(declaration, Diagnostics.Rest_types_may_only_be_created_from_object_types); return unknownType; } @@ -11449,7 +11449,7 @@ namespace ts { typeFlags = 0; } const type = checkExpression((memberDecl as SpreadAssignment).expression); - if (!(type.flags & TypeFlags.Any) && isInvalidSpreadType(type)) { + if (!isValidSpreadType(type)) { error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types); return unknownType; } @@ -11527,14 +11527,21 @@ namespace ts { } } - function isInvalidSpreadType(type: Type): boolean { + function isValidSpreadType(type: Type): boolean { + if (type.flags & TypeFlags.Any) { + return true; + } if (type.flags & TypeFlags.Object) { - return isGenericMappedType(type); + return !isGenericMappedType(type); } else if (type.flags & TypeFlags.UnionOrIntersection) { - return forEach((type).types, isInvalidSpreadType); + for (const t of (type).types) { + if (!isValidSpreadType(t)) { + return false; + } + } } - return true; + return false; } function checkJsxSelfClosingElement(node: JsxSelfClosingElement) { From 216f2861335f303cc2fb1abdf18480426cd114c3 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 12:25:10 -0800 Subject: [PATCH 04/12] Handel null and undefined in object spread and rest --- src/compiler/checker.ts | 30 ++++++- .../reference/objectSpreadNegative.errors.txt | 8 +- .../restInvalidArgumentType.errors.txt | 12 +-- .../reference/restInvalidArgumentType.js | 8 +- tests/baselines/reference/restUnion.js | 36 ++++++++ tests/baselines/reference/restUnion.symbols | 44 ++++++++++ tests/baselines/reference/restUnion.types | 45 ++++++++++ tests/baselines/reference/restUnion2.js | 38 +++++++++ tests/baselines/reference/restUnion2.symbols | 52 ++++++++++++ tests/baselines/reference/restUnion2.types | 55 ++++++++++++ .../spreadInvalidArgumentType.errors.txt | 12 +-- .../reference/spreadInvalidArgumentType.js | 8 +- tests/baselines/reference/spreadUnion2.js | 49 +++++++++++ .../baselines/reference/spreadUnion2.symbols | 74 ++++++++++++++++ tests/baselines/reference/spreadUnion2.types | 84 +++++++++++++++++++ .../cases/compiler/restInvalidArgumentType.ts | 4 +- tests/cases/compiler/restUnion.ts | 14 ++++ tests/cases/compiler/restUnion2.ts | 19 +++++ .../compiler/spreadInvalidArgumentType.ts | 4 +- tests/cases/compiler/spreadUnion2.ts | 25 ++++++ 20 files changed, 580 insertions(+), 41 deletions(-) create mode 100644 tests/baselines/reference/restUnion.js create mode 100644 tests/baselines/reference/restUnion.symbols create mode 100644 tests/baselines/reference/restUnion.types create mode 100644 tests/baselines/reference/restUnion2.js create mode 100644 tests/baselines/reference/restUnion2.symbols create mode 100644 tests/baselines/reference/restUnion2.types create mode 100644 tests/baselines/reference/spreadUnion2.js create mode 100644 tests/baselines/reference/spreadUnion2.symbols create mode 100644 tests/baselines/reference/spreadUnion2.types create mode 100644 tests/cases/compiler/restUnion.ts create mode 100644 tests/cases/compiler/restUnion2.ts create mode 100644 tests/cases/compiler/spreadUnion2.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 47ea4442e9e3c..8177939fe61d3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3055,7 +3055,10 @@ namespace ts { function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { if (source.flags & TypeFlags.Union) { - return getUnionType(map((source).types, t => getRestType(t, properties, symbol))); + const types = filter((source).types, t => !(t.flags & TypeFlags.Nullable)); + if (types.length) { + return getUnionType(map(types, t => getRestType(t, properties, symbol))); + } } const members = createMap(); @@ -6111,11 +6114,29 @@ namespace ts { } if (left.flags & TypeFlags.Union) { - return getUnionType(map((left).types, t => getSpreadType(t, right, isFromObjectLiteral))); + const types = filter((left).types, t => !(t.flags & TypeFlags.Nullable)); + if (types.length) { + return getUnionType(map(types, t => getSpreadType(t, right, isFromObjectLiteral))); + } + else { + left = emptyObjectType + } + } + else if (left.flags & TypeFlags.Nullable) { + left = emptyObjectType; } if (right.flags & TypeFlags.Union) { - return getUnionType(map((right).types, t => getSpreadType(left, t, isFromObjectLiteral))); + const types = filter((right).types, t => !(t.flags & TypeFlags.Nullable)); + if (types.length) { + return getUnionType(map(types, t => getSpreadType(left, t, isFromObjectLiteral))); + } + else { + right = emptyObjectType + } + } + else if (right.flags & TypeFlags.Nullable) { + right = emptyObjectType; } const members = createMap(); @@ -11528,7 +11549,7 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - if (type.flags & TypeFlags.Any) { + if (type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined)) { return true; } if (type.flags & TypeFlags.Object) { @@ -11540,6 +11561,7 @@ namespace ts { return false; } } + return true; } return false; } diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index dc6a356708f12..e92b685b9102e 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -7,8 +7,6 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322 Property 's' is missing in type '{ b: boolean; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,20): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,24): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,19): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,19): error TS2698: Spread types may only be created from object types. tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,20): error TS2698: Spread types may only be created from object types. @@ -20,7 +18,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS269 tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. -==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (17 errors) ==== +==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (15 errors) ==== let o = { a: 1, b: 'no' } /// private propagates @@ -68,11 +66,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS269 // null, undefined and primitives are not allowed let spreadNull = { ...null }; - ~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. let spreadUndefind = { ...undefined }; - ~~~~~~~~~~~~ -!!! error TS2698: Spread types may only be created from object types. let spreadNum = { ...12 }; ~~~~~ !!! error TS2698: Spread types may only be created from object types. diff --git a/tests/baselines/reference/restInvalidArgumentType.errors.txt b/tests/baselines/reference/restInvalidArgumentType.errors.txt index e7cf1ba6f9fc1..fff2c7b3563bc 100644 --- a/tests/baselines/reference/restInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/restInvalidArgumentType.errors.txt @@ -9,14 +9,12 @@ tests/cases/compiler/restInvalidArgumentType.ts(44,13): error TS2700: Rest types tests/cases/compiler/restInvalidArgumentType.ts(45,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(47,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(48,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(50,13): error TS2700: Rest types may only be created from object types. -tests/cases/compiler/restInvalidArgumentType.ts(51,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(55,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(56,13): error TS2700: Rest types may only be created from object types. tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types may only be created from object types. -==== tests/cases/compiler/restInvalidArgumentType.ts (16 errors) ==== +==== tests/cases/compiler/restInvalidArgumentType.ts (14 errors) ==== enum E { v1, v2 }; function f(p1: T, p2: T[]) { @@ -88,12 +86,8 @@ tests/cases/compiler/restInvalidArgumentType.ts(58,13): error TS2700: Rest types ~~~ !!! error TS2700: Rest types may only be created from object types. - var {...r14} = u; // Error - ~~~ -!!! error TS2700: Rest types may only be created from object types. - var {...r15} = n; // Error - ~~~ -!!! error TS2700: Rest types may only be created from object types. + var {...r14} = u; // OK + var {...r15} = n; // OK var {...r16} = a; // OK diff --git a/tests/baselines/reference/restInvalidArgumentType.js b/tests/baselines/reference/restInvalidArgumentType.js index 23b46a2f7756f..22a547880eb09 100644 --- a/tests/baselines/reference/restInvalidArgumentType.js +++ b/tests/baselines/reference/restInvalidArgumentType.js @@ -48,8 +48,8 @@ function f(p1: T, p2: T[]) { var {...r12} = num; // Error var {...r13} = str; // Error - var {...r14} = u; // Error - var {...r15} = n; // Error + var {...r14} = u; // OK + var {...r15} = n; // OK var {...r16} = a; // OK @@ -106,8 +106,8 @@ function f(p1, p2) { var r11 = __rest(intersection_premitive, []); // Error, intersection with generic type parameter var r12 = __rest(num, []); // Error var r13 = __rest(str, []); // Error - var r14 = __rest(u, []); // Error - var r15 = __rest(n, []); // Error + var r14 = __rest(u, []); // OK + var r15 = __rest(n, []); // OK var r16 = __rest(a, []); // OK var r17 = __rest(literal_string, []); // Error var r18 = __rest(literal_number, []); // Error diff --git a/tests/baselines/reference/restUnion.js b/tests/baselines/reference/restUnion.js new file mode 100644 index 0000000000000..beaf514808b1d --- /dev/null +++ b/tests/baselines/reference/restUnion.js @@ -0,0 +1,36 @@ +//// [restUnion.ts] +var union: { a: number, c: boolean } | { a: string, b: string }; + +var rest1: { c: boolean } | { b: string }; +var {a, ...rest1 } = union; + + +var undefinedUnion: { n: number } | undefined; +var rest2: {}; +var {n, ...rest2 } = undefinedUnion; + + +var nullUnion: { n: number } | null; +var rest3: {}; +var {n, ...rest3 } = nullUnion; + + +//// [restUnion.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var union; +var rest1; +var a = union.a, rest1 = __rest(union, ["a"]); +var undefinedUnion; +var rest2; +var n = undefinedUnion.n, rest2 = __rest(undefinedUnion, ["n"]); +var nullUnion; +var rest3; +var n = nullUnion.n, rest3 = __rest(nullUnion, ["n"]); diff --git a/tests/baselines/reference/restUnion.symbols b/tests/baselines/reference/restUnion.symbols new file mode 100644 index 0000000000000..660c85badb4e7 --- /dev/null +++ b/tests/baselines/reference/restUnion.symbols @@ -0,0 +1,44 @@ +=== tests/cases/compiler/restUnion.ts === +var union: { a: number, c: boolean } | { a: string, b: string }; +>union : Symbol(union, Decl(restUnion.ts, 0, 3)) +>a : Symbol(a, Decl(restUnion.ts, 0, 12)) +>c : Symbol(c, Decl(restUnion.ts, 0, 23)) +>a : Symbol(a, Decl(restUnion.ts, 0, 40)) +>b : Symbol(b, Decl(restUnion.ts, 0, 51)) + +var rest1: { c: boolean } | { b: string }; +>rest1 : Symbol(rest1, Decl(restUnion.ts, 2, 3), Decl(restUnion.ts, 3, 7)) +>c : Symbol(c, Decl(restUnion.ts, 2, 12)) +>b : Symbol(b, Decl(restUnion.ts, 2, 29)) + +var {a, ...rest1 } = union; +>a : Symbol(a, Decl(restUnion.ts, 3, 5)) +>rest1 : Symbol(rest1, Decl(restUnion.ts, 2, 3), Decl(restUnion.ts, 3, 7)) +>union : Symbol(union, Decl(restUnion.ts, 0, 3)) + + +var undefinedUnion: { n: number } | undefined; +>undefinedUnion : Symbol(undefinedUnion, Decl(restUnion.ts, 6, 3)) +>n : Symbol(n, Decl(restUnion.ts, 6, 21)) + +var rest2: {}; +>rest2 : Symbol(rest2, Decl(restUnion.ts, 7, 3), Decl(restUnion.ts, 8, 7)) + +var {n, ...rest2 } = undefinedUnion; +>n : Symbol(n, Decl(restUnion.ts, 8, 5), Decl(restUnion.ts, 13, 5)) +>rest2 : Symbol(rest2, Decl(restUnion.ts, 7, 3), Decl(restUnion.ts, 8, 7)) +>undefinedUnion : Symbol(undefinedUnion, Decl(restUnion.ts, 6, 3)) + + +var nullUnion: { n: number } | null; +>nullUnion : Symbol(nullUnion, Decl(restUnion.ts, 11, 3)) +>n : Symbol(n, Decl(restUnion.ts, 11, 16)) + +var rest3: {}; +>rest3 : Symbol(rest3, Decl(restUnion.ts, 12, 3), Decl(restUnion.ts, 13, 7)) + +var {n, ...rest3 } = nullUnion; +>n : Symbol(n, Decl(restUnion.ts, 8, 5), Decl(restUnion.ts, 13, 5)) +>rest3 : Symbol(rest3, Decl(restUnion.ts, 12, 3), Decl(restUnion.ts, 13, 7)) +>nullUnion : Symbol(nullUnion, Decl(restUnion.ts, 11, 3)) + diff --git a/tests/baselines/reference/restUnion.types b/tests/baselines/reference/restUnion.types new file mode 100644 index 0000000000000..9837466684b26 --- /dev/null +++ b/tests/baselines/reference/restUnion.types @@ -0,0 +1,45 @@ +=== tests/cases/compiler/restUnion.ts === +var union: { a: number, c: boolean } | { a: string, b: string }; +>union : { a: number; c: boolean; } | { a: string; b: string; } +>a : number +>c : boolean +>a : string +>b : string + +var rest1: { c: boolean } | { b: string }; +>rest1 : { c: boolean; } | { b: string; } +>c : boolean +>b : string + +var {a, ...rest1 } = union; +>a : string | number +>rest1 : { c: boolean; } | { b: string; } +>union : { a: number; c: boolean; } | { a: string; b: string; } + + +var undefinedUnion: { n: number } | undefined; +>undefinedUnion : { n: number; } +>n : number + +var rest2: {}; +>rest2 : {} + +var {n, ...rest2 } = undefinedUnion; +>n : number +>rest2 : {} +>undefinedUnion : { n: number; } + + +var nullUnion: { n: number } | null; +>nullUnion : { n: number; } +>n : number +>null : null + +var rest3: {}; +>rest3 : {} + +var {n, ...rest3 } = nullUnion; +>n : number +>rest3 : {} +>nullUnion : { n: number; } + diff --git a/tests/baselines/reference/restUnion2.js b/tests/baselines/reference/restUnion2.js new file mode 100644 index 0000000000000..d746698164596 --- /dev/null +++ b/tests/baselines/reference/restUnion2.js @@ -0,0 +1,38 @@ +//// [restUnion2.ts] + +declare const undefinedUnion: { n: number } | undefined; +var rest2: { n: number }; +var {...rest2 } = undefinedUnion; + + +declare const nullUnion: { n: number } | null; +var rest3: { n: number }; +var {...rest3 } = nullUnion; + + +declare const nullAndUndefinedUnion: null | undefined; +var rest4: { }; +var {...rest4 } = nullAndUndefinedUnion; + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +var rest5: { n: number, s: string }; +var {...rest5 } = unionWithIntersection; + +//// [restUnion2.js] +var __rest = (this && this.__rest) || function (s, e) { + var t = {}; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) + t[p] = s[p]; + if (typeof Object.getOwnPropertySymbols === "function") + for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) + t[p[i]] = s[p[i]]; + return t; +}; +var rest2; +var rest2 = __rest(undefinedUnion, []); +var rest3; +var rest3 = __rest(nullUnion, []); +var rest4; +var rest4 = __rest(nullAndUndefinedUnion, []); +var rest5; +var rest5 = __rest(unionWithIntersection, []); diff --git a/tests/baselines/reference/restUnion2.symbols b/tests/baselines/reference/restUnion2.symbols new file mode 100644 index 0000000000000..20a113a23b498 --- /dev/null +++ b/tests/baselines/reference/restUnion2.symbols @@ -0,0 +1,52 @@ +=== tests/cases/compiler/restUnion2.ts === + +declare const undefinedUnion: { n: number } | undefined; +>undefinedUnion : Symbol(undefinedUnion, Decl(restUnion2.ts, 1, 13)) +>n : Symbol(n, Decl(restUnion2.ts, 1, 31)) + +var rest2: { n: number }; +>rest2 : Symbol(rest2, Decl(restUnion2.ts, 2, 3), Decl(restUnion2.ts, 3, 5)) +>n : Symbol(n, Decl(restUnion2.ts, 2, 12)) + +var {...rest2 } = undefinedUnion; +>rest2 : Symbol(rest2, Decl(restUnion2.ts, 2, 3), Decl(restUnion2.ts, 3, 5)) +>undefinedUnion : Symbol(undefinedUnion, Decl(restUnion2.ts, 1, 13)) + + +declare const nullUnion: { n: number } | null; +>nullUnion : Symbol(nullUnion, Decl(restUnion2.ts, 6, 13)) +>n : Symbol(n, Decl(restUnion2.ts, 6, 26)) + +var rest3: { n: number }; +>rest3 : Symbol(rest3, Decl(restUnion2.ts, 7, 3), Decl(restUnion2.ts, 8, 5)) +>n : Symbol(n, Decl(restUnion2.ts, 7, 12)) + +var {...rest3 } = nullUnion; +>rest3 : Symbol(rest3, Decl(restUnion2.ts, 7, 3), Decl(restUnion2.ts, 8, 5)) +>nullUnion : Symbol(nullUnion, Decl(restUnion2.ts, 6, 13)) + + +declare const nullAndUndefinedUnion: null | undefined; +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(restUnion2.ts, 11, 13)) + +var rest4: { }; +>rest4 : Symbol(rest4, Decl(restUnion2.ts, 12, 3), Decl(restUnion2.ts, 13, 5)) + +var {...rest4 } = nullAndUndefinedUnion; +>rest4 : Symbol(rest4, Decl(restUnion2.ts, 12, 3), Decl(restUnion2.ts, 13, 5)) +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(restUnion2.ts, 11, 13)) + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +>unionWithIntersection : Symbol(unionWithIntersection, Decl(restUnion2.ts, 15, 13)) +>n : Symbol(n, Decl(restUnion2.ts, 15, 39)) +>s : Symbol(s, Decl(restUnion2.ts, 15, 55)) + +var rest5: { n: number, s: string }; +>rest5 : Symbol(rest5, Decl(restUnion2.ts, 16, 3), Decl(restUnion2.ts, 17, 5)) +>n : Symbol(n, Decl(restUnion2.ts, 16, 12)) +>s : Symbol(s, Decl(restUnion2.ts, 16, 23)) + +var {...rest5 } = unionWithIntersection; +>rest5 : Symbol(rest5, Decl(restUnion2.ts, 16, 3), Decl(restUnion2.ts, 17, 5)) +>unionWithIntersection : Symbol(unionWithIntersection, Decl(restUnion2.ts, 15, 13)) + diff --git a/tests/baselines/reference/restUnion2.types b/tests/baselines/reference/restUnion2.types new file mode 100644 index 0000000000000..81b768777fd17 --- /dev/null +++ b/tests/baselines/reference/restUnion2.types @@ -0,0 +1,55 @@ +=== tests/cases/compiler/restUnion2.ts === + +declare const undefinedUnion: { n: number } | undefined; +>undefinedUnion : { n: number; } | undefined +>n : number + +var rest2: { n: number }; +>rest2 : { n: number; } +>n : number + +var {...rest2 } = undefinedUnion; +>rest2 : { n: number; } +>undefinedUnion : { n: number; } | undefined + + +declare const nullUnion: { n: number } | null; +>nullUnion : { n: number; } | null +>n : number +>null : null + +var rest3: { n: number }; +>rest3 : { n: number; } +>n : number + +var {...rest3 } = nullUnion; +>rest3 : { n: number; } +>nullUnion : { n: number; } | null + + +declare const nullAndUndefinedUnion: null | undefined; +>nullAndUndefinedUnion : null | undefined +>null : null + +var rest4: { }; +>rest4 : {} + +var {...rest4 } = nullAndUndefinedUnion; +>rest4 : {} +>nullAndUndefinedUnion : null | undefined + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +>unionWithIntersection : ({ n: number; } & { s: string; } & undefined) | null +>n : number +>s : string +>null : null + +var rest5: { n: number, s: string }; +>rest5 : { n: number; s: string; } +>n : number +>s : string + +var {...rest5 } = unionWithIntersection; +>rest5 : { n: number; s: string; } +>unionWithIntersection : ({ n: number; } & { s: string; } & undefined) | null + diff --git a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt index 34356e538131f..5088390f9eea9 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.errors.txt +++ b/tests/baselines/reference/spreadInvalidArgumentType.errors.txt @@ -9,14 +9,12 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(44,17): error TS2698: Spread t tests/cases/compiler/spreadInvalidArgumentType.ts(45,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(47,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(48,17): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(50,17): error TS2698: Spread types may only be created from object types. -tests/cases/compiler/spreadInvalidArgumentType.ts(51,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(55,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(56,17): error TS2698: Spread types may only be created from object types. tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread types may only be created from object types. -==== tests/cases/compiler/spreadInvalidArgumentType.ts (16 errors) ==== +==== tests/cases/compiler/spreadInvalidArgumentType.ts (14 errors) ==== enum E { v1, v2 }; function f(p1: T, p2: T[]) { @@ -88,12 +86,8 @@ tests/cases/compiler/spreadInvalidArgumentType.ts(58,17): error TS2698: Spread t ~~~~~~ !!! error TS2698: Spread types may only be created from object types. - var o14 = { ...u }; // Error - ~~~~ -!!! error TS2698: Spread types may only be created from object types. - var o15 = { ...n }; // Error - ~~~~ -!!! error TS2698: Spread types may only be created from object types. + var o14 = { ...u }; // OK + var o15 = { ...n }; // OK var o16 = { ...a }; // OK diff --git a/tests/baselines/reference/spreadInvalidArgumentType.js b/tests/baselines/reference/spreadInvalidArgumentType.js index ecea599842e9a..26f958f224da3 100644 --- a/tests/baselines/reference/spreadInvalidArgumentType.js +++ b/tests/baselines/reference/spreadInvalidArgumentType.js @@ -48,8 +48,8 @@ function f(p1: T, p2: T[]) { var o12 = { ...num }; // Error var o13 = { ...str }; // Error - var o14 = { ...u }; // Error - var o15 = { ...n }; // Error + var o14 = { ...u }; // OK + var o15 = { ...n }; // OK var o16 = { ...a }; // OK @@ -105,8 +105,8 @@ function f(p1, p2) { var o11 = __assign({}, intersection_premitive); // Error, intersection with generic type parameter var o12 = __assign({}, num); // Error var o13 = __assign({}, str); // Error - var o14 = __assign({}, u); // Error - var o15 = __assign({}, n); // Error + var o14 = __assign({}, u); // OK + var o15 = __assign({}, n); // OK var o16 = __assign({}, a); // OK var o17 = __assign({}, literal_string); // Error var o18 = __assign({}, literal_number); // Error diff --git a/tests/baselines/reference/spreadUnion2.js b/tests/baselines/reference/spreadUnion2.js new file mode 100644 index 0000000000000..6c7527af9dd26 --- /dev/null +++ b/tests/baselines/reference/spreadUnion2.js @@ -0,0 +1,49 @@ +//// [spreadUnion2.ts] + +declare const undefinedUnion: { a: number } | undefined; +declare const nullUnion: { b: number } | null; +declare const nullAndUndefinedUnion: null | undefined; + +var o1: { a: number }; +var o1 = { ...undefinedUnion }; + +var o2: { b: number }; +var o2 = { ...nullUnion }; + +var o3: { a: number, b: number }; +var o3 = { ...undefinedUnion, ...nullUnion }; +var o3 = { ...nullUnion, ...undefinedUnion }; + +var o4: { a: number }; +var o4 = { ...undefinedUnion, ...undefinedUnion }; + +var o5: { b: number }; +var o5 = { ...nullUnion, ...nullUnion }; + +var o6: { }; +var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +var o6 = { ...nullAndUndefinedUnion }; + +//// [spreadUnion2.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +var o1; +var o1 = __assign({}, undefinedUnion); +var o2; +var o2 = __assign({}, nullUnion); +var o3; +var o3 = __assign({}, undefinedUnion, nullUnion); +var o3 = __assign({}, nullUnion, undefinedUnion); +var o4; +var o4 = __assign({}, undefinedUnion, undefinedUnion); +var o5; +var o5 = __assign({}, nullUnion, nullUnion); +var o6; +var o6 = __assign({}, nullAndUndefinedUnion, nullAndUndefinedUnion); +var o6 = __assign({}, nullAndUndefinedUnion); diff --git a/tests/baselines/reference/spreadUnion2.symbols b/tests/baselines/reference/spreadUnion2.symbols new file mode 100644 index 0000000000000..cc2c194f2a65f --- /dev/null +++ b/tests/baselines/reference/spreadUnion2.symbols @@ -0,0 +1,74 @@ +=== tests/cases/compiler/spreadUnion2.ts === + +declare const undefinedUnion: { a: number } | undefined; +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) +>a : Symbol(a, Decl(spreadUnion2.ts, 1, 31)) + +declare const nullUnion: { b: number } | null; +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) +>b : Symbol(b, Decl(spreadUnion2.ts, 2, 26)) + +declare const nullAndUndefinedUnion: null | undefined; +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 3, 13)) + +var o1: { a: number }; +>o1 : Symbol(o1, Decl(spreadUnion2.ts, 5, 3), Decl(spreadUnion2.ts, 6, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 5, 9)) + +var o1 = { ...undefinedUnion }; +>o1 : Symbol(o1, Decl(spreadUnion2.ts, 5, 3), Decl(spreadUnion2.ts, 6, 3)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) + +var o2: { b: number }; +>o2 : Symbol(o2, Decl(spreadUnion2.ts, 8, 3), Decl(spreadUnion2.ts, 9, 3)) +>b : Symbol(b, Decl(spreadUnion2.ts, 8, 9)) + +var o2 = { ...nullUnion }; +>o2 : Symbol(o2, Decl(spreadUnion2.ts, 8, 3), Decl(spreadUnion2.ts, 9, 3)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) + +var o3: { a: number, b: number }; +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3), Decl(spreadUnion2.ts, 13, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 11, 9)) +>b : Symbol(b, Decl(spreadUnion2.ts, 11, 20)) + +var o3 = { ...undefinedUnion, ...nullUnion }; +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3), Decl(spreadUnion2.ts, 13, 3)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) + +var o3 = { ...nullUnion, ...undefinedUnion }; +>o3 : Symbol(o3, Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3), Decl(spreadUnion2.ts, 13, 3)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) + +var o4: { a: number }; +>o4 : Symbol(o4, Decl(spreadUnion2.ts, 15, 3), Decl(spreadUnion2.ts, 16, 3)) +>a : Symbol(a, Decl(spreadUnion2.ts, 15, 9)) + +var o4 = { ...undefinedUnion, ...undefinedUnion }; +>o4 : Symbol(o4, Decl(spreadUnion2.ts, 15, 3), Decl(spreadUnion2.ts, 16, 3)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) +>undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 1, 13)) + +var o5: { b: number }; +>o5 : Symbol(o5, Decl(spreadUnion2.ts, 18, 3), Decl(spreadUnion2.ts, 19, 3)) +>b : Symbol(b, Decl(spreadUnion2.ts, 18, 9)) + +var o5 = { ...nullUnion, ...nullUnion }; +>o5 : Symbol(o5, Decl(spreadUnion2.ts, 18, 3), Decl(spreadUnion2.ts, 19, 3)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) +>nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 2, 13)) + +var o6: { }; +>o6 : Symbol(o6, Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3), Decl(spreadUnion2.ts, 23, 3)) + +var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +>o6 : Symbol(o6, Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3), Decl(spreadUnion2.ts, 23, 3)) +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 3, 13)) +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 3, 13)) + +var o6 = { ...nullAndUndefinedUnion }; +>o6 : Symbol(o6, Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3), Decl(spreadUnion2.ts, 23, 3)) +>nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 3, 13)) + diff --git a/tests/baselines/reference/spreadUnion2.types b/tests/baselines/reference/spreadUnion2.types new file mode 100644 index 0000000000000..cf90381ca77f2 --- /dev/null +++ b/tests/baselines/reference/spreadUnion2.types @@ -0,0 +1,84 @@ +=== tests/cases/compiler/spreadUnion2.ts === + +declare const undefinedUnion: { a: number } | undefined; +>undefinedUnion : { a: number; } | undefined +>a : number + +declare const nullUnion: { b: number } | null; +>nullUnion : { b: number; } | null +>b : number +>null : null + +declare const nullAndUndefinedUnion: null | undefined; +>nullAndUndefinedUnion : null | undefined +>null : null + +var o1: { a: number }; +>o1 : { a: number; } +>a : number + +var o1 = { ...undefinedUnion }; +>o1 : { a: number; } +>{ ...undefinedUnion } : { a: number; } +>undefinedUnion : { a: number; } | undefined + +var o2: { b: number }; +>o2 : { b: number; } +>b : number + +var o2 = { ...nullUnion }; +>o2 : { b: number; } +>{ ...nullUnion } : { b: number; } +>nullUnion : { b: number; } | null + +var o3: { a: number, b: number }; +>o3 : { a: number; b: number; } +>a : number +>b : number + +var o3 = { ...undefinedUnion, ...nullUnion }; +>o3 : { a: number; b: number; } +>{ ...undefinedUnion, ...nullUnion } : { b: number; a: number; } +>undefinedUnion : { a: number; } | undefined +>nullUnion : { b: number; } | null + +var o3 = { ...nullUnion, ...undefinedUnion }; +>o3 : { a: number; b: number; } +>{ ...nullUnion, ...undefinedUnion } : { a: number; b: number; } +>nullUnion : { b: number; } | null +>undefinedUnion : { a: number; } | undefined + +var o4: { a: number }; +>o4 : { a: number; } +>a : number + +var o4 = { ...undefinedUnion, ...undefinedUnion }; +>o4 : { a: number; } +>{ ...undefinedUnion, ...undefinedUnion } : { a: number; } +>undefinedUnion : { a: number; } | undefined +>undefinedUnion : { a: number; } | undefined + +var o5: { b: number }; +>o5 : { b: number; } +>b : number + +var o5 = { ...nullUnion, ...nullUnion }; +>o5 : { b: number; } +>{ ...nullUnion, ...nullUnion } : { b: number; } +>nullUnion : { b: number; } | null +>nullUnion : { b: number; } | null + +var o6: { }; +>o6 : {} + +var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +>o6 : {} +>{ ...nullAndUndefinedUnion, ...nullAndUndefinedUnion } : {} +>nullAndUndefinedUnion : null | undefined +>nullAndUndefinedUnion : null | undefined + +var o6 = { ...nullAndUndefinedUnion }; +>o6 : {} +>{ ...nullAndUndefinedUnion } : {} +>nullAndUndefinedUnion : null | undefined + diff --git a/tests/cases/compiler/restInvalidArgumentType.ts b/tests/cases/compiler/restInvalidArgumentType.ts index 7f7037bbb333d..488f546e2310a 100644 --- a/tests/cases/compiler/restInvalidArgumentType.ts +++ b/tests/cases/compiler/restInvalidArgumentType.ts @@ -47,8 +47,8 @@ function f(p1: T, p2: T[]) { var {...r12} = num; // Error var {...r13} = str; // Error - var {...r14} = u; // Error - var {...r15} = n; // Error + var {...r14} = u; // OK + var {...r15} = n; // OK var {...r16} = a; // OK diff --git a/tests/cases/compiler/restUnion.ts b/tests/cases/compiler/restUnion.ts new file mode 100644 index 0000000000000..c838b37340f8d --- /dev/null +++ b/tests/cases/compiler/restUnion.ts @@ -0,0 +1,14 @@ +var union: { a: number, c: boolean } | { a: string, b: string }; + +var rest1: { c: boolean } | { b: string }; +var {a, ...rest1 } = union; + + +var undefinedUnion: { n: number } | undefined; +var rest2: {}; +var {n, ...rest2 } = undefinedUnion; + + +var nullUnion: { n: number } | null; +var rest3: {}; +var {n, ...rest3 } = nullUnion; diff --git a/tests/cases/compiler/restUnion2.ts b/tests/cases/compiler/restUnion2.ts new file mode 100644 index 0000000000000..83d94e03a7365 --- /dev/null +++ b/tests/cases/compiler/restUnion2.ts @@ -0,0 +1,19 @@ +// @strictNullChecks: true + +declare const undefinedUnion: { n: number } | undefined; +var rest2: { n: number }; +var {...rest2 } = undefinedUnion; + + +declare const nullUnion: { n: number } | null; +var rest3: { n: number }; +var {...rest3 } = nullUnion; + + +declare const nullAndUndefinedUnion: null | undefined; +var rest4: { }; +var {...rest4 } = nullAndUndefinedUnion; + +declare const unionWithIntersection: ({ n: number } & { s: string }) & undefined | null; +var rest5: { n: number, s: string }; +var {...rest5 } = unionWithIntersection; \ No newline at end of file diff --git a/tests/cases/compiler/spreadInvalidArgumentType.ts b/tests/cases/compiler/spreadInvalidArgumentType.ts index bb8f4894711f9..2ac6aa921f48c 100644 --- a/tests/cases/compiler/spreadInvalidArgumentType.ts +++ b/tests/cases/compiler/spreadInvalidArgumentType.ts @@ -47,8 +47,8 @@ function f(p1: T, p2: T[]) { var o12 = { ...num }; // Error var o13 = { ...str }; // Error - var o14 = { ...u }; // Error - var o15 = { ...n }; // Error + var o14 = { ...u }; // OK + var o15 = { ...n }; // OK var o16 = { ...a }; // OK diff --git a/tests/cases/compiler/spreadUnion2.ts b/tests/cases/compiler/spreadUnion2.ts new file mode 100644 index 0000000000000..25dba81c0dfca --- /dev/null +++ b/tests/cases/compiler/spreadUnion2.ts @@ -0,0 +1,25 @@ +// @strictNullChecks: true + +declare const undefinedUnion: { a: number } | undefined; +declare const nullUnion: { b: number } | null; +declare const nullAndUndefinedUnion: null | undefined; + +var o1: { a: number }; +var o1 = { ...undefinedUnion }; + +var o2: { b: number }; +var o2 = { ...nullUnion }; + +var o3: { a: number, b: number }; +var o3 = { ...undefinedUnion, ...nullUnion }; +var o3 = { ...nullUnion, ...undefinedUnion }; + +var o4: { a: number }; +var o4 = { ...undefinedUnion, ...undefinedUnion }; + +var o5: { b: number }; +var o5 = { ...nullUnion, ...nullUnion }; + +var o6: { }; +var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; +var o6 = { ...nullAndUndefinedUnion }; \ No newline at end of file From 86b48e3f89ada9fc29dee0e20c814830683a3bd2 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 12:26:57 -0800 Subject: [PATCH 05/12] Handel null and undefined in `__rest` --- src/compiler/transformers/destructuring.ts | 2 +- tests/baselines/reference/objectRest.js | 2 +- tests/baselines/reference/objectRestAssignment.js | 2 +- tests/baselines/reference/objectRestForOf.js | 2 +- tests/baselines/reference/objectRestNegative.js | 2 +- tests/baselines/reference/objectRestParameter.js | 2 +- tests/baselines/reference/restIntersectionOrIntersection.js | 2 +- tests/baselines/reference/restInvalidArgumentType.js | 2 +- tests/baselines/reference/restUnion.js | 2 +- tests/baselines/reference/restUnion2.js | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/compiler/transformers/destructuring.ts b/src/compiler/transformers/destructuring.ts index 43590791c83c6..8e32259ff0f2d 100644 --- a/src/compiler/transformers/destructuring.ts +++ b/src/compiler/transformers/destructuring.ts @@ -459,7 +459,7 @@ namespace ts { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRest.js b/tests/baselines/reference/objectRest.js index 85d8a6a573e37..e6d45c7a98aaf 100644 --- a/tests/baselines/reference/objectRest.js +++ b/tests/baselines/reference/objectRest.js @@ -43,7 +43,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRestAssignment.js b/tests/baselines/reference/objectRestAssignment.js index 66ee00f669635..cbdff663c2676 100644 --- a/tests/baselines/reference/objectRestAssignment.js +++ b/tests/baselines/reference/objectRestAssignment.js @@ -19,7 +19,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRestForOf.js b/tests/baselines/reference/objectRestForOf.js index b4e33550cb05f..fd81f77512e19 100644 --- a/tests/baselines/reference/objectRestForOf.js +++ b/tests/baselines/reference/objectRestForOf.js @@ -27,7 +27,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRestNegative.js b/tests/baselines/reference/objectRestNegative.js index f8c5b72ada5d0..915e0a0e86732 100644 --- a/tests/baselines/reference/objectRestNegative.js +++ b/tests/baselines/reference/objectRestNegative.js @@ -23,7 +23,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/objectRestParameter.js b/tests/baselines/reference/objectRestParameter.js index 87419bd06e909..14e84eddfce79 100644 --- a/tests/baselines/reference/objectRestParameter.js +++ b/tests/baselines/reference/objectRestParameter.js @@ -22,7 +22,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/restIntersectionOrIntersection.js b/tests/baselines/reference/restIntersectionOrIntersection.js index a60a5acbd9328..0697e579ecd40 100644 --- a/tests/baselines/reference/restIntersectionOrIntersection.js +++ b/tests/baselines/reference/restIntersectionOrIntersection.js @@ -16,7 +16,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/restInvalidArgumentType.js b/tests/baselines/reference/restInvalidArgumentType.js index 22a547880eb09..48e4e11e8051d 100644 --- a/tests/baselines/reference/restInvalidArgumentType.js +++ b/tests/baselines/reference/restInvalidArgumentType.js @@ -64,7 +64,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/restUnion.js b/tests/baselines/reference/restUnion.js index beaf514808b1d..09a6243d2a957 100644 --- a/tests/baselines/reference/restUnion.js +++ b/tests/baselines/reference/restUnion.js @@ -20,7 +20,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; diff --git a/tests/baselines/reference/restUnion2.js b/tests/baselines/reference/restUnion2.js index d746698164596..44a0acfbcf825 100644 --- a/tests/baselines/reference/restUnion2.js +++ b/tests/baselines/reference/restUnion2.js @@ -23,7 +23,7 @@ var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; - if (typeof Object.getOwnPropertySymbols === "function") + if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) if (e.indexOf(p[i]) < 0) t[p[i]] = s[p[i]]; return t; From 9ab55c157666c6c5ad72cc6d81f44e3335461816 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 12:27:56 -0800 Subject: [PATCH 06/12] change test --- tests/cases/compiler/restIntersectionOrIntersection.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/cases/compiler/restIntersectionOrIntersection.ts b/tests/cases/compiler/restIntersectionOrIntersection.ts index 6d06ed5ebc263..5fca2dafc3654 100644 --- a/tests/cases/compiler/restIntersectionOrIntersection.ts +++ b/tests/cases/compiler/restIntersectionOrIntersection.ts @@ -1,10 +1,4 @@ var intersection: { x: number, y: number } & { w: string, z: string }; -var union: { a: number, c: boolean } | { a: string, b: string }; - var rest1: { y: number, w: string, z: string }; var {x, ...rest1 } = intersection; - -var rest2: { c: boolean } | { b: string }; -var {a, ...rest2 } = union; - From e4f0a50a7cf9f212d7102756e336472af89d2fa7 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 12:29:40 -0800 Subject: [PATCH 07/12] Update test name --- ...nOrIntersection.js => restIntersection.js} | 13 +------ .../reference/restIntersection.symbols | 19 ++++++++++ .../reference/restIntersection.types | 19 ++++++++++ .../restIntersectionOrIntersection.symbols | 38 ------------------- .../restIntersectionOrIntersection.types | 38 ------------------- ...nOrIntersection.ts => restIntersection.ts} | 0 6 files changed, 40 insertions(+), 87 deletions(-) rename tests/baselines/reference/{restIntersectionOrIntersection.js => restIntersection.js} (67%) create mode 100644 tests/baselines/reference/restIntersection.symbols create mode 100644 tests/baselines/reference/restIntersection.types delete mode 100644 tests/baselines/reference/restIntersectionOrIntersection.symbols delete mode 100644 tests/baselines/reference/restIntersectionOrIntersection.types rename tests/cases/compiler/{restIntersectionOrIntersection.ts => restIntersection.ts} (100%) diff --git a/tests/baselines/reference/restIntersectionOrIntersection.js b/tests/baselines/reference/restIntersection.js similarity index 67% rename from tests/baselines/reference/restIntersectionOrIntersection.js rename to tests/baselines/reference/restIntersection.js index 0697e579ecd40..d1f9aa3094cc4 100644 --- a/tests/baselines/reference/restIntersectionOrIntersection.js +++ b/tests/baselines/reference/restIntersection.js @@ -1,17 +1,11 @@ -//// [restIntersectionOrIntersection.ts] +//// [restIntersection.ts] var intersection: { x: number, y: number } & { w: string, z: string }; -var union: { a: number, c: boolean } | { a: string, b: string }; - var rest1: { y: number, w: string, z: string }; var {x, ...rest1 } = intersection; - -var rest2: { c: boolean } | { b: string }; -var {a, ...rest2 } = union; - -//// [restIntersectionOrIntersection.js] +//// [restIntersection.js] var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) @@ -22,8 +16,5 @@ var __rest = (this && this.__rest) || function (s, e) { return t; }; var intersection; -var union; var rest1; var x = intersection.x, rest1 = __rest(intersection, ["x"]); -var rest2; -var a = union.a, rest2 = __rest(union, ["a"]); diff --git a/tests/baselines/reference/restIntersection.symbols b/tests/baselines/reference/restIntersection.symbols new file mode 100644 index 0000000000000..75f91d243e24e --- /dev/null +++ b/tests/baselines/reference/restIntersection.symbols @@ -0,0 +1,19 @@ +=== tests/cases/compiler/restIntersection.ts === +var intersection: { x: number, y: number } & { w: string, z: string }; +>intersection : Symbol(intersection, Decl(restIntersection.ts, 0, 3)) +>x : Symbol(x, Decl(restIntersection.ts, 0, 19)) +>y : Symbol(y, Decl(restIntersection.ts, 0, 30)) +>w : Symbol(w, Decl(restIntersection.ts, 0, 46)) +>z : Symbol(z, Decl(restIntersection.ts, 0, 57)) + +var rest1: { y: number, w: string, z: string }; +>rest1 : Symbol(rest1, Decl(restIntersection.ts, 2, 3), Decl(restIntersection.ts, 3, 7)) +>y : Symbol(y, Decl(restIntersection.ts, 2, 12)) +>w : Symbol(w, Decl(restIntersection.ts, 2, 23)) +>z : Symbol(z, Decl(restIntersection.ts, 2, 34)) + +var {x, ...rest1 } = intersection; +>x : Symbol(x, Decl(restIntersection.ts, 3, 5)) +>rest1 : Symbol(rest1, Decl(restIntersection.ts, 2, 3), Decl(restIntersection.ts, 3, 7)) +>intersection : Symbol(intersection, Decl(restIntersection.ts, 0, 3)) + diff --git a/tests/baselines/reference/restIntersection.types b/tests/baselines/reference/restIntersection.types new file mode 100644 index 0000000000000..5779349ba2986 --- /dev/null +++ b/tests/baselines/reference/restIntersection.types @@ -0,0 +1,19 @@ +=== tests/cases/compiler/restIntersection.ts === +var intersection: { x: number, y: number } & { w: string, z: string }; +>intersection : { x: number; y: number; } & { w: string; z: string; } +>x : number +>y : number +>w : string +>z : string + +var rest1: { y: number, w: string, z: string }; +>rest1 : { y: number; w: string; z: string; } +>y : number +>w : string +>z : string + +var {x, ...rest1 } = intersection; +>x : number +>rest1 : { y: number; w: string; z: string; } +>intersection : { x: number; y: number; } & { w: string; z: string; } + diff --git a/tests/baselines/reference/restIntersectionOrIntersection.symbols b/tests/baselines/reference/restIntersectionOrIntersection.symbols deleted file mode 100644 index f2eb4f16014f0..0000000000000 --- a/tests/baselines/reference/restIntersectionOrIntersection.symbols +++ /dev/null @@ -1,38 +0,0 @@ -=== tests/cases/compiler/restIntersectionOrIntersection.ts === -var intersection: { x: number, y: number } & { w: string, z: string }; ->intersection : Symbol(intersection, Decl(restIntersectionOrIntersection.ts, 0, 3)) ->x : Symbol(x, Decl(restIntersectionOrIntersection.ts, 0, 19)) ->y : Symbol(y, Decl(restIntersectionOrIntersection.ts, 0, 30)) ->w : Symbol(w, Decl(restIntersectionOrIntersection.ts, 0, 46)) ->z : Symbol(z, Decl(restIntersectionOrIntersection.ts, 0, 57)) - -var union: { a: number, c: boolean } | { a: string, b: string }; ->union : Symbol(union, Decl(restIntersectionOrIntersection.ts, 1, 3)) ->a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 1, 12)) ->c : Symbol(c, Decl(restIntersectionOrIntersection.ts, 1, 23)) ->a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 1, 40)) ->b : Symbol(b, Decl(restIntersectionOrIntersection.ts, 1, 51)) - - -var rest1: { y: number, w: string, z: string }; ->rest1 : Symbol(rest1, Decl(restIntersectionOrIntersection.ts, 4, 3), Decl(restIntersectionOrIntersection.ts, 5, 7)) ->y : Symbol(y, Decl(restIntersectionOrIntersection.ts, 4, 12)) ->w : Symbol(w, Decl(restIntersectionOrIntersection.ts, 4, 23)) ->z : Symbol(z, Decl(restIntersectionOrIntersection.ts, 4, 34)) - -var {x, ...rest1 } = intersection; ->x : Symbol(x, Decl(restIntersectionOrIntersection.ts, 5, 5)) ->rest1 : Symbol(rest1, Decl(restIntersectionOrIntersection.ts, 4, 3), Decl(restIntersectionOrIntersection.ts, 5, 7)) ->intersection : Symbol(intersection, Decl(restIntersectionOrIntersection.ts, 0, 3)) - -var rest2: { c: boolean } | { b: string }; ->rest2 : Symbol(rest2, Decl(restIntersectionOrIntersection.ts, 7, 3), Decl(restIntersectionOrIntersection.ts, 8, 7)) ->c : Symbol(c, Decl(restIntersectionOrIntersection.ts, 7, 12)) ->b : Symbol(b, Decl(restIntersectionOrIntersection.ts, 7, 29)) - -var {a, ...rest2 } = union; ->a : Symbol(a, Decl(restIntersectionOrIntersection.ts, 8, 5)) ->rest2 : Symbol(rest2, Decl(restIntersectionOrIntersection.ts, 7, 3), Decl(restIntersectionOrIntersection.ts, 8, 7)) ->union : Symbol(union, Decl(restIntersectionOrIntersection.ts, 1, 3)) - - diff --git a/tests/baselines/reference/restIntersectionOrIntersection.types b/tests/baselines/reference/restIntersectionOrIntersection.types deleted file mode 100644 index c87769ff3ccdf..0000000000000 --- a/tests/baselines/reference/restIntersectionOrIntersection.types +++ /dev/null @@ -1,38 +0,0 @@ -=== tests/cases/compiler/restIntersectionOrIntersection.ts === -var intersection: { x: number, y: number } & { w: string, z: string }; ->intersection : { x: number; y: number; } & { w: string; z: string; } ->x : number ->y : number ->w : string ->z : string - -var union: { a: number, c: boolean } | { a: string, b: string }; ->union : { a: number; c: boolean; } | { a: string; b: string; } ->a : number ->c : boolean ->a : string ->b : string - - -var rest1: { y: number, w: string, z: string }; ->rest1 : { y: number; w: string; z: string; } ->y : number ->w : string ->z : string - -var {x, ...rest1 } = intersection; ->x : number ->rest1 : { y: number; w: string; z: string; } ->intersection : { x: number; y: number; } & { w: string; z: string; } - -var rest2: { c: boolean } | { b: string }; ->rest2 : { c: boolean; } | { b: string; } ->c : boolean ->b : string - -var {a, ...rest2 } = union; ->a : string | number ->rest2 : { c: boolean; } | { b: string; } ->union : { a: number; c: boolean; } | { a: string; b: string; } - - diff --git a/tests/cases/compiler/restIntersectionOrIntersection.ts b/tests/cases/compiler/restIntersection.ts similarity index 100% rename from tests/cases/compiler/restIntersectionOrIntersection.ts rename to tests/cases/compiler/restIntersection.ts From 17b6645a7090589c0adc6b84243ee7dc1e39fbb2 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 13:37:02 -0800 Subject: [PATCH 08/12] add missing semicolons --- src/compiler/checker.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 8177939fe61d3..936afefce9b85 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -6119,7 +6119,7 @@ namespace ts { return getUnionType(map(types, t => getSpreadType(t, right, isFromObjectLiteral))); } else { - left = emptyObjectType + left = emptyObjectType; } } else if (left.flags & TypeFlags.Nullable) { @@ -6132,7 +6132,7 @@ namespace ts { return getUnionType(map(types, t => getSpreadType(left, t, isFromObjectLiteral))); } else { - right = emptyObjectType + right = emptyObjectType; } } else if (right.flags & TypeFlags.Nullable) { From 51f5ef67525ae68acdbb55f626f3ff81dff76d7a Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 13:37:21 -0800 Subject: [PATCH 09/12] Update test --- .../reference/objectSpreadNegative.errors.txt | 22 +++++++++---------- .../reference/objectSpreadNegative.js | 8 ++----- .../types/spread/objectSpreadNegative.ts | 4 +--- 3 files changed, 13 insertions(+), 21 deletions(-) diff --git a/tests/baselines/reference/objectSpreadNegative.errors.txt b/tests/baselines/reference/objectSpreadNegative.errors.txt index e92b685b9102e..17f07bc06a296 100644 --- a/tests/baselines/reference/objectSpreadNegative.errors.txt +++ b/tests/baselines/reference/objectSpreadNegative.errors.txt @@ -7,15 +7,15 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(25,1): error TS2322 Property 's' is missing in type '{ b: boolean; }'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,36): error TS2300: Duplicate identifier 'b'. tests/cases/conformance/types/spread/objectSpreadNegative.ts(28,53): error TS2300: Duplicate identifier 'b'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(34,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,20): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(39,19): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(44,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(48,12): error TS2339: Property 'b' does not exist on type '{}'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(54,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(58,14): error TS2698: Spread types may only be created from object types. -tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(32,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(33,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(35,20): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(37,19): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(42,1): error TS2349: Cannot invoke an expression whose type lacks a call signature. Type '{}' has no compatible call signatures. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(46,12): error TS2339: Property 'b' does not exist on type '{}'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(52,9): error TS2339: Property 'm' does not exist on type '{ p: number; }'. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(56,14): error TS2698: Spread types may only be created from object types. +tests/cases/conformance/types/spread/objectSpreadNegative.ts(59,14): error TS2698: Spread types may only be created from object types. ==== tests/cases/conformance/types/spread/objectSpreadNegative.ts (15 errors) ==== @@ -64,9 +64,7 @@ tests/cases/conformance/types/spread/objectSpreadNegative.ts(61,14): error TS269 !!! error TS2300: Duplicate identifier 'b'. let duplicatedSpread = { ...o, ...o } - // null, undefined and primitives are not allowed - let spreadNull = { ...null }; - let spreadUndefind = { ...undefined }; + // primitives are not allowed let spreadNum = { ...12 }; ~~~~~ !!! error TS2698: Spread types may only be created from object types. diff --git a/tests/baselines/reference/objectSpreadNegative.js b/tests/baselines/reference/objectSpreadNegative.js index 6287f4559a79b..dff84355370e7 100644 --- a/tests/baselines/reference/objectSpreadNegative.js +++ b/tests/baselines/reference/objectSpreadNegative.js @@ -29,9 +29,7 @@ spread = b; // error, missing 's' let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// null, undefined and primitives are not allowed -let spreadNull = { ...null }; -let spreadUndefind = { ...undefined }; +// primitives are not allowed let spreadNum = { ...12 }; let spreadSum = { ...1 + 1 }; spreadSum.toFixed(); // error, no methods from number @@ -108,9 +106,7 @@ spread = b; // error, missing 's' // literal repeats are not allowed, but spread repeats are fine var duplicated = __assign({ b: 'bad' }, o, { b: 'bad' }, o2, { b: 'bad' }); var duplicatedSpread = __assign({}, o, o); -// null, undefined and primitives are not allowed -var spreadNull = __assign({}, null); -var spreadUndefind = __assign({}, undefined); +// primitives are not allowed var spreadNum = __assign({}, 12); var spreadSum = __assign({}, 1 + 1); spreadSum.toFixed(); // error, no methods from number diff --git a/tests/cases/conformance/types/spread/objectSpreadNegative.ts b/tests/cases/conformance/types/spread/objectSpreadNegative.ts index 3cd819d061350..6d1e0dde42900 100644 --- a/tests/cases/conformance/types/spread/objectSpreadNegative.ts +++ b/tests/cases/conformance/types/spread/objectSpreadNegative.ts @@ -29,9 +29,7 @@ spread = b; // error, missing 's' let duplicated = { b: 'bad', ...o, b: 'bad', ...o2, b: 'bad' } let duplicatedSpread = { ...o, ...o } -// null, undefined and primitives are not allowed -let spreadNull = { ...null }; -let spreadUndefind = { ...undefined }; +// primitives are not allowed let spreadNum = { ...12 }; let spreadSum = { ...1 + 1 }; spreadSum.toFixed(); // error, no methods from number From 2178d5526f7b930a47bac4ef1b0f83d4ceb917bf Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 16:30:27 -0800 Subject: [PATCH 10/12] extract filterNullableTypes --- src/compiler/checker.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 936afefce9b85..c0a487ffa0f08 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3055,7 +3055,7 @@ namespace ts { function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { if (source.flags & TypeFlags.Union) { - const types = filter((source).types, t => !(t.flags & TypeFlags.Nullable)); + const types = filterNulableTypes(source); if (types.length) { return getUnionType(map(types, t => getRestType(t, properties, symbol))); } @@ -6103,6 +6103,10 @@ namespace ts { return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined; } + function filterNulableTypes(union: UnionType): Type[] { + return filter(union.types, t => !(t.flags & TypeFlags.Nullable)); + } + /** * Since the source of spread types are object literals, which are not binary, * this function should be called in a left folding style, with left = previous result of getSpreadType @@ -6114,7 +6118,7 @@ namespace ts { } if (left.flags & TypeFlags.Union) { - const types = filter((left).types, t => !(t.flags & TypeFlags.Nullable)); + const types = filterNulableTypes(left); if (types.length) { return getUnionType(map(types, t => getSpreadType(t, right, isFromObjectLiteral))); } @@ -6127,7 +6131,7 @@ namespace ts { } if (right.flags & TypeFlags.Union) { - const types = filter((right).types, t => !(t.flags & TypeFlags.Nullable)); + const types = filterNulableTypes(right); if (types.length) { return getUnionType(map(types, t => getSpreadType(left, t, isFromObjectLiteral))); } From 21526833252bf6f9137c73b7bb6b4c3256df6d2f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 16:55:50 -0800 Subject: [PATCH 11/12] Simplify logic --- src/compiler/checker.ts | 46 ++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 30 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c0a487ffa0f08..56112fe7e861d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3054,11 +3054,13 @@ namespace ts { } function getRestType(source: Type, properties: PropertyName[], symbol: Symbol): Type { + source = filterType(source, t => !(t.flags & TypeFlags.Nullable)); + if (source.flags & TypeFlags.Never) { + return emptyObjectType; + } + if (source.flags & TypeFlags.Union) { - const types = filterNulableTypes(source); - if (types.length) { - return getUnionType(map(types, t => getRestType(t, properties, symbol))); - } + return mapType(source, t => getRestType(t, properties, symbol)); } const members = createMap(); @@ -6103,10 +6105,6 @@ namespace ts { return symbol ? getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol) : undefined; } - function filterNulableTypes(union: UnionType): Type[] { - return filter(union.types, t => !(t.flags & TypeFlags.Nullable)); - } - /** * Since the source of spread types are object literals, which are not binary, * this function should be called in a left folding style, with left = previous result of getSpreadType @@ -6116,31 +6114,19 @@ namespace ts { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } - - if (left.flags & TypeFlags.Union) { - const types = filterNulableTypes(left); - if (types.length) { - return getUnionType(map(types, t => getSpreadType(t, right, isFromObjectLiteral))); - } - else { - left = emptyObjectType; - } + left = filterType(left, t => !(t.flags & TypeFlags.Nullable)); + if (left.flags & TypeFlags.Never) { + return right; } - else if (left.flags & TypeFlags.Nullable) { - left = emptyObjectType; + right = filterType(right, t => !(t.flags & TypeFlags.Nullable)); + if (right.flags & TypeFlags.Never) { + return left; } - - if (right.flags & TypeFlags.Union) { - const types = filterNulableTypes(right); - if (types.length) { - return getUnionType(map(types, t => getSpreadType(left, t, isFromObjectLiteral))); - } - else { - right = emptyObjectType; - } + if (left.flags & TypeFlags.Union) { + return mapType(left, t => getSpreadType(t, right, isFromObjectLiteral)); } - else if (right.flags & TypeFlags.Nullable) { - right = emptyObjectType; + if (right.flags & TypeFlags.Union) { + return mapType(right, t => getSpreadType(left, t, isFromObjectLiteral)); } const members = createMap(); From 505c153fed9e45905c8e9d61f7a8d6fae3d11c29 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Nov 2016 16:57:37 -0800 Subject: [PATCH 12/12] Simplify isValidSpreadType --- src/compiler/checker.ts | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 56112fe7e861d..7dc1ea577089d 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -11539,21 +11539,9 @@ namespace ts { } function isValidSpreadType(type: Type): boolean { - if (type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined)) { - return true; - } - if (type.flags & TypeFlags.Object) { - return !isGenericMappedType(type); - } - else if (type.flags & TypeFlags.UnionOrIntersection) { - for (const t of (type).types) { - if (!isValidSpreadType(t)) { - return false; - } - } - return true; - } - return false; + return !!(type.flags & (TypeFlags.Any | TypeFlags.Null | TypeFlags.Undefined) || + type.flags & TypeFlags.Object && !isGenericMappedType(type) || + type.flags & TypeFlags.UnionOrIntersection && !forEach((type).types, t => !isValidSpreadType(t))); } function checkJsxSelfClosingElement(node: JsxSelfClosingElement) {