Merge pull request #38049 from JoshuaKGoldberg/literal-to-primitive-relation-reporting

Report primitive type in literal-to-primitive relation complaints
This commit is contained in:
Daniel Rosenwasser
2020-05-26 13:18:14 -07:00
committed by GitHub
240 changed files with 1079 additions and 1065 deletions

View File

@@ -4139,12 +4139,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);
}
@@ -15726,23 +15730,30 @@ namespace ts {
function reportRelationError(message: DiagnosticMessage | undefined, source: Type, target: Type) {
if (incompatibleStack.length) reportIncompatibleStack();
const [sourceType, targetType] = getTypeNamesForErrorDisplay(source, target);
let generalizedSource = source;
let generalizedSourceType = sourceType;
if (isLiteralType(source) && !typeCouldHaveTopLevelSingletonTypes(target)) {
generalizedSource = getBaseTypeOfLiteralType(source);
generalizedSourceType = getTypeNameForErrorDisplay(generalizedSource);
}
if (target.flags & TypeFlags.TypeParameter) {
const constraint = getBaseConstraintOfType(target);
const constraintElab = constraint && isTypeAssignableTo(source, constraint);
if (constraintElab) {
let needsOriginalSource;
if (constraint && (isTypeAssignableTo(generalizedSource, constraint) || (needsOriginalSource = isTypeAssignableTo(source, constraint)))) {
reportError(
Diagnostics._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2,
sourceType,
needsOriginalSource ? sourceType : generalizedSourceType,
targetType,
typeToString(constraint!),
typeToString(constraint),
);
}
else {
reportError(
Diagnostics._0_could_be_instantiated_with_an_arbitrary_type_which_could_be_unrelated_to_1,
targetType,
sourceType
generalizedSourceType
);
}
}
@@ -15759,7 +15770,7 @@ namespace ts {
}
}
reportError(message, sourceType, targetType);
reportError(message, generalizedSourceType, targetType);
}
function tryElaborateErrorsForPrimitivesAndObjects(source: Type, target: Type) {
@@ -17357,6 +17368,21 @@ namespace ts {
}
}
function typeCouldHaveTopLevelSingletonTypes(type: Type): boolean {
if (type.flags & TypeFlags.UnionOrIntersection) {
return !!forEach((type as IntersectionType).types, typeCouldHaveTopLevelSingletonTypes);
}
if (type.flags & TypeFlags.Instantiable) {
const constraint = getConstraintOfType(type);
if (constraint) {
return typeCouldHaveTopLevelSingletonTypes(constraint);
}
}
return isUnitType(type);
}
function getBestMatchingType(source: Type, target: UnionOrIntersectionType, isRelatedTo = compareTypesAssignable) {
return findMatchingDiscriminantType(source, target, isRelatedTo, /*skipPartial*/ true) ||
findMatchingTypeReferenceOrTypeAliasReference(source, target) ||

View File

@@ -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

View File

@@ -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
]);
}

View File

@@ -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: []
},

View File

@@ -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",
)
],
@@ -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",
)
],