mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-30 01:04:49 -05:00
Add isIntersectionConstituent to relation key (#34789)
* Add isIntersectionConstituent to relation key isIntersectionConstituent controls whether relation checking performs excess property and common property checks. It is possible to fail a relation check with excess property checks turned on, cache the result, and then skip a relation check with excess property checks that would have succeeded. #33133 provides an example of such a program. Fixes #33133 the right way, so I reverted the fix at #33213 Fixes #34762 (by reverting #33213) Fixes #33944 -- I added the test from #34646 * Update comments in test
This commit is contained in:
committed by
GitHub
parent
7635884224
commit
00dd1f0609
@@ -14165,7 +14165,7 @@ namespace ts {
|
||||
return true;
|
||||
}
|
||||
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
|
||||
const related = relation.get(getRelationKey(source, target, relation));
|
||||
const related = relation.get(getRelationKey(source, target, /*isIntersectionConstituent*/ false, relation));
|
||||
if (related !== undefined) {
|
||||
return !!(related & RelationComparisonResult.Succeeded);
|
||||
}
|
||||
@@ -14571,7 +14571,7 @@ namespace ts {
|
||||
// and we need to handle "each" relations before "some" relations for the same kind of type.
|
||||
if (source.flags & TypeFlags.Union) {
|
||||
result = relation === comparableRelation ?
|
||||
someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive), isIntersectionConstituent) :
|
||||
someTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive)) :
|
||||
eachTypeRelatedToType(source as UnionType, target, reportErrors && !(source.flags & TypeFlags.Primitive));
|
||||
}
|
||||
else {
|
||||
@@ -14609,7 +14609,7 @@ namespace ts {
|
||||
//
|
||||
// - For a primitive type or type parameter (such as 'number = A & B') there is no point in
|
||||
// breaking the intersection apart.
|
||||
result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false, /*isIntersectionConstituent*/ true);
|
||||
result = someTypeRelatedToType(<IntersectionType>source, target, /*reportErrors*/ false);
|
||||
}
|
||||
if (!result && (source.flags & TypeFlags.StructuredOrInstantiable || target.flags & TypeFlags.StructuredOrInstantiable)) {
|
||||
if (result = recursiveTypeRelatedTo(source, target, reportErrors, isIntersectionConstituent)) {
|
||||
@@ -14903,14 +14903,14 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean, isIntersectionConstituent: boolean): Ternary {
|
||||
function someTypeRelatedToType(source: UnionOrIntersectionType, target: Type, reportErrors: boolean): Ternary {
|
||||
const sourceTypes = source.types;
|
||||
if (source.flags & TypeFlags.Union && containsType(sourceTypes, target)) {
|
||||
return Ternary.True;
|
||||
}
|
||||
const len = sourceTypes.length;
|
||||
for (let i = 0; i < len; i++) {
|
||||
const related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1, /*headMessage*/ undefined, isIntersectionConstituent);
|
||||
const related = isRelatedTo(sourceTypes[i], target, reportErrors && i === len - 1);
|
||||
if (related) {
|
||||
return related;
|
||||
}
|
||||
@@ -14997,7 +14997,7 @@ namespace ts {
|
||||
if (overflow) {
|
||||
return Ternary.False;
|
||||
}
|
||||
const id = getRelationKey(source, target, relation);
|
||||
const id = getRelationKey(source, target, isIntersectionConstituent, relation);
|
||||
const entry = relation.get(id);
|
||||
if (entry !== undefined) {
|
||||
if (reportErrors && entry & RelationComparisonResult.Failed && !(entry & RelationComparisonResult.Reported)) {
|
||||
@@ -16211,17 +16211,18 @@ namespace ts {
|
||||
* To improve caching, the relation key for two generic types uses the target's id plus ids of the type parameters.
|
||||
* For other cases, the types ids are used.
|
||||
*/
|
||||
function getRelationKey(source: Type, target: Type, relation: Map<RelationComparisonResult>) {
|
||||
function getRelationKey(source: Type, target: Type, isIntersectionConstituent: boolean, relation: Map<RelationComparisonResult>) {
|
||||
if (relation === identityRelation && source.id > target.id) {
|
||||
const temp = source;
|
||||
source = target;
|
||||
target = temp;
|
||||
}
|
||||
const intersection = isIntersectionConstituent ? "&" : "";
|
||||
if (isTypeReferenceWithGenericArguments(source) && isTypeReferenceWithGenericArguments(target)) {
|
||||
const typeParameters: Type[] = [];
|
||||
return getTypeReferenceId(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>target, typeParameters);
|
||||
return getTypeReferenceId(<TypeReference>source, typeParameters) + "," + getTypeReferenceId(<TypeReference>target, typeParameters) + intersection;
|
||||
}
|
||||
return source.id + "," + target.id;
|
||||
return source.id + "," + target.id + intersection;
|
||||
}
|
||||
|
||||
// Invoke the callback for each underlying property symbol of the given symbol and return the first
|
||||
|
||||
Reference in New Issue
Block a user