Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Report primitive type in literal-to-primitive relation complaints #38049

Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions src/compiler/checker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4070,12 +4070,16 @@ namespace ts {
let leftStr = symbolValueDeclarationIsContextSensitive(left.symbol) ? typeToString(left, left.symbol.valueDeclaration) : typeToString(left);
let rightStr = symbolValueDeclarationIsContextSensitive(right.symbol) ? typeToString(right, right.symbol.valueDeclaration) : typeToString(right);
if (leftStr === rightStr) {
leftStr = typeToString(left, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
rightStr = typeToString(right, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
leftStr = getTypeNameForErrorDisplay(left);
rightStr = getTypeNameForErrorDisplay(right);
}
return [leftStr, rightStr];
}

function getTypeNameForErrorDisplay(type: Type) {
return typeToString(type, /*enclosingDeclaration*/ undefined, TypeFormatFlags.UseFullyQualifiedType);
}

function symbolValueDeclarationIsContextSensitive(symbol: Symbol): boolean {
return symbol && symbol.valueDeclaration && isExpression(symbol.valueDeclaration) && !isContextSensitive(symbol.valueDeclaration);
}
Expand Down Expand Up @@ -15451,6 +15455,7 @@ namespace ts {
function reportRelationError(message: DiagnosticMessage | undefined, source: Type, target: Type) {
if (incompatibleStack.length) reportIncompatibleStack();
const [sourceType, targetType] = getTypeNamesForErrorDisplay(source, target);
let generalizedSourceType = sourceType;

if (target.flags & TypeFlags.TypeParameter) {
const constraint = getBaseConstraintOfType(target);
Expand Down Expand Up @@ -15484,7 +15489,21 @@ namespace ts {
}
}

reportError(message, sourceType, targetType);
if (isLiteralType(source) && !typeCouldHaveNoTopLevelSingletonTypes(target)) {
generalizedSourceType = getTypeNameForErrorDisplay(getBaseTypeOfLiteralType(source));
}

reportError(message, generalizedSourceType, targetType);
}

function typeCouldHaveNoTopLevelSingletonTypes(type: Type) {
return forEachType(type, typeCouldHaveNoTopLevelSingletonTypesWorker);
}

function typeCouldHaveNoTopLevelSingletonTypesWorker(type: Type): boolean {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I think we're getting there. First, I would move these functions out so that they don't add more to the current closure on every call.

Second, I think we have to go deeper on constraints, and we can get rid of the "Worker" function.

            function typeCouldHaveNoTopLevelSingletonTypes(type: Type): boolean {
                if (type.flags & TypeFlags.UnionOrIntersection) {
                    return !!forEach((type as IntersectionType).types, typeCouldHaveNoTopLevelSingletonTypes);
                }

                if (type.flags & TypeFlags.Instantiable) {
                    const constraint = getConstraintOfType(type);
                    if (constraint) {
                        return typeCouldHaveNoTopLevelSingletonTypes(constraint);
                    }
                }

                return isUnitType(type);
            }

return (type.flags & TypeFlags.Intersection)
? !!forEach((type as IntersectionType).types, typeCouldHaveNoTopLevelSingletonTypesWorker)
: isUnitType(type) || !!(type.flags & TypeFlags.Instantiable);
}

function tryElaborateErrorsForPrimitivesAndObjects(source: Type, target: Type) {
Expand Down
2 changes: 1 addition & 1 deletion src/testRunner/unittests/tscWatch/incremental.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ namespace ts.tscWatch {
length: 1,
code: Diagnostics.Type_0_is_not_assignable_to_type_1.code,
category: Diagnostics.Type_0_is_not_assignable_to_type_1.category,
messageText: "Type '20' is not assignable to type 'string'.",
messageText: "Type 'number' is not assignable to type 'string'.",
relatedInformation: undefined,
reportsUnnecessary: undefined,
source: undefined
Expand Down
2 changes: 1 addition & 1 deletion src/testRunner/unittests/tscWatch/resolutionCache.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ namespace ts.tscWatch {
// ensure file has correct number of errors after edit
checkOutputErrorsIncremental(host, [
f1IsNotModule,
getDiagnosticOfFileFromProgram(watch.getCurrentProgram().getProgram(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, 1, "string"),
getDiagnosticOfFileFromProgram(watch.getCurrentProgram().getProgram(), root.path, newContent.indexOf("var x") + "var ".length, "x".length, Diagnostics.Type_0_is_not_assignable_to_type_1, "number", "string"),
cannotFindFoo
]);
}
Expand Down
2 changes: 1 addition & 1 deletion src/testRunner/unittests/tsserver/openFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ bar();`
file,
syntax: [],
semantic: [
createDiagnostic(locationOfY.start, locationOfY.end, Diagnostics.Type_0_is_not_assignable_to_type_1, ["10", "string"]),
createDiagnostic(locationOfY.start, locationOfY.end, Diagnostics.Type_0_is_not_assignable_to_type_1, ["number", "string"]),
],
suggestion: []
},
Expand Down
4 changes: 2 additions & 2 deletions src/testRunner/unittests/tsserver/projectReferenceErrors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ fnErr();
{ line: 6, offset: 12 },
{ line: 6, offset: 13 },
Diagnostics.Type_0_is_not_assignable_to_type_1,
["10", "string"],
["number", "string"],
"error",
)
],
Expand Down Expand Up @@ -235,7 +235,7 @@ fnErr();
{ line: 6, offset: 5 },
{ line: 6, offset: 6 },
Diagnostics.Type_0_is_not_assignable_to_type_1,
["10", "string"],
["number", "string"],
"error",
)
],
Expand Down
8 changes: 4 additions & 4 deletions tests/baselines/reference/ES5For-of30.errors.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,6): error TS2461: Type 'string | number' is not an array type.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,7): error TS2322: Type '1' is not assignable to type 'string'.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,14): error TS2322: Type '""' is not assignable to type 'number'.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,7): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,14): error TS2322: Type 'string' is not assignable to type 'number'.


==== tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts (3 errors) ====
Expand All @@ -10,9 +10,9 @@ tests/cases/conformance/statements/for-ofStatements/ES5For-of30.ts(3,14): error
~~~~~~~~~~~~~~~
!!! error TS2461: Type 'string | number' is not an array type.
~
!!! error TS2322: Type '1' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~
!!! error TS2322: Type '""' is not assignable to type 'number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
a;
b;
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(2,16): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(3,16): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(3,48): error TS2322: Type '""' is not assignable to type 'number'.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(3,48): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(5,16): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(5,47): error TS2322: Type '""' is not assignable to type 'number'.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(5,47): error TS2322: Type 'string' is not assignable to type 'number'.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(6,16): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(8,16): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(9,16): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(9,52): error TS2322: Type '0' is not assignable to type 'string'.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(9,52): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(11,16): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(11,51): error TS2322: Type '0' is not assignable to type 'string'.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(11,51): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(12,16): error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.


Expand All @@ -21,13 +21,13 @@ tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(12,16): error TS1
~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
~~~~~~~~~~
!!! error TS2322: Type '""' is not assignable to type 'number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.

public get AnnotatedSetter_SetterLast() { return ""; }
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
~~~~~~~~~~
!!! error TS2322: Type '""' is not assignable to type 'number'.
!!! error TS2322: Type 'string' is not assignable to type 'number'.
public set AnnotatedSetter_SetterLast(a: number) { }
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
Expand All @@ -39,13 +39,13 @@ tests/cases/compiler/accessors_spec_section-4.5_error-cases.ts(12,16): error TS1
~~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
~~~~
!!! error TS2322: Type '0' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.

public set AnnotatedGetter_GetterLast(aStr) { aStr = 0; }
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
~~~~
!!! error TS2322: Type '0' is not assignable to type 'string'.
!!! error TS2322: Type 'number' is not assignable to type 'string'.
public get AnnotatedGetter_GetterLast(): string { return ""; }
~~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS1056: Accessors are only available when targeting ECMAScript 5 and higher.
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/aliasAssignments.errors.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
tests/cases/compiler/aliasAssignments_1.ts(3,1): error TS2322: Type '1' is not assignable to type 'typeof import("tests/cases/compiler/aliasAssignments_moduleA")'.
tests/cases/compiler/aliasAssignments_1.ts(3,1): error TS2322: Type 'number' is not assignable to type 'typeof import("tests/cases/compiler/aliasAssignments_moduleA")'.
tests/cases/compiler/aliasAssignments_1.ts(5,1): error TS2322: Type 'typeof import("tests/cases/compiler/aliasAssignments_moduleA")' is not assignable to type 'number'.


Expand All @@ -7,7 +7,7 @@ tests/cases/compiler/aliasAssignments_1.ts(5,1): error TS2322: Type 'typeof impo
var x = moduleA;
x = 1; // Should be error
~
!!! error TS2322: Type '1' is not assignable to type 'typeof import("tests/cases/compiler/aliasAssignments_moduleA")'.
!!! error TS2322: Type 'number' is not assignable to type 'typeof import("tests/cases/compiler/aliasAssignments_moduleA")'.
var y = 1;
y = moduleA; // should be error
~
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
tests/cases/compiler/app.js(6,7): error TS2322: Type '1' is not assignable to type 'WatchHandler<any>'.
tests/cases/compiler/app.js(6,7): error TS2322: Type 'number' is not assignable to type 'WatchHandler<any>'.


==== tests/cases/compiler/func.ts (0 errors) ====
Expand All @@ -16,7 +16,7 @@ tests/cases/compiler/app.js(6,7): error TS2322: Type '1' is not assignable to ty
data1(val) {
this.data2 = 1;
~~~~~~~~~~
!!! error TS2322: Type '1' is not assignable to type 'WatchHandler<any>'.
!!! error TS2322: Type 'number' is not assignable to type 'WatchHandler<any>'.
},
data2(val) { },
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
tests/cases/compiler/argumentsBindsToFunctionScopeArgumentList.ts(3,5): error TS2322: Type '10' is not assignable to type 'IArguments'.
tests/cases/compiler/argumentsBindsToFunctionScopeArgumentList.ts(3,5): error TS2322: Type 'number' is not assignable to type 'IArguments'.


==== tests/cases/compiler/argumentsBindsToFunctionScopeArgumentList.ts (1 errors) ====
var arguments = 10;
function foo(a) {
arguments = 10; /// This shouldnt be of type number and result in error.
~~~~~~~~~
!!! error TS2322: Type '10' is not assignable to type 'IArguments'.
!!! error TS2322: Type 'number' is not assignable to type 'IArguments'.
}
4 changes: 2 additions & 2 deletions tests/baselines/reference/arrayLiterals3.errors.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(10,5): error TS2739: Type '[]' is missing the following properties from type '[any, any, any]': 0, 1, 2
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(11,38): error TS2322: Type 'string' is not assignable to type 'boolean'.
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(11,48): error TS2322: Type 'number' is not assignable to type 'string'.
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(11,51): error TS2322: Type 'true' is not assignable to type 'number'.
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(11,51): error TS2322: Type 'boolean' is not assignable to type 'number'.
tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(17,5): error TS2322: Type '[number, number, string, boolean]' is not assignable to type '[number, number]'.
Types of property 'length' are incompatible.
Type '4' is not assignable to type '2'.
Expand Down Expand Up @@ -31,7 +31,7 @@ tests/cases/conformance/expressions/arrayLiterals/arrayLiterals3.ts(34,5): error
~
!!! error TS2322: Type 'number' is not assignable to type 'string'.
~~~~
!!! error TS2322: Type 'true' is not assignable to type 'number'.
!!! error TS2322: Type 'boolean' is not assignable to type 'number'.

// The resulting type an array literal expression is determined as follows:
// - If the array literal contains no spread elements and is an array assignment pattern in a destructuring assignment (section 4.17.1),
Expand Down
4 changes: 2 additions & 2 deletions tests/baselines/reference/assignToFn.errors.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
tests/cases/compiler/assignToFn.ts(8,5): error TS2322: Type '"hello"' is not assignable to type '(n: number) => boolean'.
tests/cases/compiler/assignToFn.ts(8,5): error TS2322: Type 'string' is not assignable to type '(n: number) => boolean'.


==== tests/cases/compiler/assignToFn.ts (1 errors) ====
Expand All @@ -11,6 +11,6 @@ tests/cases/compiler/assignToFn.ts(8,5): error TS2322: Type '"hello"' is not ass

x.f="hello";
~~~
!!! error TS2322: Type '"hello"' is not assignable to type '(n: number) => boolean'.
!!! error TS2322: Type 'string' is not assignable to type '(n: number) => boolean'.
}

8 changes: 4 additions & 4 deletions tests/baselines/reference/assignmentCompat1.errors.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
tests/cases/compiler/assignmentCompat1.ts(4,1): error TS2741: Property 'one' is missing in type '{ [index: string]: any; }' but required in type '{ one: number; }'.
tests/cases/compiler/assignmentCompat1.ts(6,1): error TS2741: Property 'one' is missing in type '{ [index: number]: any; }' but required in type '{ one: number; }'.
tests/cases/compiler/assignmentCompat1.ts(8,1): error TS2322: Type '"foo"' is not assignable to type '{ [index: string]: any; }'.
tests/cases/compiler/assignmentCompat1.ts(10,1): error TS2322: Type 'false' is not assignable to type '{ [index: number]: any; }'.
tests/cases/compiler/assignmentCompat1.ts(8,1): error TS2322: Type 'string' is not assignable to type '{ [index: string]: any; }'.
tests/cases/compiler/assignmentCompat1.ts(10,1): error TS2322: Type 'boolean' is not assignable to type '{ [index: number]: any; }'.


==== tests/cases/compiler/assignmentCompat1.ts (4 errors) ====
Expand All @@ -20,10 +20,10 @@ tests/cases/compiler/assignmentCompat1.ts(10,1): error TS2322: Type 'false' is n
z = x; // Ok because index signature type is any
y = "foo"; // Error
~
!!! error TS2322: Type '"foo"' is not assignable to type '{ [index: string]: any; }'.
!!! error TS2322: Type 'string' is not assignable to type '{ [index: string]: any; }'.
z = "foo"; // OK, string has numeric indexer
z = false; // Error
~
!!! error TS2322: Type 'false' is not assignable to type '{ [index: number]: any; }'.
!!! error TS2322: Type 'boolean' is not assignable to type '{ [index: number]: any; }'.


Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(1,10): error TS2391: Function implementation is missing or not immediately following the declaration.
tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(4,17): error TS2322: Type 'false' is not assignable to type 'string'.
tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(4,17): error TS2322: Type 'boolean' is not assignable to type 'string'.
tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(5,5): error TS2345: Argument of type '{ name: string; }' is not assignable to parameter of type '{ id: number; name?: string; }'.
Property 'id' is missing in type '{ name: string; }' but required in type '{ id: number; name?: string; }'.

Expand All @@ -12,7 +12,7 @@ tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts(5,5): error TS
foo({ id: 1234, name: "hello" }); // Ok
foo({ id: 1234, name: false }); // Error, name of wrong type
~~~~
!!! error TS2322: Type 'false' is not assignable to type 'string'.
!!! error TS2322: Type 'boolean' is not assignable to type 'string'.
!!! related TS6500 tests/cases/compiler/assignmentCompatFunctionsWithOptionalArgs.ts:1:31: The expected type comes from property 'name' which is declared here on type '{ id: number; name?: string; }'
foo({ name: "hello" }); // Error, id required but missing
~~~~~~~~~~~~~~~~~
Expand Down
Loading