From ebe2fdb4c831bbd43a7873e869f072aff6dcaaaf Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Fri, 25 Nov 2016 18:54:01 +0800 Subject: [PATCH 01/10] Fix #1809, introduce non primitive type --- src/compiler/binder.ts | 2 ++ src/compiler/checker.ts | 13 +++++++++++++ src/compiler/scanner.ts | 1 + src/compiler/types.ts | 3 +++ 4 files changed, 19 insertions(+) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index a6f5993f6c8..4b7d1d7b274 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -3145,6 +3145,7 @@ namespace ts { case SyntaxKind.AnyKeyword: case SyntaxKind.NumberKeyword: case SyntaxKind.NeverKeyword: + case SyntaxKind.ObjectKeyword: case SyntaxKind.StringKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: @@ -3343,6 +3344,7 @@ namespace ts { case SyntaxKind.NumberKeyword: case SyntaxKind.NeverKeyword: case SyntaxKind.StringKeyword: + case SyntaxKind.ObjectKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: case SyntaxKind.VoidKeyword: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a27e8ba524d..39832dfcb35 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -146,6 +146,7 @@ namespace ts { const silentNeverType = createIntrinsicType(TypeFlags.Never, "never"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); + const nonPrimitiveType = createNonPrimitiveType(); const emptyTypeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral | SymbolFlags.Transient, "__type"); emptyTypeLiteralSymbol.members = createMap(); @@ -1684,6 +1685,14 @@ namespace ts { return type; } + function createNonPrimitiveType(): NonPrimitiveType { + const type = setStructuredTypeMembers( + createObjectType(ObjectFlags.NonPrimitive, undefined), + emptySymbols, emptyArray, emptyArray, undefined, undefined); + type.intrinsicName = "object"; + return type; + } + function createObjectType(objectFlags: ObjectFlags, symbol?: Symbol): ObjectType { const type = createType(TypeFlags.Object); type.objectFlags = objectFlags; @@ -4178,6 +4187,7 @@ namespace ts { case SyntaxKind.NumberKeyword: case SyntaxKind.BooleanKeyword: case SyntaxKind.SymbolKeyword: + case SyntaxKind.ObjectKeyword: case SyntaxKind.VoidKeyword: case SyntaxKind.UndefinedKeyword: case SyntaxKind.NullKeyword: @@ -6384,6 +6394,8 @@ namespace ts { return nullType; case SyntaxKind.NeverKeyword: return neverType; + case SyntaxKind.ObjectKeyword: + return nonPrimitiveType; case SyntaxKind.JSDocNullKeyword: return nullType; case SyntaxKind.JSDocUndefinedKeyword: @@ -7139,6 +7151,7 @@ namespace ts { if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(source, target, errorReporter)) return true; if (source.flags & TypeFlags.Undefined && (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void))) return true; if (source.flags & TypeFlags.Null && (!strictNullChecks || target.flags & TypeFlags.Null)) return true; + if (source.flags & TypeFlags.Object && (source).objectFlags & ObjectFlags.NonPrimitive && target.flags & TypeFlags.Primitive) return false; if (relation === assignableRelation || relation === comparableRelation) { if (source.flags & TypeFlags.Any) return true; if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true; diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 82302e98e37..ad8781aecec 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -98,6 +98,7 @@ namespace ts { "new": SyntaxKind.NewKeyword, "null": SyntaxKind.NullKeyword, "number": SyntaxKind.NumberKeyword, + "object": SyntaxKind.ObjectKeyword, "package": SyntaxKind.PackageKeyword, "private": SyntaxKind.PrivateKeyword, "protected": SyntaxKind.ProtectedKeyword, diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1ee59149b2c..db919b56449 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -175,6 +175,7 @@ namespace ts { ReadonlyKeyword, RequireKeyword, NumberKeyword, + ObjectKeyword, SetKeyword, StringKeyword, SymbolKeyword, @@ -816,6 +817,7 @@ namespace ts { export interface KeywordTypeNode extends TypeNode { kind: SyntaxKind.AnyKeyword | SyntaxKind.NumberKeyword + | SyntaxKind.ObjectKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.StringKeyword | SyntaxKind.SymbolKeyword @@ -2857,6 +2859,7 @@ namespace ts { ObjectLiteral = 1 << 7, // Originates in an object literal EvolvingArray = 1 << 8, // Evolving array type ObjectLiteralPatternWithComputedProperties = 1 << 9, // Object literal pattern with computed properties + NonPrimitive = 1 << 10, // NonPrimitive object type ClassOrInterface = Class | Interface } From db9dd387b169475239a22dac398bcc8dc2cf887a Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Fri, 25 Nov 2016 20:20:15 +0800 Subject: [PATCH 02/10] enable parsing --- src/compiler/parser.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 2f0d6a4d975..5bf9ce789c1 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -2507,6 +2507,7 @@ namespace ts { case SyntaxKind.SymbolKeyword: case SyntaxKind.UndefinedKeyword: case SyntaxKind.NeverKeyword: + case SyntaxKind.ObjectKeyword: // If these are followed by a dot, then parse these out as a dotted type reference instead. const node = tryParse(parseKeywordAndNoDot); return node || parseTypeReference(); @@ -2565,6 +2566,7 @@ namespace ts { case SyntaxKind.NumericLiteral: case SyntaxKind.TrueKeyword: case SyntaxKind.FalseKeyword: + case SyntaxKind.ObjectKeyword: return true; case SyntaxKind.MinusToken: return lookAhead(nextTokenIsNumericLiteral); @@ -6026,6 +6028,7 @@ namespace ts { case SyntaxKind.NullKeyword: case SyntaxKind.UndefinedKeyword: case SyntaxKind.NeverKeyword: + case SyntaxKind.ObjectKeyword: return parseTokenNode(); case SyntaxKind.StringLiteral: case SyntaxKind.NumericLiteral: From ce4c95f332975ea5c2fd18e5c17bf4443056b5b1 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Fri, 25 Nov 2016 22:24:31 +0800 Subject: [PATCH 03/10] fix error reporting --- src/compiler/checker.ts | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 39832dfcb35..c863e2fd2c7 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1685,11 +1685,10 @@ namespace ts { return type; } - function createNonPrimitiveType(): NonPrimitiveType { - const type = setStructuredTypeMembers( + function createNonPrimitiveType(): ResolvedType { + const type = setStructuredTypeMembers( createObjectType(ObjectFlags.NonPrimitive, undefined), emptySymbols, emptyArray, emptyArray, undefined, undefined); - type.intrinsicName = "object"; return type; } @@ -2321,6 +2320,9 @@ namespace ts { else if (type.flags & TypeFlags.UnionOrIntersection) { writeUnionOrIntersectionType(type, nextFlags); } + else if (getObjectFlags(type) & ObjectFlags.NonPrimitive) { + writer.writeKeyword("object"); + } else if (getObjectFlags(type) & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) { writeAnonymousType(type, nextFlags); } @@ -3087,6 +3089,10 @@ namespace ts { return type && (type.flags & TypeFlags.Never) !== 0; } + function isTypeNonPrimitive(type: Type) { + return type === nonPrimitiveType; + } + // Return the type of a binding element parent. We check SymbolLinks first to see if a type has been // assigned by contextual typing. function getTypeForBindingElementParent(node: VariableLikeDeclaration) { @@ -7151,7 +7157,6 @@ namespace ts { if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(source, target, errorReporter)) return true; if (source.flags & TypeFlags.Undefined && (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void))) return true; if (source.flags & TypeFlags.Null && (!strictNullChecks || target.flags & TypeFlags.Null)) return true; - if (source.flags & TypeFlags.Object && (source).objectFlags & ObjectFlags.NonPrimitive && target.flags & TypeFlags.Primitive) return false; if (relation === assignableRelation || relation === comparableRelation) { if (source.flags & TypeFlags.Any) return true; if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true; @@ -7470,7 +7475,7 @@ namespace ts { } } } - else { + else if (!(source.flags & TypeFlags.Primitive && isTypeNonPrimitive(target))) { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { // We have type references to same target type, see if relationship holds for all type arguments if (result = typeArgumentsRelatedTo(source, target, reportErrors)) { @@ -18085,6 +18090,7 @@ namespace ts { case "string": case "symbol": case "void": + case "object": error(name, message, (name).text); } } From b8648fa9f63e7fd55e1793a96ab9bfaf4d483451 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Sat, 26 Nov 2016 00:32:55 +0800 Subject: [PATCH 04/10] add tests for non primitive type --- .../reference/assignObjectToNonPrimitive.js | 14 ++++++ .../assignObjectToNonPrimitive.symbols | 19 ++++++++ .../assignObjectToNonPrimitive.types | 24 ++++++++++ .../nonPriimitiveInFunction.errors.txt | 31 +++++++++++++ .../reference/nonPriimitiveInFunction.js | 36 +++++++++++++++ .../nonPrimitiveAsProperty.errors.txt | 18 ++++++++ .../reference/nonPrimitiveAsProperty.js | 13 ++++++ .../nonPrimitiveAssignError.errors.txt | 44 +++++++++++++++++++ .../reference/nonPrimitiveAssignError.js | 35 +++++++++++++++ .../nonPrimitiveInGeneric.errors.txt | 31 +++++++++++++ .../reference/nonPrimitiveInGeneric.js | 31 +++++++++++++ .../nonPrimitiveUnionIntersection.errors.txt | 18 ++++++++ .../nonPrimitiveUnionIntersection.js | 12 +++++ .../reservedNamesInAliases.errors.txt | 9 +++- .../reference/reservedNamesInAliases.js | 4 +- .../assignObjectToNonPrimitive.ts | 5 +++ .../nonPrimitive/nonPriimitiveInFunction.ts | 18 ++++++++ .../nonPrimitive/nonPrimitiveAsProperty.ts | 7 +++ .../nonPrimitive/nonPrimitiveAssignError.ts | 17 +++++++ .../nonPrimitive/nonPrimitiveInGeneric.ts | 15 +++++++ .../nonPrimitiveUnionIntersection.ts | 4 ++ .../typeAliases/reservedNamesInAliases.ts | 3 +- 22 files changed, 404 insertions(+), 4 deletions(-) create mode 100644 tests/baselines/reference/assignObjectToNonPrimitive.js create mode 100644 tests/baselines/reference/assignObjectToNonPrimitive.symbols create mode 100644 tests/baselines/reference/assignObjectToNonPrimitive.types create mode 100644 tests/baselines/reference/nonPriimitiveInFunction.errors.txt create mode 100644 tests/baselines/reference/nonPriimitiveInFunction.js create mode 100644 tests/baselines/reference/nonPrimitiveAsProperty.errors.txt create mode 100644 tests/baselines/reference/nonPrimitiveAsProperty.js create mode 100644 tests/baselines/reference/nonPrimitiveAssignError.errors.txt create mode 100644 tests/baselines/reference/nonPrimitiveAssignError.js create mode 100644 tests/baselines/reference/nonPrimitiveInGeneric.errors.txt create mode 100644 tests/baselines/reference/nonPrimitiveInGeneric.js create mode 100644 tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt create mode 100644 tests/baselines/reference/nonPrimitiveUnionIntersection.js create mode 100644 tests/cases/conformance/types/nonPrimitive/assignObjectToNonPrimitive.ts create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPrimitiveAsProperty.ts create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts diff --git a/tests/baselines/reference/assignObjectToNonPrimitive.js b/tests/baselines/reference/assignObjectToNonPrimitive.js new file mode 100644 index 00000000000..ec0015fba8a --- /dev/null +++ b/tests/baselines/reference/assignObjectToNonPrimitive.js @@ -0,0 +1,14 @@ +//// [assignObjectToNonPrimitive.ts] +var x = {}; +var y = {foo: "bar"}; +var a: object; +a = x; +a = y; + + +//// [assignObjectToNonPrimitive.js] +var x = {}; +var y = { foo: "bar" }; +var a; +a = x; +a = y; diff --git a/tests/baselines/reference/assignObjectToNonPrimitive.symbols b/tests/baselines/reference/assignObjectToNonPrimitive.symbols new file mode 100644 index 00000000000..5c806e09b94 --- /dev/null +++ b/tests/baselines/reference/assignObjectToNonPrimitive.symbols @@ -0,0 +1,19 @@ +=== tests/cases/conformance/types/nonPrimitive/assignObjectToNonPrimitive.ts === +var x = {}; +>x : Symbol(x, Decl(assignObjectToNonPrimitive.ts, 0, 3)) + +var y = {foo: "bar"}; +>y : Symbol(y, Decl(assignObjectToNonPrimitive.ts, 1, 3)) +>foo : Symbol(foo, Decl(assignObjectToNonPrimitive.ts, 1, 9)) + +var a: object; +>a : Symbol(a, Decl(assignObjectToNonPrimitive.ts, 2, 3)) + +a = x; +>a : Symbol(a, Decl(assignObjectToNonPrimitive.ts, 2, 3)) +>x : Symbol(x, Decl(assignObjectToNonPrimitive.ts, 0, 3)) + +a = y; +>a : Symbol(a, Decl(assignObjectToNonPrimitive.ts, 2, 3)) +>y : Symbol(y, Decl(assignObjectToNonPrimitive.ts, 1, 3)) + diff --git a/tests/baselines/reference/assignObjectToNonPrimitive.types b/tests/baselines/reference/assignObjectToNonPrimitive.types new file mode 100644 index 00000000000..f16c2287155 --- /dev/null +++ b/tests/baselines/reference/assignObjectToNonPrimitive.types @@ -0,0 +1,24 @@ +=== tests/cases/conformance/types/nonPrimitive/assignObjectToNonPrimitive.ts === +var x = {}; +>x : {} +>{} : {} + +var y = {foo: "bar"}; +>y : { foo: string; } +>{foo: "bar"} : { foo: string; } +>foo : string +>"bar" : "bar" + +var a: object; +>a : object + +a = x; +>a = x : {} +>a : object +>x : {} + +a = y; +>a = y : { foo: string; } +>a : object +>y : { foo: string; } + diff --git a/tests/baselines/reference/nonPriimitiveInFunction.errors.txt b/tests/baselines/reference/nonPriimitiveInFunction.errors.txt new file mode 100644 index 00000000000..4b244cfcd04 --- /dev/null +++ b/tests/baselines/reference/nonPriimitiveInFunction.errors.txt @@ -0,0 +1,31 @@ +tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts(12,12): error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts(13,1): error TS2322: Type 'object' is not assignable to type 'boolean'. +tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts(17,12): error TS2322: Type 'number' is not assignable to type 'object'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts (3 errors) ==== + function takeObject(o: object) {} + function returnObject(): object { + return {}; + } + + var nonPrimitive: object; + var primitive: boolean; + + takeObject(nonPrimitive); + nonPrimitive = returnObject(); + + takeObject(primitive); // expect error + ~~~~~~~~~ +!!! error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'object'. + primitive = returnObject(); // expect error + ~~~~~~~~~ +!!! error TS2322: Type 'object' is not assignable to type 'boolean'. + + function returnError(): object { + var ret = 123; + return ret; // expect error + ~~~ +!!! error TS2322: Type 'number' is not assignable to type 'object'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/nonPriimitiveInFunction.js b/tests/baselines/reference/nonPriimitiveInFunction.js new file mode 100644 index 00000000000..a534ea7c84e --- /dev/null +++ b/tests/baselines/reference/nonPriimitiveInFunction.js @@ -0,0 +1,36 @@ +//// [nonPriimitiveInFunction.ts] +function takeObject(o: object) {} +function returnObject(): object { + return {}; +} + +var nonPrimitive: object; +var primitive: boolean; + +takeObject(nonPrimitive); +nonPrimitive = returnObject(); + +takeObject(primitive); // expect error +primitive = returnObject(); // expect error + +function returnError(): object { + var ret = 123; + return ret; // expect error +} + + +//// [nonPriimitiveInFunction.js] +function takeObject(o) { } +function returnObject() { + return {}; +} +var nonPrimitive; +var primitive; +takeObject(nonPrimitive); +nonPrimitive = returnObject(); +takeObject(primitive); // expect error +primitive = returnObject(); // expect error +function returnError() { + var ret = 123; + return ret; // expect error +} diff --git a/tests/baselines/reference/nonPrimitiveAsProperty.errors.txt b/tests/baselines/reference/nonPrimitiveAsProperty.errors.txt new file mode 100644 index 00000000000..8d4042c92f0 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAsProperty.errors.txt @@ -0,0 +1,18 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAsProperty.ts(7,5): error TS2322: Type '{ foo: string; }' is not assignable to type 'WithNonPrimitive'. + Types of property 'foo' are incompatible. + Type 'string' is not assignable to type 'object'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAsProperty.ts (1 errors) ==== + interface WithNonPrimitive { + foo: object + } + + var a: WithNonPrimitive = { foo: {bar: "bar"} }; + + var b: WithNonPrimitive = {foo: "bar"}; // expect error + ~ +!!! error TS2322: Type '{ foo: string; }' is not assignable to type 'WithNonPrimitive'. +!!! error TS2322: Types of property 'foo' are incompatible. +!!! error TS2322: Type 'string' is not assignable to type 'object'. + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveAsProperty.js b/tests/baselines/reference/nonPrimitiveAsProperty.js new file mode 100644 index 00000000000..f51a9b35435 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAsProperty.js @@ -0,0 +1,13 @@ +//// [nonPrimitiveAsProperty.ts] +interface WithNonPrimitive { + foo: object +} + +var a: WithNonPrimitive = { foo: {bar: "bar"} }; + +var b: WithNonPrimitive = {foo: "bar"}; // expect error + + +//// [nonPrimitiveAsProperty.js] +var a = { foo: { bar: "bar" } }; +var b = { foo: "bar" }; // expect error diff --git a/tests/baselines/reference/nonPrimitiveAssignError.errors.txt b/tests/baselines/reference/nonPrimitiveAssignError.errors.txt new file mode 100644 index 00000000000..4fdd4649824 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAssignError.errors.txt @@ -0,0 +1,44 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(5,1): error TS2322: Type 'object' is not assignable to type '{ foo: string; }'. + Property 'foo' is missing in type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(11,1): error TS2322: Type 'number' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(12,1): error TS2322: Type 'true' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(13,1): error TS2322: Type 'string' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(15,1): error TS2322: Type 'object' is not assignable to type 'number'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(16,1): error TS2322: Type 'object' is not assignable to type 'boolean'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(17,1): error TS2322: Type 'object' is not assignable to type 'string'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts (7 errors) ==== + var x = {}; + var y = {foo: "bar"}; + var a: object; + x = a; + y = a; // expect error + ~ +!!! error TS2322: Type 'object' is not assignable to type '{ foo: string; }'. +!!! error TS2322: Property 'foo' is missing in type 'object'. + + var n = 123; + var b = true; + var s = "fooo"; + + a = n; // expect error + ~ +!!! error TS2322: Type 'number' is not assignable to type 'object'. + a = b; // expect error + ~ +!!! error TS2322: Type 'true' is not assignable to type 'object'. + a = s; // expect error + ~ +!!! error TS2322: Type 'string' is not assignable to type 'object'. + + n = a; // expect error + ~ +!!! error TS2322: Type 'object' is not assignable to type 'number'. + b = a; // expect error + ~ +!!! error TS2322: Type 'object' is not assignable to type 'boolean'. + s = a; // expect error + ~ +!!! error TS2322: Type 'object' is not assignable to type 'string'. + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveAssignError.js b/tests/baselines/reference/nonPrimitiveAssignError.js new file mode 100644 index 00000000000..67f21bcf178 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAssignError.js @@ -0,0 +1,35 @@ +//// [nonPrimitiveAssignError.ts] +var x = {}; +var y = {foo: "bar"}; +var a: object; +x = a; +y = a; // expect error + +var n = 123; +var b = true; +var s = "fooo"; + +a = n; // expect error +a = b; // expect error +a = s; // expect error + +n = a; // expect error +b = a; // expect error +s = a; // expect error + + +//// [nonPrimitiveAssignError.js] +var x = {}; +var y = { foo: "bar" }; +var a; +x = a; +y = a; // expect error +var n = 123; +var b = true; +var s = "fooo"; +a = n; // expect error +a = b; // expect error +a = s; // expect error +n = a; // expect error +b = a; // expect error +s = a; // expect error diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt b/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt new file mode 100644 index 00000000000..db359cd43af --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt @@ -0,0 +1,31 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(7,17): error TS2345: Argument of type '123' is not assignable to parameter of type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(8,17): error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(14,7): error TS2345: Argument of type '123' is not assignable to parameter of type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(15,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts (4 errors) ==== + function generic(t: T) {} + var a = {}; + var b = "42"; + + generic({}); + generic(a); + generic(123); // expect error + ~~~ +!!! error TS2345: Argument of type '123' is not assignable to parameter of type 'object'. + generic(b); // expect error + ~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. + + function bound(t: T) {} + + bound({}); + bound(a); + bound(123); // expect error + ~~~ +!!! error TS2345: Argument of type '123' is not assignable to parameter of type 'object'. + bound(b); // expect error + ~ +!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.js b/tests/baselines/reference/nonPrimitiveInGeneric.js new file mode 100644 index 00000000000..82439509234 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveInGeneric.js @@ -0,0 +1,31 @@ +//// [nonPrimitiveInGeneric.ts] +function generic(t: T) {} +var a = {}; +var b = "42"; + +generic({}); +generic(a); +generic(123); // expect error +generic(b); // expect error + +function bound(t: T) {} + +bound({}); +bound(a); +bound(123); // expect error +bound(b); // expect error + + +//// [nonPrimitiveInGeneric.js] +function generic(t) { } +var a = {}; +var b = "42"; +generic({}); +generic(a); +generic(123); // expect error +generic(b); // expect error +function bound(t) { } +bound({}); +bound(a); +bound(123); // expect error +bound(b); // expect error diff --git a/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt b/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt new file mode 100644 index 00000000000..5fb1e89c2e3 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt @@ -0,0 +1,18 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(1,5): error TS2322: Type '""' is not assignable to type 'object & string'. + Type '""' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(3,1): error TS2322: Type 'string' is not assignable to type 'object & string'. + Type 'string' is not assignable to type 'object'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts (2 errors) ==== + var a: object & string = ""; // error + ~ +!!! error TS2322: Type '""' is not assignable to type 'object & string'. +!!! error TS2322: Type '""' is not assignable to type 'object'. + var b: object | string = ""; // ok + a = b; // error + ~ +!!! error TS2322: Type 'string' is not assignable to type 'object & string'. +!!! error TS2322: Type 'string' is not assignable to type 'object'. + b = a; // ok + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveUnionIntersection.js b/tests/baselines/reference/nonPrimitiveUnionIntersection.js new file mode 100644 index 00000000000..c50a2330018 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveUnionIntersection.js @@ -0,0 +1,12 @@ +//// [nonPrimitiveUnionIntersection.ts] +var a: object & string = ""; // error +var b: object | string = ""; // ok +a = b; // error +b = a; // ok + + +//// [nonPrimitiveUnionIntersection.js] +var a = ""; // error +var b = ""; // ok +a = b; // error +b = a; // ok diff --git a/tests/baselines/reference/reservedNamesInAliases.errors.txt b/tests/baselines/reference/reservedNamesInAliases.errors.txt index b6565427395..22894f8f6a6 100644 --- a/tests/baselines/reference/reservedNamesInAliases.errors.txt +++ b/tests/baselines/reference/reservedNamesInAliases.errors.txt @@ -6,9 +6,10 @@ tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,1): error tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,6): error TS1005: ';' expected. tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,11): error TS1109: Expression expected. tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,13): error TS2693: 'I' only refers to a type, but is being used as a value here. +tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(7,6): error TS2457: Type alias name cannot be 'object' -==== tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts (8 errors) ==== +==== tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts (9 errors) ==== interface I {} type any = I; ~~~ @@ -30,4 +31,8 @@ tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts(6,13): error ~ !!! error TS1109: Expression expected. ~ -!!! error TS2693: 'I' only refers to a type, but is being used as a value here. \ No newline at end of file +!!! error TS2693: 'I' only refers to a type, but is being used as a value here. + type object = I; + ~~~~~~ +!!! error TS2457: Type alias name cannot be 'object' + \ No newline at end of file diff --git a/tests/baselines/reference/reservedNamesInAliases.js b/tests/baselines/reference/reservedNamesInAliases.js index 4ebc3bdb95f..368331d3114 100644 --- a/tests/baselines/reference/reservedNamesInAliases.js +++ b/tests/baselines/reference/reservedNamesInAliases.js @@ -4,7 +4,9 @@ type any = I; type number = I; type boolean = I; type string = I; -type void = I; +type void = I; +type object = I; + //// [reservedNamesInAliases.js] type; diff --git a/tests/cases/conformance/types/nonPrimitive/assignObjectToNonPrimitive.ts b/tests/cases/conformance/types/nonPrimitive/assignObjectToNonPrimitive.ts new file mode 100644 index 00000000000..e9dcb5671c5 --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/assignObjectToNonPrimitive.ts @@ -0,0 +1,5 @@ +var x = {}; +var y = {foo: "bar"}; +var a: object; +a = x; +a = y; diff --git a/tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts b/tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts new file mode 100644 index 00000000000..c38693dbfb1 --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts @@ -0,0 +1,18 @@ +function takeObject(o: object) {} +function returnObject(): object { + return {}; +} + +var nonPrimitive: object; +var primitive: boolean; + +takeObject(nonPrimitive); +nonPrimitive = returnObject(); + +takeObject(primitive); // expect error +primitive = returnObject(); // expect error + +function returnError(): object { + var ret = 123; + return ret; // expect error +} diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAsProperty.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAsProperty.ts new file mode 100644 index 00000000000..ee4011ecf7d --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAsProperty.ts @@ -0,0 +1,7 @@ +interface WithNonPrimitive { + foo: object +} + +var a: WithNonPrimitive = { foo: {bar: "bar"} }; + +var b: WithNonPrimitive = {foo: "bar"}; // expect error diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts new file mode 100644 index 00000000000..f177b5cd255 --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts @@ -0,0 +1,17 @@ +var x = {}; +var y = {foo: "bar"}; +var a: object; +x = a; +y = a; // expect error + +var n = 123; +var b = true; +var s = "fooo"; + +a = n; // expect error +a = b; // expect error +a = s; // expect error + +n = a; // expect error +b = a; // expect error +s = a; // expect error diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts new file mode 100644 index 00000000000..0e7914ab715 --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts @@ -0,0 +1,15 @@ +function generic(t: T) {} +var a = {}; +var b = "42"; + +generic({}); +generic(a); +generic(123); // expect error +generic(b); // expect error + +function bound(t: T) {} + +bound({}); +bound(a); +bound(123); // expect error +bound(b); // expect error diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts new file mode 100644 index 00000000000..c1667c7a32e --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts @@ -0,0 +1,4 @@ +var a: object & string = ""; // error +var b: object | string = ""; // ok +a = b; // error +b = a; // ok diff --git a/tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts b/tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts index 3b115573830..f2c6476bd8e 100644 --- a/tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts +++ b/tests/cases/conformance/types/typeAliases/reservedNamesInAliases.ts @@ -3,4 +3,5 @@ type any = I; type number = I; type boolean = I; type string = I; -type void = I; \ No newline at end of file +type void = I; +type object = I; From 2fb51e71125a9100c69c8673f3adb65ecbb5be81 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Sat, 26 Nov 2016 12:49:55 +0800 Subject: [PATCH 05/10] address code review feedback --- src/compiler/checker.ts | 6 +-- .../nonPrimitiveAccessProperty.ts | 3 ++ .../nonPrimitive/nonPrimitiveAssignError.ts | 8 ++++ .../nonPrimitive/nonPrimitiveInGeneric.ts | 7 +++ .../types/nonPrimitive/nonPrimitiveNarrow.ts | 22 +++++++++ .../nonPrimitive/nonPrimitiveStrictNull.ts | 48 +++++++++++++++++++ 6 files changed, 89 insertions(+), 5 deletions(-) create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts create mode 100644 tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c863e2fd2c7..a1fae5ebbd3 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -3089,10 +3089,6 @@ namespace ts { return type && (type.flags & TypeFlags.Never) !== 0; } - function isTypeNonPrimitive(type: Type) { - return type === nonPrimitiveType; - } - // Return the type of a binding element parent. We check SymbolLinks first to see if a type has been // assigned by contextual typing. function getTypeForBindingElementParent(node: VariableLikeDeclaration) { @@ -7475,7 +7471,7 @@ namespace ts { } } } - else if (!(source.flags & TypeFlags.Primitive && isTypeNonPrimitive(target))) { + else if (!(source.flags & TypeFlags.Primitive && target === nonPrimitiveType)) { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { // We have type references to same target type, see if relationship holds for all type arguments if (result = typeArgumentsRelatedTo(source, target, reportErrors)) { diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts new file mode 100644 index 00000000000..2febbb1e2ca --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts @@ -0,0 +1,3 @@ +var a: object; +a.toString(); +a.nonExist(); // error diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts index f177b5cd255..8fe8c8a3ebb 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts @@ -15,3 +15,11 @@ a = s; // expect error n = a; // expect error b = a; // expect error s = a; // expect error + +var numObj: Number = 123; +var boolObj: Boolean = true; +var strObj: String = "string"; + +a = numObj; // ok +a = boolObj; // ok +a = strObj; // ok diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts index 0e7914ab715..0de4771a5ef 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts @@ -13,3 +13,10 @@ bound({}); bound(a); bound(123); // expect error bound(b); // expect error + +function bound2() {} + +bound2<{}>(); +bound2(); +bound2(); // expect error +bound2(); // expect error diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts new file mode 100644 index 00000000000..04f7351290e --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts @@ -0,0 +1,22 @@ +class Narrow { + narrowed: boolean +} + +var a: object + +if (a instanceof Narrow) { + a.narrowed; // ok + a = 123; // error +} + +if (typeof a === 'number') { + a.toFixed(); // error, never +} + +var b: object | null + +if (typeof b === 'object') { + b.toString(); // error, object | null +} else { + b.toString(); // error, never +} diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts new file mode 100644 index 00000000000..5fbf85dc01b --- /dev/null +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts @@ -0,0 +1,48 @@ +// @strictNullChecks: true + +var a: object +declare var b: object | null +declare var c: object | undefined +declare var d: object | null | undefined +var e: object | null +a.toString; // error +a = undefined; // error +a = null; // error +a = b; // error +a = c; // error +a = d; // error + +e = a; // ok +a = e; // ok + +if (typeof b !== 'object') { + b.toString(); // error, never +} + +if (typeof b === 'object') { + a = b; // error, b is not narrowed +} + +if (typeof d === 'object') { + b = d; // ok +} else { + d; // undefined +} + +if (d == null) { + d; // null | undefined +} else { + d.toString(); // object +} + +if (d === null) { + d; // null +} else { + d.toString(); // error, object | undefined +} + +if (typeof d === 'undefined') { + d; // undefined +} else { + d.toString(); // error, object | null +} From c19221cb3e90dc8064a240731ca77e05d3eb5fae Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Sat, 26 Nov 2016 13:09:20 +0800 Subject: [PATCH 06/10] accept new baselines --- .../nonPrimitiveAccessProperty.errors.txt | 10 ++ .../reference/nonPrimitiveAccessProperty.js | 10 ++ .../nonPrimitiveAssignError.errors.txt | 8 ++ .../reference/nonPrimitiveAssignError.js | 14 +++ .../nonPrimitiveInGeneric.errors.txt | 15 ++- .../reference/nonPrimitiveInGeneric.js | 12 ++ .../reference/nonPrimitiveNarrow.errors.txt | 35 ++++++ .../baselines/reference/nonPrimitiveNarrow.js | 46 +++++++ .../nonPrimitiveStrictNull.errors.txt | 117 ++++++++++++++++++ .../reference/nonPrimitiveStrictNull.js | 93 ++++++++++++++ .../types/nonPrimitive/nonPrimitiveNarrow.ts | 2 +- .../nonPrimitive/nonPrimitiveStrictNull.ts | 9 +- 12 files changed, 365 insertions(+), 6 deletions(-) create mode 100644 tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt create mode 100644 tests/baselines/reference/nonPrimitiveAccessProperty.js create mode 100644 tests/baselines/reference/nonPrimitiveNarrow.errors.txt create mode 100644 tests/baselines/reference/nonPrimitiveNarrow.js create mode 100644 tests/baselines/reference/nonPrimitiveStrictNull.errors.txt create mode 100644 tests/baselines/reference/nonPrimitiveStrictNull.js diff --git a/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt b/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt new file mode 100644 index 00000000000..8ef94c64448 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAccessProperty.errors.txt @@ -0,0 +1,10 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts(3,3): error TS2339: Property 'nonExist' does not exist on type 'object'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAccessProperty.ts (1 errors) ==== + var a: object; + a.toString(); + a.nonExist(); // error + ~~~~~~~~ +!!! error TS2339: Property 'nonExist' does not exist on type 'object'. + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveAccessProperty.js b/tests/baselines/reference/nonPrimitiveAccessProperty.js new file mode 100644 index 00000000000..a71b2aba865 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveAccessProperty.js @@ -0,0 +1,10 @@ +//// [nonPrimitiveAccessProperty.ts] +var a: object; +a.toString(); +a.nonExist(); // error + + +//// [nonPrimitiveAccessProperty.js] +var a; +a.toString(); +a.nonExist(); // error diff --git a/tests/baselines/reference/nonPrimitiveAssignError.errors.txt b/tests/baselines/reference/nonPrimitiveAssignError.errors.txt index 4fdd4649824..093445570fe 100644 --- a/tests/baselines/reference/nonPrimitiveAssignError.errors.txt +++ b/tests/baselines/reference/nonPrimitiveAssignError.errors.txt @@ -41,4 +41,12 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(17,1): err s = a; // expect error ~ !!! error TS2322: Type 'object' is not assignable to type 'string'. + + var numObj: Number = 123; + var boolObj: Boolean = true; + var strObj: String = "string"; + + a = numObj; // ok + a = boolObj; // ok + a = strObj; // ok \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveAssignError.js b/tests/baselines/reference/nonPrimitiveAssignError.js index 67f21bcf178..e7bb56746ca 100644 --- a/tests/baselines/reference/nonPrimitiveAssignError.js +++ b/tests/baselines/reference/nonPrimitiveAssignError.js @@ -16,6 +16,14 @@ a = s; // expect error n = a; // expect error b = a; // expect error s = a; // expect error + +var numObj: Number = 123; +var boolObj: Boolean = true; +var strObj: String = "string"; + +a = numObj; // ok +a = boolObj; // ok +a = strObj; // ok //// [nonPrimitiveAssignError.js] @@ -33,3 +41,9 @@ a = s; // expect error n = a; // expect error b = a; // expect error s = a; // expect error +var numObj = 123; +var boolObj = true; +var strObj = "string"; +a = numObj; // ok +a = boolObj; // ok +a = strObj; // ok diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt b/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt index db359cd43af..ab8786c37bc 100644 --- a/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt +++ b/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt @@ -2,9 +2,11 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(7,17): error tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(8,17): error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(14,7): error TS2345: Argument of type '123' is not assignable to parameter of type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(15,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(21,8): error TS2344: Type 'number' does not satisfy the constraint 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(22,8): error TS2344: Type 'string' does not satisfy the constraint 'object'. -==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts (4 errors) ==== +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts (6 errors) ==== function generic(t: T) {} var a = {}; var b = "42"; @@ -28,4 +30,15 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(15,7): error bound(b); // expect error ~ !!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. + + function bound2() {} + + bound2<{}>(); + bound2(); + bound2(); // expect error + ~~~~~~ +!!! error TS2344: Type 'number' does not satisfy the constraint 'object'. + bound2(); // expect error + ~~~~~~ +!!! error TS2344: Type 'string' does not satisfy the constraint 'object'. \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.js b/tests/baselines/reference/nonPrimitiveInGeneric.js index 82439509234..c2e19dde1e4 100644 --- a/tests/baselines/reference/nonPrimitiveInGeneric.js +++ b/tests/baselines/reference/nonPrimitiveInGeneric.js @@ -14,6 +14,13 @@ bound({}); bound(a); bound(123); // expect error bound(b); // expect error + +function bound2() {} + +bound2<{}>(); +bound2(); +bound2(); // expect error +bound2(); // expect error //// [nonPrimitiveInGeneric.js] @@ -29,3 +36,8 @@ bound({}); bound(a); bound(123); // expect error bound(b); // expect error +function bound2() { } +bound2(); +bound2(); +bound2(); // expect error +bound2(); // expect error diff --git a/tests/baselines/reference/nonPrimitiveNarrow.errors.txt b/tests/baselines/reference/nonPrimitiveNarrow.errors.txt new file mode 100644 index 00000000000..1b3cf55b4b2 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveNarrow.errors.txt @@ -0,0 +1,35 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts(9,5): error TS2322: Type '123' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts(13,7): error TS2339: Property 'toFixed' does not exist on type 'never'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts(21,6): error TS2339: Property 'toString' does not exist on type 'never'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts (3 errors) ==== + class Narrow { + narrowed: boolean + } + + var a: object + + if (a instanceof Narrow) { + a.narrowed; // ok + a = 123; // error + ~ +!!! error TS2322: Type '123' is not assignable to type 'object'. + } + + if (typeof a === 'number') { + a.toFixed(); // error, never + ~~~~~~~ +!!! error TS2339: Property 'toFixed' does not exist on type 'never'. + } + + var b: object | null + + if (typeof b === 'object') { + b.toString(); // ok, object | null + } else { + b.toString(); // error, never + ~~~~~~~~ +!!! error TS2339: Property 'toString' does not exist on type 'never'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveNarrow.js b/tests/baselines/reference/nonPrimitiveNarrow.js new file mode 100644 index 00000000000..607206eecfc --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveNarrow.js @@ -0,0 +1,46 @@ +//// [nonPrimitiveNarrow.ts] +class Narrow { + narrowed: boolean +} + +var a: object + +if (a instanceof Narrow) { + a.narrowed; // ok + a = 123; // error +} + +if (typeof a === 'number') { + a.toFixed(); // error, never +} + +var b: object | null + +if (typeof b === 'object') { + b.toString(); // ok, object | null +} else { + b.toString(); // error, never +} + + +//// [nonPrimitiveNarrow.js] +var Narrow = (function () { + function Narrow() { + } + return Narrow; +}()); +var a; +if (a instanceof Narrow) { + a.narrowed; // ok + a = 123; // error +} +if (typeof a === 'number') { + a.toFixed(); // error, never +} +var b; +if (typeof b === 'object') { + b.toString(); // ok, object | null +} +else { + b.toString(); // error, never +} diff --git a/tests/baselines/reference/nonPrimitiveStrictNull.errors.txt b/tests/baselines/reference/nonPrimitiveStrictNull.errors.txt new file mode 100644 index 00000000000..cf09994888b --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveStrictNull.errors.txt @@ -0,0 +1,117 @@ +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(7,1): error TS2454: Variable 'a' is used before being assigned. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(8,1): error TS2322: Type 'undefined' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(9,1): error TS2322: Type 'null' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(10,1): error TS2322: Type 'object | null' is not assignable to type 'object'. + Type 'null' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(11,1): error TS2322: Type 'object | undefined' is not assignable to type 'object'. + Type 'undefined' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(12,1): error TS2322: Type 'object | null | undefined' is not assignable to type 'object'. + Type 'undefined' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(18,7): error TS2339: Property 'toString' does not exist on type 'never'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(22,5): error TS2322: Type 'object | null' is not assignable to type 'object'. + Type 'null' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(27,5): error TS2531: Object is possibly 'null'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(29,5): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(29,7): error TS2339: Property 'toString' does not exist on type 'never'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(33,5): error TS2533: Object is possibly 'null' or 'undefined'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(33,7): error TS2339: Property 'toString' does not exist on type 'never'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(39,5): error TS2531: Object is possibly 'null'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(39,7): error TS2339: Property 'toString' does not exist on type 'never'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(41,5): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(45,5): error TS2532: Object is possibly 'undefined'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(45,7): error TS2339: Property 'toString' does not exist on type 'never'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(47,5): error TS2531: Object is possibly 'null'. + + +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts (19 errors) ==== + + var a: object + declare var b: object | null + declare var c: object | undefined + declare var d: object | null | undefined + var e: object | null + a.toString; // error + ~ +!!! error TS2454: Variable 'a' is used before being assigned. + a = undefined; // error + ~ +!!! error TS2322: Type 'undefined' is not assignable to type 'object'. + a = null; // error + ~ +!!! error TS2322: Type 'null' is not assignable to type 'object'. + a = b; // error + ~ +!!! error TS2322: Type 'object | null' is not assignable to type 'object'. +!!! error TS2322: Type 'null' is not assignable to type 'object'. + a = c; // error + ~ +!!! error TS2322: Type 'object | undefined' is not assignable to type 'object'. +!!! error TS2322: Type 'undefined' is not assignable to type 'object'. + a = d; // error + ~ +!!! error TS2322: Type 'object | null | undefined' is not assignable to type 'object'. +!!! error TS2322: Type 'undefined' is not assignable to type 'object'. + + e = a; // ok + a = e; // ok + + if (typeof b !== 'object') { + b.toString(); // error, never + ~~~~~~~~ +!!! error TS2339: Property 'toString' does not exist on type 'never'. + } + + if (typeof b === 'object') { + a = b; // error, b is not narrowed + ~ +!!! error TS2322: Type 'object | null' is not assignable to type 'object'. +!!! error TS2322: Type 'null' is not assignable to type 'object'. + } + + if (typeof d === 'object') { + b = d; // ok + d.toString(); // error, object | null + ~ +!!! error TS2531: Object is possibly 'null'. + } else { + d.toString(); // error, undefined + ~ +!!! error TS2532: Object is possibly 'undefined'. + ~~~~~~~~ +!!! error TS2339: Property 'toString' does not exist on type 'never'. + } + + if (d == null) { + d.toString(); // error, undefined | null + ~ +!!! error TS2533: Object is possibly 'null' or 'undefined'. + ~~~~~~~~ +!!! error TS2339: Property 'toString' does not exist on type 'never'. + } else { + d.toString(); // object + } + + if (d === null) { + d.toString(); // error, null + ~ +!!! error TS2531: Object is possibly 'null'. + ~~~~~~~~ +!!! error TS2339: Property 'toString' does not exist on type 'never'. + } else { + d.toString(); // error, object | undefined + ~ +!!! error TS2532: Object is possibly 'undefined'. + } + + if (typeof d === 'undefined') { + d.toString(); // error, undefined + ~ +!!! error TS2532: Object is possibly 'undefined'. + ~~~~~~~~ +!!! error TS2339: Property 'toString' does not exist on type 'never'. + } else { + d.toString(); // error, object | null + ~ +!!! error TS2531: Object is possibly 'null'. + } + \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveStrictNull.js b/tests/baselines/reference/nonPrimitiveStrictNull.js new file mode 100644 index 00000000000..c91097de960 --- /dev/null +++ b/tests/baselines/reference/nonPrimitiveStrictNull.js @@ -0,0 +1,93 @@ +//// [nonPrimitiveStrictNull.ts] + +var a: object +declare var b: object | null +declare var c: object | undefined +declare var d: object | null | undefined +var e: object | null +a.toString; // error +a = undefined; // error +a = null; // error +a = b; // error +a = c; // error +a = d; // error + +e = a; // ok +a = e; // ok + +if (typeof b !== 'object') { + b.toString(); // error, never +} + +if (typeof b === 'object') { + a = b; // error, b is not narrowed +} + +if (typeof d === 'object') { + b = d; // ok + d.toString(); // error, object | null +} else { + d.toString(); // error, undefined +} + +if (d == null) { + d.toString(); // error, undefined | null +} else { + d.toString(); // object +} + +if (d === null) { + d.toString(); // error, null +} else { + d.toString(); // error, object | undefined +} + +if (typeof d === 'undefined') { + d.toString(); // error, undefined +} else { + d.toString(); // error, object | null +} + + +//// [nonPrimitiveStrictNull.js] +var a; +var e; +a.toString; // error +a = undefined; // error +a = null; // error +a = b; // error +a = c; // error +a = d; // error +e = a; // ok +a = e; // ok +if (typeof b !== 'object') { + b.toString(); // error, never +} +if (typeof b === 'object') { + a = b; // error, b is not narrowed +} +if (typeof d === 'object') { + b = d; // ok + d.toString(); // error, object | null +} +else { + d.toString(); // error, undefined +} +if (d == null) { + d.toString(); // error, undefined | null +} +else { + d.toString(); // object +} +if (d === null) { + d.toString(); // error, null +} +else { + d.toString(); // error, object | undefined +} +if (typeof d === 'undefined') { + d.toString(); // error, undefined +} +else { + d.toString(); // error, object | null +} diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts index 04f7351290e..2df691958de 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveNarrow.ts @@ -16,7 +16,7 @@ if (typeof a === 'number') { var b: object | null if (typeof b === 'object') { - b.toString(); // error, object | null + b.toString(); // ok, object | null } else { b.toString(); // error, never } diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts index 5fbf85dc01b..78f2d5ff7ba 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts @@ -25,24 +25,25 @@ if (typeof b === 'object') { if (typeof d === 'object') { b = d; // ok + d.toString(); // error, object | null } else { - d; // undefined + d.toString(); // error, undefined } if (d == null) { - d; // null | undefined + d.toString(); // error, undefined | null } else { d.toString(); // object } if (d === null) { - d; // null + d.toString(); // error, null } else { d.toString(); // error, object | undefined } if (typeof d === 'undefined') { - d; // undefined + d.toString(); // error, undefined } else { d.toString(); // error, object | null } From 186ce38c180ed0670cccd4b60be06ee6b110b533 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Sat, 26 Nov 2016 13:19:04 +0800 Subject: [PATCH 07/10] add tests for generic type argument under strict null checks --- .../nonPrimitiveInGeneric.errors.txt | 18 ++++++++++++++- .../reference/nonPrimitiveInGeneric.js | 17 ++++++++++++++ .../nonPrimitiveStrictNull.errors.txt | 23 ++++++++++++++++++- .../reference/nonPrimitiveStrictNull.js | 16 +++++++++++++ .../nonPrimitive/nonPrimitiveInGeneric.ts | 13 +++++++++++ .../nonPrimitive/nonPrimitiveStrictNull.ts | 12 ++++++++++ 6 files changed, 97 insertions(+), 2 deletions(-) diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt b/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt index ab8786c37bc..04d4ee4a1a7 100644 --- a/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt +++ b/tests/baselines/reference/nonPrimitiveInGeneric.errors.txt @@ -4,9 +4,10 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(14,7): error tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(15,7): error TS2345: Argument of type 'string' is not assignable to parameter of type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(21,8): error TS2344: Type 'number' does not satisfy the constraint 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(22,8): error TS2344: Type 'string' does not satisfy the constraint 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(26,14): error TS2344: Type 'number' does not satisfy the constraint 'object'. -==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts (6 errors) ==== +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts (7 errors) ==== function generic(t: T) {} var a = {}; var b = "42"; @@ -41,4 +42,19 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts(22,8): error bound2(); // expect error ~~~~~~ !!! error TS2344: Type 'string' does not satisfy the constraint 'object'. + + interface Proxy {} + + var x: Proxy; // error + ~~~~~~ +!!! error TS2344: Type 'number' does not satisfy the constraint 'object'. + var y: Proxy; // ok + var z: Proxy ; // ok + + + interface Blah { + foo: number; + } + + var u: Proxy; // ok \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveInGeneric.js b/tests/baselines/reference/nonPrimitiveInGeneric.js index c2e19dde1e4..b7080e149b4 100644 --- a/tests/baselines/reference/nonPrimitiveInGeneric.js +++ b/tests/baselines/reference/nonPrimitiveInGeneric.js @@ -21,6 +21,19 @@ bound2<{}>(); bound2(); bound2(); // expect error bound2(); // expect error + +interface Proxy {} + +var x: Proxy; // error +var y: Proxy; // ok +var z: Proxy ; // ok + + +interface Blah { + foo: number; +} + +var u: Proxy; // ok //// [nonPrimitiveInGeneric.js] @@ -41,3 +54,7 @@ bound2(); bound2(); bound2(); // expect error bound2(); // expect error +var x; // error +var y; // ok +var z; // ok +var u; // ok diff --git a/tests/baselines/reference/nonPrimitiveStrictNull.errors.txt b/tests/baselines/reference/nonPrimitiveStrictNull.errors.txt index cf09994888b..de6fbfcf698 100644 --- a/tests/baselines/reference/nonPrimitiveStrictNull.errors.txt +++ b/tests/baselines/reference/nonPrimitiveStrictNull.errors.txt @@ -21,9 +21,12 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(41,5): erro tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(45,5): error TS2532: Object is possibly 'undefined'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(45,7): error TS2339: Property 'toString' does not exist on type 'never'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(47,5): error TS2531: Object is possibly 'null'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(52,14): error TS2344: Type 'number' does not satisfy the constraint 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(53,14): error TS2344: Type 'null' does not satisfy the constraint 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(54,14): error TS2344: Type 'undefined' does not satisfy the constraint 'object'. -==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts (19 errors) ==== +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts (22 errors) ==== var a: object declare var b: object | null @@ -114,4 +117,22 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts(47,5): erro ~ !!! error TS2531: Object is possibly 'null'. } + + interface Proxy {} + + var x: Proxy; // error + ~~~~~~ +!!! error TS2344: Type 'number' does not satisfy the constraint 'object'. + var y: Proxy; // error + ~~~~ +!!! error TS2344: Type 'null' does not satisfy the constraint 'object'. + var z: Proxy; // error + ~~~~~~~~~ +!!! error TS2344: Type 'undefined' does not satisfy the constraint 'object'. + + interface Blah { + foo: number; + } + + var u: Proxy; // ok \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveStrictNull.js b/tests/baselines/reference/nonPrimitiveStrictNull.js index c91097de960..754ca8cac7d 100644 --- a/tests/baselines/reference/nonPrimitiveStrictNull.js +++ b/tests/baselines/reference/nonPrimitiveStrictNull.js @@ -47,6 +47,18 @@ if (typeof d === 'undefined') { } else { d.toString(); // error, object | null } + +interface Proxy {} + +var x: Proxy; // error +var y: Proxy; // error +var z: Proxy; // error + +interface Blah { + foo: number; +} + +var u: Proxy; // ok //// [nonPrimitiveStrictNull.js] @@ -91,3 +103,7 @@ if (typeof d === 'undefined') { else { d.toString(); // error, object | null } +var x; // error +var y; // error +var z; // error +var u; // ok diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts index 0de4771a5ef..a19271a59d3 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInGeneric.ts @@ -20,3 +20,16 @@ bound2<{}>(); bound2(); bound2(); // expect error bound2(); // expect error + +interface Proxy {} + +var x: Proxy; // error +var y: Proxy; // ok +var z: Proxy ; // ok + + +interface Blah { + foo: number; +} + +var u: Proxy; // ok diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts index 78f2d5ff7ba..3c2b9646c7e 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveStrictNull.ts @@ -47,3 +47,15 @@ if (typeof d === 'undefined') { } else { d.toString(); // error, object | null } + +interface Proxy {} + +var x: Proxy; // error +var y: Proxy; // error +var z: Proxy; // error + +interface Blah { + foo: number; +} + +var u: Proxy; // ok From 8b411effa637c5cd345471da485fa4c37868aec3 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Fri, 16 Dec 2016 10:26:49 +0800 Subject: [PATCH 08/10] address CR feedback --- .../reference/nonPrimitiveAssignError.errors.txt | 14 ++++++++------ .../baselines/reference/nonPrimitiveAssignError.js | 4 ++++ ...rrors.txt => nonPrimitiveInFunction.errors.txt} | 8 ++++---- ...tiveInFunction.js => nonPrimitiveInFunction.js} | 4 ++-- .../types/nonPrimitive/nonPrimitiveAssignError.ts | 2 ++ ...tiveInFunction.ts => nonPrimitiveInFunction.ts} | 0 6 files changed, 20 insertions(+), 12 deletions(-) rename tests/baselines/reference/{nonPriimitiveInFunction.errors.txt => nonPrimitiveInFunction.errors.txt} (56%) rename tests/baselines/reference/{nonPriimitiveInFunction.js => nonPrimitiveInFunction.js} (88%) rename tests/cases/conformance/types/nonPrimitive/{nonPriimitiveInFunction.ts => nonPrimitiveInFunction.ts} (100%) diff --git a/tests/baselines/reference/nonPrimitiveAssignError.errors.txt b/tests/baselines/reference/nonPrimitiveAssignError.errors.txt index 093445570fe..bb62d494d74 100644 --- a/tests/baselines/reference/nonPrimitiveAssignError.errors.txt +++ b/tests/baselines/reference/nonPrimitiveAssignError.errors.txt @@ -1,11 +1,11 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(5,1): error TS2322: Type 'object' is not assignable to type '{ foo: string; }'. Property 'foo' is missing in type 'object'. -tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(11,1): error TS2322: Type 'number' is not assignable to type 'object'. -tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(12,1): error TS2322: Type 'true' is not assignable to type 'object'. -tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(13,1): error TS2322: Type 'string' is not assignable to type 'object'. -tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(15,1): error TS2322: Type 'object' is not assignable to type 'number'. -tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(16,1): error TS2322: Type 'object' is not assignable to type 'boolean'. -tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(17,1): error TS2322: Type 'object' is not assignable to type 'string'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(13,1): error TS2322: Type 'number' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(14,1): error TS2322: Type 'true' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(15,1): error TS2322: Type 'string' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(17,1): error TS2322: Type 'object' is not assignable to type 'number'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(18,1): error TS2322: Type 'object' is not assignable to type 'boolean'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(19,1): error TS2322: Type 'object' is not assignable to type 'string'. ==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts (7 errors) ==== @@ -17,6 +17,8 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(17,1): err ~ !!! error TS2322: Type 'object' is not assignable to type '{ foo: string; }'. !!! error TS2322: Property 'foo' is missing in type 'object'. + a = x; + a = y; var n = 123; var b = true; diff --git a/tests/baselines/reference/nonPrimitiveAssignError.js b/tests/baselines/reference/nonPrimitiveAssignError.js index e7bb56746ca..c37836a91c6 100644 --- a/tests/baselines/reference/nonPrimitiveAssignError.js +++ b/tests/baselines/reference/nonPrimitiveAssignError.js @@ -4,6 +4,8 @@ var y = {foo: "bar"}; var a: object; x = a; y = a; // expect error +a = x; +a = y; var n = 123; var b = true; @@ -32,6 +34,8 @@ var y = { foo: "bar" }; var a; x = a; y = a; // expect error +a = x; +a = y; var n = 123; var b = true; var s = "fooo"; diff --git a/tests/baselines/reference/nonPriimitiveInFunction.errors.txt b/tests/baselines/reference/nonPrimitiveInFunction.errors.txt similarity index 56% rename from tests/baselines/reference/nonPriimitiveInFunction.errors.txt rename to tests/baselines/reference/nonPrimitiveInFunction.errors.txt index 4b244cfcd04..5ca231b61c8 100644 --- a/tests/baselines/reference/nonPriimitiveInFunction.errors.txt +++ b/tests/baselines/reference/nonPrimitiveInFunction.errors.txt @@ -1,9 +1,9 @@ -tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts(12,12): error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'object'. -tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts(13,1): error TS2322: Type 'object' is not assignable to type 'boolean'. -tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts(17,12): error TS2322: Type 'number' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInFunction.ts(12,12): error TS2345: Argument of type 'boolean' is not assignable to parameter of type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInFunction.ts(13,1): error TS2322: Type 'object' is not assignable to type 'boolean'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveInFunction.ts(17,12): error TS2322: Type 'number' is not assignable to type 'object'. -==== tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts (3 errors) ==== +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveInFunction.ts (3 errors) ==== function takeObject(o: object) {} function returnObject(): object { return {}; diff --git a/tests/baselines/reference/nonPriimitiveInFunction.js b/tests/baselines/reference/nonPrimitiveInFunction.js similarity index 88% rename from tests/baselines/reference/nonPriimitiveInFunction.js rename to tests/baselines/reference/nonPrimitiveInFunction.js index a534ea7c84e..a67b68542dd 100644 --- a/tests/baselines/reference/nonPriimitiveInFunction.js +++ b/tests/baselines/reference/nonPrimitiveInFunction.js @@ -1,4 +1,4 @@ -//// [nonPriimitiveInFunction.ts] +//// [nonPrimitiveInFunction.ts] function takeObject(o: object) {} function returnObject(): object { return {}; @@ -19,7 +19,7 @@ function returnError(): object { } -//// [nonPriimitiveInFunction.js] +//// [nonPrimitiveInFunction.js] function takeObject(o) { } function returnObject() { return {}; diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts index 8fe8c8a3ebb..83801652865 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts @@ -3,6 +3,8 @@ var y = {foo: "bar"}; var a: object; x = a; y = a; // expect error +a = x; +a = y; var n = 123; var b = true; diff --git a/tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveInFunction.ts similarity index 100% rename from tests/cases/conformance/types/nonPrimitive/nonPriimitiveInFunction.ts rename to tests/cases/conformance/types/nonPrimitive/nonPrimitiveInFunction.ts From 66069fc382ca71e703c9a953db7215151490b6c5 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Mon, 19 Dec 2016 13:36:49 +0800 Subject: [PATCH 09/10] update implementation to use intrinsic type --- src/compiler/checker.ts | 20 ++++++++----------- src/compiler/types.ts | 7 ++++--- .../nonPrimitiveAssignError.errors.txt | 4 ++-- 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a1fae5ebbd3..b7d8ccf7f16 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -144,9 +144,9 @@ namespace ts { const voidType = createIntrinsicType(TypeFlags.Void, "void"); const neverType = createIntrinsicType(TypeFlags.Never, "never"); const silentNeverType = createIntrinsicType(TypeFlags.Never, "never"); + const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object"); const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined); - const nonPrimitiveType = createNonPrimitiveType(); const emptyTypeLiteralSymbol = createSymbol(SymbolFlags.TypeLiteral | SymbolFlags.Transient, "__type"); emptyTypeLiteralSymbol.members = createMap(); @@ -1685,13 +1685,6 @@ namespace ts { return type; } - function createNonPrimitiveType(): ResolvedType { - const type = setStructuredTypeMembers( - createObjectType(ObjectFlags.NonPrimitive, undefined), - emptySymbols, emptyArray, emptyArray, undefined, undefined); - return type; - } - function createObjectType(objectFlags: ObjectFlags, symbol?: Symbol): ObjectType { const type = createType(TypeFlags.Object); type.objectFlags = objectFlags; @@ -2320,9 +2313,6 @@ namespace ts { else if (type.flags & TypeFlags.UnionOrIntersection) { writeUnionOrIntersectionType(type, nextFlags); } - else if (getObjectFlags(type) & ObjectFlags.NonPrimitive) { - writer.writeKeyword("object"); - } else if (getObjectFlags(type) & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) { writeAnonymousType(type, nextFlags); } @@ -4771,6 +4761,7 @@ namespace ts { t.flags & TypeFlags.NumberLike ? globalNumberType : t.flags & TypeFlags.BooleanLike ? globalBooleanType : t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType() : + t.flags & TypeFlags.NonPrimitive ? globalObjectType : t; } @@ -7153,6 +7144,8 @@ namespace ts { if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(source, target, errorReporter)) return true; if (source.flags & TypeFlags.Undefined && (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void))) return true; if (source.flags & TypeFlags.Null && (!strictNullChecks || target.flags & TypeFlags.Null)) return true; + if (source.flags & TypeFlags.Object && target === nonPrimitiveType) return true; + if (source.flags & TypeFlags.Primitive && target === nonPrimitiveType) return false; if (relation === assignableRelation || relation === comparableRelation) { if (source.flags & TypeFlags.Any) return true; if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true; @@ -7471,7 +7464,7 @@ namespace ts { } } } - else if (!(source.flags & TypeFlags.Primitive && target === nonPrimitiveType)) { + else { if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { // We have type references to same target type, see if relationship holds for all type arguments if (result = typeArgumentsRelatedTo(source, target, reportErrors)) { @@ -9224,6 +9217,9 @@ namespace ts { } function getTypeFacts(type: Type): TypeFacts { + if (type === nonPrimitiveType) { + return strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts; + } const flags = type.flags; if (flags & TypeFlags.String) { return strictNullChecks ? TypeFacts.StringStrictFacts : TypeFacts.StringFacts; diff --git a/src/compiler/types.ts b/src/compiler/types.ts index db919b56449..5b411ffea30 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2781,6 +2781,7 @@ namespace ts { ContainsObjectLiteral = 1 << 22, // Type is or contains object literal type /* @internal */ ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type + NonPrimitive = 1 << 24, // intrinsic object type /* @internal */ Nullable = Undefined | Null, @@ -2790,7 +2791,7 @@ namespace ts { DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null, PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean, /* @internal */ - Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never, + Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive, /* @internal */ Primitive = String | Number | Boolean | Enum | ESSymbol | Void | Undefined | Null | Literal, StringLike = String | StringLiteral | Index, @@ -2798,14 +2799,14 @@ namespace ts { BooleanLike = Boolean | BooleanLiteral, EnumLike = Enum | EnumLiteral, UnionOrIntersection = Union | Intersection, - StructuredType = Object | Union | Intersection, + StructuredType = Object | Union | Intersection | NonPrimitive, StructuredOrTypeParameter = StructuredType | TypeParameter | Index, TypeVariable = TypeParameter | IndexedAccess, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol, - NotUnionOrUnit = Any | ESSymbol | Object, + NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral, /* @internal */ diff --git a/tests/baselines/reference/nonPrimitiveAssignError.errors.txt b/tests/baselines/reference/nonPrimitiveAssignError.errors.txt index bb62d494d74..a9bfaaa4a8a 100644 --- a/tests/baselines/reference/nonPrimitiveAssignError.errors.txt +++ b/tests/baselines/reference/nonPrimitiveAssignError.errors.txt @@ -1,5 +1,5 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(5,1): error TS2322: Type 'object' is not assignable to type '{ foo: string; }'. - Property 'foo' is missing in type 'object'. + Property 'foo' is missing in type 'Object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(13,1): error TS2322: Type 'number' is not assignable to type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(14,1): error TS2322: Type 'true' is not assignable to type 'object'. tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(15,1): error TS2322: Type 'string' is not assignable to type 'object'. @@ -16,7 +16,7 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveAssignError.ts(19,1): err y = a; // expect error ~ !!! error TS2322: Type 'object' is not assignable to type '{ foo: string; }'. -!!! error TS2322: Property 'foo' is missing in type 'object'. +!!! error TS2322: Property 'foo' is missing in type 'Object'. a = x; a = y; From 899387706fb11d48c6b6a5f4f986d6723a3026f3 Mon Sep 17 00:00:00 2001 From: Herrington Darkholme Date: Thu, 22 Dec 2016 10:02:26 +0800 Subject: [PATCH 10/10] classify nonPrimitive type as narrowable rather than structured --- src/compiler/types.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 5b411ffea30..03cbd252924 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2799,13 +2799,13 @@ namespace ts { BooleanLike = Boolean | BooleanLiteral, EnumLike = Enum | EnumLiteral, UnionOrIntersection = Union | Intersection, - StructuredType = Object | Union | Intersection | NonPrimitive, + StructuredType = Object | Union | Intersection, StructuredOrTypeParameter = StructuredType | TypeParameter | Index, TypeVariable = TypeParameter | IndexedAccess, // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never - Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol, + Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol | NonPrimitive, NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral,