Add fastpath to isRelatedTo for type references (#37481)

* Add fastpath to isRelatedTo for type references

* Do not check intersections or unions to ignore propegating reference flags, properly set comparing jsx flag

* Re-remove unneeded check

* Just check for TypeFlags.Object

* Remove else clause
This commit is contained in:
Wesley Wigham
2020-04-13 15:54:37 -07:00
committed by GitHub
parent 8dd6b3a389
commit edd4e0a42b
5 changed files with 394 additions and 37 deletions

View File

@@ -15541,11 +15541,21 @@ namespace ts {
* * Ternary.False if they are not related.
*/
function isRelatedTo(originalSource: Type, originalTarget: Type, reportErrors = false, headMessage?: DiagnosticMessage, intersectionState = IntersectionState.None): Ternary {
// Before normalization: if `source` is type an object type, and `target` is primitive,
// skip all the checks we don't need and just return `isSimpleTypeRelatedTo` result
if (originalSource.flags & TypeFlags.Object && originalTarget.flags & TypeFlags.Primitive) {
if (isSimpleTypeRelatedTo(originalSource, originalTarget, relation, reportErrors ? reportError : undefined)) {
return Ternary.True;
}
reportErrorResults(originalSource, originalTarget, Ternary.False, !!(getObjectFlags(originalSource) & ObjectFlags.JsxAttributes));
return Ternary.False;
}
// Normalize the source and target types: Turn fresh literal types into regular literal types,
// turn deferred type references into regular type references, simplify indexed access and
// conditional types, and resolve substitution types to either the substitution (on the source
// side) or the type variable (on the target side).
let source = getNormalizedType(originalSource, /*writing*/ false);
const source = getNormalizedType(originalSource, /*writing*/ false);
let target = getNormalizedType(originalTarget, /*writing*/ true);
if (source === target) return Ternary.True;
@@ -15679,6 +15689,7 @@ namespace ts {
}
}
}
// For certain combinations involving intersections and optional, excess, or mismatched properties we need
// an extra property check where the intersection is viewed as a single object. The following are motivating
// examples that all should be errors, but aren't without this extra property check:
@@ -15702,47 +15713,51 @@ namespace ts {
inPropertyCheck = false;
}
if (!result && reportErrors) {
source = originalSource.aliasSymbol ? originalSource : source;
target = originalTarget.aliasSymbol ? originalTarget : target;
let maybeSuppress = overrideNextErrorInfo > 0;
if (maybeSuppress) {
overrideNextErrorInfo--;
}
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
const currentError = errorInfo;
tryElaborateArrayLikeErrors(source, target, reportErrors);
if (errorInfo !== currentError) {
maybeSuppress = !!errorInfo;
reportErrorResults(source, target, result, isComparingJsxAttributes);
return result;
function reportErrorResults(source: Type, target: Type, result: Ternary, isComparingJsxAttributes: boolean) {
if (!result && reportErrors) {
source = originalSource.aliasSymbol ? originalSource : source;
target = originalTarget.aliasSymbol ? originalTarget : target;
let maybeSuppress = overrideNextErrorInfo > 0;
if (maybeSuppress) {
overrideNextErrorInfo--;
}
}
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) {
tryElaborateErrorsForPrimitivesAndObjects(source, target);
}
else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) {
reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead);
}
else if (isComparingJsxAttributes && target.flags & TypeFlags.Intersection) {
const targetTypes = (target as IntersectionType).types;
const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode);
const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode);
if (intrinsicAttributes !== errorType && intrinsicClassAttributes !== errorType &&
(contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes))) {
// do not report top error
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
const currentError = errorInfo;
tryElaborateArrayLikeErrors(source, target, reportErrors);
if (errorInfo !== currentError) {
maybeSuppress = !!errorInfo;
}
}
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Primitive) {
tryElaborateErrorsForPrimitivesAndObjects(source, target);
}
else if (source.symbol && source.flags & TypeFlags.Object && globalObjectType === source) {
reportError(Diagnostics.The_Object_type_is_assignable_to_very_few_other_types_Did_you_mean_to_use_the_any_type_instead);
}
else if (isComparingJsxAttributes && target.flags & TypeFlags.Intersection) {
const targetTypes = (target as IntersectionType).types;
const intrinsicAttributes = getJsxType(JsxNames.IntrinsicAttributes, errorNode);
const intrinsicClassAttributes = getJsxType(JsxNames.IntrinsicClassAttributes, errorNode);
if (intrinsicAttributes !== errorType && intrinsicClassAttributes !== errorType &&
(contains(targetTypes, intrinsicAttributes) || contains(targetTypes, intrinsicClassAttributes))) {
// do not report top error
return result;
}
}
else {
errorInfo = elaborateNeverIntersection(errorInfo, originalTarget);
}
if (!headMessage && maybeSuppress) {
lastSkippedInfo = [source, target];
// Used by, eg, missing property checking to replace the top-level message with a more informative one
return result;
}
reportRelationError(headMessage, source, target);
}
else {
errorInfo = elaborateNeverIntersection(errorInfo, originalTarget);
}
if (!headMessage && maybeSuppress) {
lastSkippedInfo = [source, target];
// Used by, eg, missing property checking to replace the top-level message with a more informative one
return result;
}
reportRelationError(headMessage, source, target);
}
return result;
}
function isIdenticalTo(source: Type, target: Type): Ternary {