@@ -1252,12 +1252,13 @@ export const enum CheckMode {
1252
1252
1253
1253
/** @internal */
1254
1254
export const enum SignatureCheckMode {
1255
- None = 0,
1255
+ None = 0,
1256
1256
BivariantCallback = 1 << 0,
1257
- StrictCallback = 1 << 1,
1257
+ StrictCallback = 1 << 1,
1258
1258
IgnoreReturnTypes = 1 << 2,
1259
- StrictArity = 1 << 3,
1260
- Callback = BivariantCallback | StrictCallback,
1259
+ StrictArity = 1 << 3,
1260
+ StrictTopSignature = 1 << 4,
1261
+ Callback = BivariantCallback | StrictCallback,
1261
1262
}
1262
1263
1263
1264
const enum IntersectionState {
@@ -19582,12 +19583,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19582
19583
type ErrorReporter = (message: DiagnosticMessage, arg0?: string, arg1?: string) => void;
19583
19584
19584
19585
/**
19585
- * Returns true if `s` is `(...args: any[] ) => any` or `(this: any, ...args: any[]) => any`
19586
+ * Returns true if `s` is `(...args: A ) => R` where `A` is ` any`, ` any[]`, `never`, or `never[]`, and `R` is ` any` or `unknown`.
19586
19587
*/
19587
- function isAnySignature(s: Signature) {
19588
- return !s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) && s.parameters.length === 1 &&
19589
- signatureHasRestParameter(s) && (getTypeOfParameter(s.parameters[0]) === anyArrayType || isTypeAny(getTypeOfParameter(s.parameters[0]))) &&
19590
- isTypeAny(getReturnTypeOfSignature(s));
19588
+ function isTopSignature(s: Signature) {
19589
+ if (!s.typeParameters && (!s.thisParameter || isTypeAny(getTypeOfParameter(s.thisParameter))) && s.parameters.length === 1 && signatureHasRestParameter(s)) {
19590
+ const paramType = getTypeOfParameter(s.parameters[0]);
19591
+ const restType = isArrayType(paramType) ? getTypeArguments(paramType)[0] : paramType;
19592
+ return !!(restType.flags & (TypeFlags.Any | TypeFlags.Never) && getReturnTypeOfSignature(s).flags & TypeFlags.AnyOrUnknown);
19593
+ }
19594
+ return false;
19591
19595
}
19592
19596
19593
19597
/**
@@ -19606,9 +19610,12 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19606
19610
return Ternary.True;
19607
19611
}
19608
19612
19609
- if (isAnySignature (target)) {
19613
+ if (!(checkMode & SignatureCheckMode.StrictTopSignature && isTopSignature(source)) && isTopSignature (target)) {
19610
19614
return Ternary.True;
19611
19615
}
19616
+ if (checkMode & SignatureCheckMode.StrictTopSignature && isTopSignature(source) && !isTopSignature(target)) {
19617
+ return Ternary.False;
19618
+ }
19612
19619
19613
19620
const targetCount = getParameterCount(target);
19614
19621
const sourceHasMoreParameters = !hasEffectiveRestParameter(target) &&
@@ -19864,7 +19871,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
19864
19871
function isSimpleTypeRelatedTo(source: Type, target: Type, relation: Map<string, RelationComparisonResult>, errorReporter?: ErrorReporter) {
19865
19872
const s = source.flags;
19866
19873
const t = target.flags;
19867
- if (t & TypeFlags.AnyOrUnknown || s & TypeFlags.Never || source === wildcardType) return true;
19874
+ if (t & TypeFlags.Any || s & TypeFlags.Never || source === wildcardType) return true;
19875
+ if (t & TypeFlags.Unknown && !(relation === strictSubtypeRelation && s & TypeFlags.Any)) return true;
19868
19876
if (t & TypeFlags.Never) return false;
19869
19877
if (s & TypeFlags.StringLike && t & TypeFlags.String) return true;
19870
19878
if (s & TypeFlags.StringLiteral && s & TypeFlags.EnumLiteral &&
@@ -21486,8 +21494,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
21486
21494
return Ternary.False;
21487
21495
}
21488
21496
}
21489
- // Consider a fresh empty object literal type "closed" under the subtype relationship - this way `{} <- {[idx : string]: any} <- fresh({})`
21490
- // and not `{} <- fresh({}) <- {[idx: string]: any}`
21497
+ // A fresh empty object type is never a subtype of a non-empty object type. This ensures fresh({}) <: { [x : string]: xxx }
21498
+ // but not vice-versa. Without this rule, those types would be mutual subtypes.
21491
21499
else if ((relation === subtypeRelation || relation === strictSubtypeRelation) && isEmptyObjectType(target) && getObjectFlags(target) & ObjectFlags.FreshLiteral && !isEmptyObjectType(source)) {
21492
21500
return Ternary.False;
21493
21501
}
@@ -22142,8 +22150,11 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22142
22150
* See signatureAssignableTo, compareSignaturesIdentical
22143
22151
*/
22144
22152
function signatureRelatedTo(source: Signature, target: Signature, erase: boolean, reportErrors: boolean, intersectionState: IntersectionState, incompatibleReporter: (source: Type, target: Type) => void): Ternary {
22153
+ const checkMode = relation === subtypeRelation ? SignatureCheckMode.StrictTopSignature :
22154
+ relation === strictSubtypeRelation ? SignatureCheckMode.StrictTopSignature | SignatureCheckMode.StrictArity :
22155
+ SignatureCheckMode.None;
22145
22156
return compareSignaturesRelated(erase ? getErasedSignature(source) : source, erase ? getErasedSignature(target) : target,
22146
- relation === strictSubtypeRelation ? SignatureCheckMode.StrictArity : 0 , reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper);
22157
+ checkMode , reportErrors, reportError, incompatibleReporter, isRelatedToWorker, reportUnreliableMapper);
22147
22158
function isRelatedToWorker(source: Type, target: Type, reportErrors?: boolean) {
22148
22159
return isRelatedTo(source, target, RecursionFlags.Both, reportErrors, /*headMessage*/ undefined, intersectionState);
22149
22160
}
@@ -22239,8 +22250,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
22239
22250
if (sourceInfo) {
22240
22251
return indexInfoRelatedTo(sourceInfo, targetInfo, reportErrors, intersectionState);
22241
22252
}
22242
- if (!(intersectionState & IntersectionState.Source) && isObjectTypeWithInferableIndex(source)) {
22243
- // Intersection constituents are never considered to have an inferred index signature
22253
+ // Intersection constituents are never considered to have an inferred index signature. Also, in the strict subtype relation,
22254
+ // only fresh object literals are considered to have inferred index signatures. This ensures { [x: string]: xxx } <: {} but
22255
+ // not vice-versa. Without this rule, those types would be mutual strict subtypes.
22256
+ if (!(intersectionState & IntersectionState.Source) && (relation !== strictSubtypeRelation || getObjectFlags(source) & ObjectFlags.FreshLiteral) && isObjectTypeWithInferableIndex(source)) {
22244
22257
return membersRelatedToIndexInfo(source, targetInfo, reportErrors, intersectionState);
22245
22258
}
22246
22259
if (reportErrors) {
@@ -27089,21 +27102,25 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
27089
27102
return emptyObjectType;
27090
27103
}
27091
27104
27092
- function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) {
27105
+ function getNarrowedType(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean): Type {
27093
27106
const key = type.flags & TypeFlags.Union ? `N${getTypeId(type)},${getTypeId(candidate)},${(assumeTrue ? 1 : 0) | (checkDerived ? 2 : 0)}` : undefined;
27094
27107
return getCachedType(key) ?? setCachedType(key, getNarrowedTypeWorker(type, candidate, assumeTrue, checkDerived));
27095
27108
}
27096
27109
27097
27110
function getNarrowedTypeWorker(type: Type, candidate: Type, assumeTrue: boolean, checkDerived: boolean) {
27098
- const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf;
27099
27111
if (!assumeTrue) {
27100
- return filterType(type, t => !isRelated(t, candidate));
27112
+ if (checkDerived) {
27113
+ return filterType(type, t => !isTypeDerivedFrom(t, candidate));
27114
+ }
27115
+ const trueType = getNarrowedType(type, candidate, /*assumeTrue*/ true, /*checkDerived*/ false);
27116
+ return filterType(type, t => !isTypeSubsetOf(t, trueType));
27101
27117
}
27102
27118
if (type.flags & TypeFlags.AnyOrUnknown) {
27103
27119
return candidate;
27104
27120
}
27105
27121
// We first attempt to filter the current type, narrowing constituents as appropriate and removing
27106
27122
// constituents that are unrelated to the candidate.
27123
+ const isRelated = checkDerived ? isTypeDerivedFrom : isTypeSubtypeOf;
27107
27124
const keyPropertyName = type.flags & TypeFlags.Union ? getKeyPropertyName(type as UnionType) : undefined;
27108
27125
const narrowedType = mapType(candidate, c => {
27109
27126
// If a discriminant property is available, use that to reduce the type.
@@ -27115,7 +27132,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
27115
27132
// prototype object types.
27116
27133
const directlyRelated = mapType(matching || type, checkDerived ?
27117
27134
t => isTypeDerivedFrom(t, c) ? t : isTypeDerivedFrom(c, t) ? c : neverType :
27118
- t => isTypeSubtypeOf(c, t) ? c : isTypeSubtypeOf(t, c) ? t : neverType);
27135
+ t => isTypeSubtypeOf(c, t) && !isTypeIdenticalTo(c, t) ? c : isTypeSubtypeOf(t, c) ? t : neverType);
27119
27136
// If no constituents are directly related, create intersections for any generic constituents that
27120
27137
// are related by constraint.
27121
27138
return directlyRelated.flags & TypeFlags.Never ?
@@ -36529,7 +36546,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
36529
36546
}
36530
36547
else {
36531
36548
checkAssignmentOperator(rightType);
36532
- return getRegularTypeOfObjectLiteral( rightType) ;
36549
+ return rightType;
36533
36550
}
36534
36551
case SyntaxKind.CommaToken:
36535
36552
if (!compilerOptions.allowUnreachableCode && isSideEffectFree(left) && !isIndirectCall(left.parent as BinaryExpression)) {
0 commit comments