diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f15fd70378ea7..6a5ce9f13222e 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1500,6 +1500,8 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { var lastGetCombinedModifierFlagsNode: Declaration | undefined; var lastGetCombinedModifierFlagsResult = ModifierFlags.None; + var checkTypeRelatedToDepth = 0; + var checkTypeRelatedToCurrentlyVisitingMap: Map | undefined; // for public members that accept a Node or one of its subtypes, we must guard against // synthetic nodes created during transformations by calling `getParseTreeNode`. // for most of these, we perform the guard only on `checker` to avoid any possible @@ -3563,7 +3565,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { // try to resolve name in /*1*/ which is used in variable position, // we want to check for block-scoped if ( - errorLocation && + result && errorLocation && (meaning & SymbolFlags.BlockScopedVariable || ((meaning & SymbolFlags.Class || meaning & SymbolFlags.Enum) && (meaning & SymbolFlags.Value) === SymbolFlags.Value)) ) { @@ -20767,7 +20769,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { /** * See signatureRelatedTo, compareSignaturesIdentical */ - function compareSignaturesRelated(source: Signature, target: Signature, checkMode: SignatureCheckMode, reportErrors: boolean, errorReporter: ErrorReporter | undefined, incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined, compareTypes: TypeComparer, reportUnreliableMarkers: TypeMapper | undefined): Ternary { + function compareSignaturesRelated(source: Signature, target: Signature, checkMode: SignatureCheckMode, reportErrors: boolean, errorReporter: ErrorReporter | undefined, incompatibleErrorReporter: ((source: Type, target: Type) => void) | undefined, compareTypes: TypeComparer, reportUnreliableMarkers: TypeMapper | undefined, compareTypesUnilaterally = false): Ternary { // TODO (drosen): De-duplicate code between related functions. if (source === target) { return Ternary.True; @@ -20845,9 +20847,18 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { const targetSig = checkMode & SignatureCheckMode.Callback || isInstantiatedGenericParameter(target, i) ? undefined : getSingleCallSignature(getNonNullableType(targetType)); const callbacks = sourceSig && targetSig && !getTypePredicateOfSignature(sourceSig) && !getTypePredicateOfSignature(targetSig) && getTypeFacts(sourceType, TypeFacts.IsUndefinedOrNull) === getTypeFacts(targetType, TypeFacts.IsUndefinedOrNull); - let related = callbacks ? - compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers) : - !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); + let related: Ternary; + if (callbacks) { + related = compareSignaturesRelated(targetSig, sourceSig, (checkMode & SignatureCheckMode.StrictArity) | (strictVariance ? SignatureCheckMode.StrictCallback : SignatureCheckMode.BivariantCallback), reportErrors, errorReporter, incompatibleErrorReporter, compareTypes, reportUnreliableMarkers); + } + else { + if (!compareTypesUnilaterally) { + related = !(checkMode & SignatureCheckMode.Callback) && !strictVariance && compareTypes(sourceType, targetType, /*reportErrors*/ false) || compareTypes(targetType, sourceType, reportErrors); + } + else { + related = compareTypes(sourceType, targetType, reportErrors); + } + } // With strict arity, (x: number | undefined) => void is a subtype of (x?: number | undefined) => void if (related && checkMode & SignatureCheckMode.StrictArity && i >= getMinArgumentCount(source) && i < getMinArgumentCount(target) && compareTypes(sourceType, targetType, /*reportErrors*/ false)) { related = Ternary.False; @@ -21240,6 +21251,24 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert(relation !== identityRelation || !errorNode, "no error reporting in identity checking"); + const visitingKey = getRelationKey(source, target, /*intersectionState*/ IntersectionState.None, relation, /*ignoreConstraints*/ false); + if (checkTypeRelatedToDepth === 0) { + checkTypeRelatedToCurrentlyVisitingMap = new Map(); + } + if (!errorNode && !headMessage) { + let got = checkTypeRelatedToCurrentlyVisitingMap!.get(visitingKey); + const maxSameKey = 1; + if (got && got >= maxSameKey) { + relation.set(visitingKey, RelationComparisonResult.Succeeded); + return true; + } + else { + if (!got) got = 1; + else got = got + 1; + checkTypeRelatedToCurrentlyVisitingMap!.set(visitingKey, got); + } + } + checkTypeRelatedToDepth++; const result = isRelatedTo(source, target, RecursionFlags.Both, /*reportErrors*/ !!errorNode, headMessage); if (incompatibleStack) { reportIncompatibleStack(); @@ -21294,6 +21323,17 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { Debug.assert(!!errorOutputContainer.errors, "missed opportunity to interact with error."); } + checkTypeRelatedToDepth--; + if (checkTypeRelatedToDepth === 0) { + checkTypeRelatedToCurrentlyVisitingMap = undefined; + } + else { + const got = checkTypeRelatedToCurrentlyVisitingMap!.get(visitingKey); + if (got) { + if (got === 1) checkTypeRelatedToCurrentlyVisitingMap!.delete(visitingKey); + else checkTypeRelatedToCurrentlyVisitingMap!.set(visitingKey, got - 1); + } + } return result !== Ternary.False; function resetErrorInfo(saved: ReturnType) { @@ -21880,6 +21920,127 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return prop.valueDeclaration && container.valueDeclaration && prop.valueDeclaration.parent === container.valueDeclaration; } + /** + * Check that an overload instance is assignable to an intersection target. + * Algorithm + * + * Let s[i], i in 0...Ns-1 be the source overloads. + * + * Let t[j], j in 0...Nt-1 be the target intersection member types. + * + * Let t[j][k], k in 0...Ntj-1 be the target overloads in type t[j]. + * + * Check that the source has an into mapping to the target: + * + * SourceDomainMatch(i):== + * For some j,k exists IdentitiyRelation(Parameters,Parameters)===true + * + * SourceRangeMatch(i):== + * Let rt be the union of ReturnTypes for all j,k s.t. Parameters assignable to Parameters + * ReturnTypes assignable to rt + * + * TargetDomainMatch(t[j,k]):== + * For some i exists IdentitiyRelation(Parameters,Parameters)===true + * + * Passing conditions: + * - For all i, SourceDomainMatch(i)===true + * - For all i, SourceRangeMatch(i)===true + * - For all j,k, TargetDomainMatch(t[j][k])===true + */ + function checkOverloadsRelatedToIntersection(source: Type, target: Type, _reportErrors: boolean): { computed: boolean; ternary: Ternary; } { + const sourceSignatures = getSignaturesOfType(source, SignatureKind.Call); + const constructSignatureToString = (signature: Signature, forceReturnType?: Type) => { + const origReturnType = signature.resolvedReturnType; + signature.resolvedReturnType = forceReturnType; + const str = signatureToString(signature, /*enclosingDeclaration*/ undefined, TypeFormatFlags.WriteArrowStyleSignature, SignatureKind.Call); + signature.resolvedReturnType = origReturnType; + return str; + }; + const mapAssignedToBy: Map> = new Map>(); + const failed = sourceSignatures.some((ssig, _si) => { + if (getReturnTypeOfSignature(ssig) === neverType) return false; + const accum = { + hadMatch: false, + gReturn: neverType as Type, + gReturnAllVoid: true, + }; + const matchedTargetSigs: Signature[] = []; + (target as IntersectionType).types.forEach((targetMember, _tti) => { + const targetSignatures = getSignaturesOfType(targetMember, SignatureKind.Call); + targetSignatures.forEach((tsig, _ti) => { + const targetReturnType = getReturnTypeOfSignature(tsig); + if ( + compareSignaturesRelated( + ssig, + tsig, + SignatureCheckMode.None | SignatureCheckMode.IgnoreReturnTypes, + /*reportErrors*/ false, + /*errorReporter*/ undefined, + /*incompatibleErrorReporter*/ undefined, + compareTypesIdentical, // compareTypesAssignable, + /*reportUnreliableMarkers*/ undefined, + /*compareTypesUnilaterally*/ true, + ) === Ternary.True + ) { + accum.hadMatch = true; + if (targetReturnType !== voidType) { + accum.gReturn = getUnionType([accum.gReturn, targetReturnType]); + accum.gReturnAllVoid = false; + } + matchedTargetSigs.push(tsig); + let mtti = mapAssignedToBy.get(_tti); + if (!mtti) { + mtti = new Map(); + mapAssignedToBy.set(_tti, mtti); + } + const setsi = mtti.get(_ti); + if (!setsi) { + mtti.set(_ti, true); + } + } + }); + }); + if (!accum.hadMatch) { + if (_reportErrors) { + resetErrorInfo({ skipParentCounter: 0 } as ReturnType); + reportError(Diagnostics.Parameters_of_signature_0_are_not_assignable_to_the_parameters_of_any_signature_in_type_1, constructSignatureToString(ssig), typeToString(target)); + } + return true; // failed + } + else { + const returnType = getReturnTypeOfSignature(ssig); + if (!accum.gReturnAllVoid && !isTypeAssignableTo(returnType, accum.gReturn)) { + if (_reportErrors) { + resetErrorInfo({ skipParentCounter: 0 } as ReturnType); + reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, typeToString(returnType), typeToString(accum.gReturn)); + const strset = new Set(); + matchedTargetSigs.forEach(tsig => strset.add(constructSignatureToString(tsig))); + const strarr: string[] = []; + strset.forEach(tstr => strarr.push(tstr)); + reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, constructSignatureToString(ssig), strarr.join(" | ")); + } + return true; // failed + } + } + }); + if (failed) return { computed: true, ternary: Ternary.False }; + const failed2 = (target as IntersectionType).types.some((targetMember, _tti) => { + const mtti = mapAssignedToBy.get(_tti); + const targetSignatures = getSignaturesOfType(targetMember, SignatureKind.Call); + return targetSignatures.some((tsig, _ti) => { + if (!mtti || !mtti.get(_ti)) { + if (_reportErrors) { + resetErrorInfo({ skipParentCounter: 0 } as ReturnType); + reportError(Diagnostics.There_is_no_signature_in_type_0_such_that_its_parameters_are_assignable_to_the_parameters_of_signature_1, typeToString(source), constructSignatureToString(tsig, anyType)); + reportError(Diagnostics.Type_0_is_not_assignable_to_type_1, typeToString(source), typeToString(targetMember)); + } + return true; + } + }); + }); + if (failed2) return { computed: true, ternary: Ternary.False }; + return { computed: true, ternary: Ternary.True }; + } function unionOrIntersectionRelatedTo(source: Type, target: Type, reportErrors: boolean, intersectionState: IntersectionState): Ternary { // Note that these checks are specifically ordered to produce correct results. In particular, // we need to deconstruct unions before intersections (because unions are always at the top), @@ -21909,7 +22070,33 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker { return typeRelatedToSomeType(getRegularTypeOfObjectLiteral(source), target as UnionType, reportErrors && !(source.flags & TypeFlags.Primitive) && !(target.flags & TypeFlags.Primitive), intersectionState); } if (target.flags & TypeFlags.Intersection) { - return typeRelatedToEachType(source, target as IntersectionType, reportErrors, IntersectionState.Target); + const result1 = typeRelatedToEachType(source, target as IntersectionType, reportErrors, IntersectionState.Target); + + if (result1 === Ternary.False) { + /** + * [cph] Existing code checks that source supports target, but not that source fits within target. + */ + // const target0 = (target as IntersectionType).types[0]; + const sourceSignatures = getSignaturesOfType(source, SignatureKind.Call); + if ( + sourceSignatures.every(sourceSig => { + return !sourceSig.typeParameters; + }) + ) { + if ( + source.flags & TypeFlags.Object && getSignaturesOfType(source, SignatureKind.Call).length > 1 + // && target.flags & TypeFlags.Object && getSignaturesOfType(target0, SignatureKind.Call).length > 1 // already known to be intersection type + ) { + const { computed, ternary } = checkOverloadsRelatedToIntersection(source, target as IntersectionType, reportErrors); + if (computed) { + Debug.assert(ternary === Ternary.True || ternary === Ternary.False); + return ternary; + } + // if not computed falls through to the reult of the general case: typeRelatedToEachType + } + } + } + return result1; } // Source is an intersection. For the comparable relation, if the target is a primitive type we hoist the // constraints of all non-primitive types in the source into a new intersection. We do this because the diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 344d92f054f58..d7186b820038a 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -7988,5 +7988,13 @@ "'await using' statements cannot be used inside a class static block.": { "category": "Error", "code": 18054 + }, + "There is no signature in type {0} such that its parameters are assignable to the parameters of signature {1}": { + "category": "Error", + "code": 18055 + }, + "Parameters of signature {0} are not assignable to the parameters of any signature in type {1}": { + "category": "Error", + "code": 18056 } } diff --git a/tests/baselines/reference/checkOverloadsRelatedToIntersection.errors.txt b/tests/baselines/reference/checkOverloadsRelatedToIntersection.errors.txt new file mode 100644 index 0000000000000..39cd23279d85a --- /dev/null +++ b/tests/baselines/reference/checkOverloadsRelatedToIntersection.errors.txt @@ -0,0 +1,552 @@ +-57087-101.ts(48,5): error TS2345: Argument of type '{ (x: 1): 1; (x: 2): 2; (x: 3): "3"; }' is not assignable to parameter of type '((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")'. + Parameters of signature (x: 1) => 1 are not assignable to the parameters of any signature in type ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3") +-57087-104.ts(101,6): error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'A & B & C'. + Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'A'. + There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any +-57087-104.ts(102,6): error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'A & C & B'. + Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'A'. + There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any +-57087-104.ts(103,6): error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'B & A & C'. + Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'A'. + There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any +-57087-104.ts(104,6): error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'B & C & A'. + Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'C'. + There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any +-57087-104.ts(105,6): error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'C & A & B'. + Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'C'. + There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any +-57087-104.ts(106,6): error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'C & B & A'. + Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'C'. + There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any +-57087-104.ts(109,6): error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'W'. + Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'A & B & C'. +-57087-105.ts(55,5): error TS2345: Argument of type '{ (x: A): string; (x: C): number; (x: B): string; }' is not assignable to parameter of type '{ (x: A): string; (x: B): 1; } & { (x: C): number; (x: B): "1"; }'. + Type '(x: B) => string' is not assignable to type '(x: B) => 1 | (x: B) => "1"'. + Type 'string' is not assignable to type '1 | "1"'. +-57087-105.ts(68,5): error TS2345: Argument of type '{ (x: C): number; (x: B): 1; }' is not assignable to parameter of type '{ (x: A): string; (x: B): 1; } & { (x: C): number; (x: B): "1"; }'. + Type '{ (x: C): number; (x: B): 1; }' is not assignable to type '{ (x: A): string; (x: B): 1; }'. + There is no signature in type { (x: C): number; (x: B): 1; } such that its parameters are assignable to the parameters of signature (x: A) => any +-57087-105.ts(81,5): error TS2345: Argument of type '{ (x: { a?: string | undefined; }): string; (x: C): number; (x: B): 1; }' is not assignable to parameter of type '{ (x: A): string; (x: B): 1; } & { (x: C): number; (x: B): "1"; }'. + Parameters of signature (x: { a?: string | undefined; }) => string are not assignable to the parameters of any signature in type { (x: A): string; (x: B): 1; } & { (x: C): number; (x: B): "1"; } +-57087-131.ts(29,6): error TS1360: Type '{ (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "221"; (x: 2, y: 1): "221"; }' does not satisfy the expected type 'Garg31A & Garg31B'. + Type '(x: 2, y: 2) => "221"' is not assignable to type '(x: 2, y: 2) => "222"'. + Type '"221"' is not assignable to type '"222"'. +-57087-131.ts(37,6): error TS1360: Type '{ (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; (x: 1, y: 2): "221"; }' does not satisfy the expected type 'Garg31A & Garg31B'. + Parameters of signature (x: 1, y: 2) => "221" are not assignable to the parameters of any signature in type Garg31A & Garg31B +-57087-131.ts(45,6): error TS1360: Type '{ (): "01"; (x?: 1 | undefined, y?: 1 | undefined): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; }' does not satisfy the expected type 'Garg31A & Garg31B'. + Type '(x?: 1 | undefined, y?: 1 | undefined) => "211"' is not assignable to type '() => "01" | () => "02"'. + Type '"211"' is not assignable to type '"01" | "02"'. +-57087-131.ts(53,6): error TS1360: Type '{ (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; }' does not satisfy the expected type 'Garg31A & Garg31B'. + Type '{ (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; }' is not assignable to type 'Garg31A'. + There is no signature in type { (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } such that its parameters are assignable to the parameters of signature () => any + + +==== -57087-101.ts (1 errors) ==== + /**********************/ + + namespace ns0 { + interface FMap { + f:(x:T)=>R + g(f:(x:T)=>R):R; + } + declare const x1: FMap<1|2,1|2>; + x1.g(x1.f); // no error + declare const x2: FMap<2|3,"2"|"3">; + x2.g(x2.f); // no error + const x = Math.random() < 0.5 ? x1 : x2; + x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" + + /* + * Exact expansion of x.g, with the intersection of the two function types expanded. + * Catch-all with "never" return is not required to pass the test. + */ + function ft0(x:1|2):1|2; + function ft0(x:2|3):"2"|"3"; + function ft0(x:1|2|3){ + if (x!==3) return x1.f(x); + else return x2.f(x); + } + x.g(ft0); // should not be error + + /* + * Condtion for passing are: + * (a1) Every source overload is matches at least one target overload + * (a2) Every target overload is matched by at least one souce overload + * where "matching" is defined as + * (b1) the target result is void OR the target result and source result overlap // should be source result subset of target result ? + * (b2) the target and source parameters match identically up to the number of required source parameters. + * This test case fails because: source (x:1) is not identical to target (x:1|2) or (x:2|3) + */ + + function ft1(x:1):1; + function ft1(x:2):2; + function ft1(x:3):"3"; + function ft1(x:1|2|3) { + switch (x) { + case 1: return 1; + case 2: return 2; + case 3: return "3"; + } + throw "unexpected error" + } + x.g(ft1); // should be error + ~~~ +!!! error TS2345: Argument of type '{ (x: 1): 1; (x: 2): 2; (x: 3): "3"; }' is not assignable to parameter of type '((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")'. +!!! error TS2345: Parameters of signature (x: 1) => 1 are not assignable to the parameters of any signature in type ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3") + + + } + + + /**********************/ +==== -57087-102.ts (0 errors) ==== + namespace ns1 { + interface FMap { + f:(x:T)=>R + g(f:(x:T)=>R):R; + } + declare const x1: FMap<1|2,1|2>; + x1.g(x1.f); // no error + declare const x2: FMap<2|3,"2"|"3">; + x2.g(x2.f); // no error + const x = Math.random() < 0.5 ? x1 : x2; + x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" + + + /** + * The following function ft3 should fail. However, it currently does not + * The new code only handles cases that fail the in the original code. + * However, using such long overload chains is not desireable anyway - so we don't need to fix this? + * Maybe fail on when the number of source overloads is greater than the total number of target overloads? + */ + + function ft3(x:1):"3"; // should cause x.g(ft3) to error + function ft3(x:3):"3"; + function ft3(x:2):2|"2"; + function ft3(x:1|2):1|2; // (4) identical to x1.f + function ft3(x:2|3):"2"|"3"; // (5) identical to x2.f + function ft3(x:1|2|3){ + if (x===1) return x1.f(x); + if (x===3) return x2.f(x); + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); + } + x.g(ft3); // should error (but currently doesn't) + + /** + * The following function ft4 should not fail, and it currently does not. + * However, using such long overload chains is not friendly anyway, so it is irrelevant. + */ + + function ft4(x:1):1; + function ft4(x:3):"3"; + function ft4(x:2):2|"2"; + function ft4(x:1|2):1|2; // (4) identical to x1.f + function ft4(x:2|3):"2"|"3"; // (5) identical to x2.f + function ft4(x:1|2|3){ + if (x===1) return x1.f(x); + if (x===3) return x2.f(x); + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); + } + x.g(ft4); // should not error + + + } + + + /**********************/ +==== -57087-104.ts (7 errors) ==== + namespace ns2 { + interface C { + (x:1):"1"; + (x:2):"20"; + (x:number):number | "1" | "20"; + }; + interface B { + (x:2):"2" + (x:3):"30" + (x:number):number | "2" | "30"; + }; + interface A { + (x:3):"3" + (x:1):"10" + (x:number):number | "3" | "10"; + }; + + type W = (A & B & C)|(A & C & B)|(B & A & C)|(B & C & A)|(C & A & B)|(C & B & A); + + /* + * Scenario: + * (1) Overloads: Usng fully expanded domain support for C & B & A, so that all errors are detected at compile time + * (2) Implementation: + * - Note extra lines added to make the function signature compatible with the implementation + * Disadvatage: More verbosity in number of overloads and in implementation. + * Number of overloads could impact compile time, and makes life harder for downstream users of the function + */ + function foo2(x:1):"1"; + function foo2(x:2):"20"; + function foo2(x:number):number; + function foo2(x:2):"2" + function foo2(x:3):"30" + function foo2(x:number):number; + function foo2(x:3):"3" + function foo2(x:1):"10" + function foo2(x:number):number; + function foo2(x:number){ + if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + // (*) These nonsense unused extra lines need to be added to make the function signature compatible with the implementation + if (x===1) return "10"; + if (x===2) return "20"; + if (x===3) return "30"; + return x; + } + + foo2 satisfies A & B & C; // should satisfy + foo2 satisfies A & C & B; // should satisfy + foo2 satisfies B & A & C; // should satisfy + foo2 satisfies B & C & A; // should satisfy + foo2 satisfies C & A & B; // should satisfy + foo2 satisfies C & B & A; // should satisfy + foo2 satisfies W; // should satisfy + + + /* + * Scenario: Select some overloads from the orignal set of overloads. + * Advantages: + * - Less verbosity in number of overloads + * - Less verbosity in implementation + * Number of overloads could impact compile time, and makes life harder for downstream users of the function + */ + function foo1(x:1):"1"; + function foo1(x:2):"2"; + function foo1(x:3):"3"; + function foo1(x:number):number; + function foo1(x:number){ + if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + return x; + } + + // The `&`-intersection operator result should be independent of the order of it's operands. + foo1 satisfies A & B & C; // should not error + foo1 satisfies A & C & B; // should not error + foo1 satisfies B & A & C; // should not error + foo1 satisfies B & C & A; // should not error + foo1 satisfies C & A & B; // should not error + foo1 satisfies C & B & A; // should not error + foo1 satisfies W; // should not error + + /* + */ + + //function foo3(x:1):"1"; // Omitted domain support should cause satisfies error + function foo3(x:2):"2"; + function foo3(x:3):"3"; + function foo3(x:number):number; + function foo3(x:number): number | "1" | "2" | "3"{ + //if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + return x; + // In this case, a final throw "unexpected error" would never be reached anyway. + // if (typeof x === "number") return x; // pointless + // throw "unexpected error"; + } + + foo3 satisfies A & B & C; // should be error + ~~~~~~~~~ +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'A & B & C'. +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'A'. +!!! error TS1360: There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any + foo3 satisfies A & C & B; // should be error + ~~~~~~~~~ +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'A & C & B'. +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'A'. +!!! error TS1360: There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any + foo3 satisfies B & A & C; // should be error + ~~~~~~~~~ +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'B & A & C'. +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'A'. +!!! error TS1360: There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any + foo3 satisfies B & C & A; // should be error + ~~~~~~~~~ +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'B & C & A'. +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'C'. +!!! error TS1360: There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any + foo3 satisfies C & A & B; // should be error + ~~~~~~~~~ +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'C & A & B'. +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'C'. +!!! error TS1360: There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any + foo3 satisfies C & B & A; // should be error + ~~~~~~~~~ +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'C & B & A'. +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'C'. +!!! error TS1360: There is no signature in type { (x: 2): "2"; (x: 3): "3"; (x: number): number; } such that its parameters are assignable to the parameters of signature (x: 1) => any + + + foo3 satisfies W; // should be error + ~~~~~~~~~ +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' does not satisfy the expected type 'W'. +!!! error TS1360: Type '{ (x: 2): "2"; (x: 3): "3"; (x: number): number; }' is not assignable to type 'A & B & C'. + + + } + + + /**********************/ +==== -57087-105.ts (3 errors) ==== + namespace ns3 { + type A = { a: string }; + type B = { b: 1 }; + type C = { c: number }; + + + interface X1 { + f(x:A):string + f(x:B):1 + g(f: X1["f"],arg:A|B):()=>ReturnType + } + interface X2 { + f(x:C):number + f(x:B):"1"; + g(f: X2["f"],arg:C|B):()=>ReturnType + } + + declare const x1: X1; + declare const arg1: A|B; + x1.g(x1.f,arg1); // should be no error + declare const x2: X2; + declare const arg2: C|B; + x2.g(x2.f,arg2); // should be no error + const x = Math.random() < 0.5 ? x1 : x2; + x.g; + const arg = Math.random() < 0.5 ? arg1 : arg2; + + + + type ArgCastType = (A & C) | (A & B) | (B & C); + + + function ftw(x:A):string; + function ftw(x:C):number; + function ftw(x:B):1; + function ftw(x: A|B|C) { + if ("a" in x) return x.a; + if ("c" in x) return x.c; + return 1; + } + + // The necessity of the argument cast is a separate issue! + x.g(ftw,arg as any as any as ArgCastType); // should not be error + + function ftx(x:A):string; + function ftx(x:C):number; + function ftx(x:B):string; // should cause x.g(ft2) to error + function ftx(x: A|B|C) { + if ("a" in x) return x.a; + if ("c" in x) return x.c; + return x.b; + } + + // The necessity of the argument cast is a separate issue! + x.g(ftx,arg as any as any as ArgCastType); // should be error + ~~~ +!!! error TS2345: Argument of type '{ (x: A): string; (x: C): number; (x: B): string; }' is not assignable to parameter of type '{ (x: A): string; (x: B): 1; } & { (x: C): number; (x: B): "1"; }'. +!!! error TS2345: Type '(x: B) => string' is not assignable to type '(x: B) => 1 | (x: B) => "1"'. +!!! error TS2345: Type 'string' is not assignable to type '1 | "1"'. + + //function fty(x:A):string; // should cause x.g(ft2) to error + function fty(x:C):number; + function fty(x:B):1; + function fty(x: {a?: string, c?: number, b?: 1|"1"}) { + if (x.a) return x.a; + if (x.c) return x.c; + if (x.b) return x.b; + throw "unexpected error" + } + + // The necessity of the argument cast is a separate issue! + x.g(fty,arg as any as any as ArgCastType); // should be error + ~~~ +!!! error TS2345: Argument of type '{ (x: C): number; (x: B): 1; }' is not assignable to parameter of type '{ (x: A): string; (x: B): 1; } & { (x: C): number; (x: B): "1"; }'. +!!! error TS2345: Type '{ (x: C): number; (x: B): 1; }' is not assignable to type '{ (x: A): string; (x: B): 1; }'. +!!! error TS2345: There is no signature in type { (x: C): number; (x: B): 1; } such that its parameters are assignable to the parameters of signature (x: A) => any + + function ftz(x:{a?:string}):string; // should cause x.g(ft2) to error + function ftz(x:C):number; + function ftz(x:B):1; + function ftz(x: {a?: string, c?: number, b?: 1|"1"}) { + if (x.a) return x.a; + if (x.c) return x.c; + if (x.b) return x.b; + throw "unexpected error" + } + + // The necessity of the argument cast is a separate issue! + x.g(ftz,arg as any as any as ArgCastType); // should be error + ~~~ +!!! error TS2345: Argument of type '{ (x: { a?: string | undefined; }): string; (x: C): number; (x: B): 1; }' is not assignable to parameter of type '{ (x: A): string; (x: B): 1; } & { (x: C): number; (x: B): "1"; }'. +!!! error TS2345: Parameters of signature (x: { a?: string | undefined; }) => string are not assignable to the parameters of any signature in type { (x: A): string; (x: B): 1; } & { (x: C): number; (x: B): "1"; } + + } + + + /**********************/ +==== -57087-131.ts (4 errors) ==== + namespace ns4 { + interface Garg31A { + (): "01"; + (x:1, y:1): "211" + }; + declare const g31A: Garg31A; + + interface Garg31B { + (): "02"; + (x:2, y:2): "222"; + (x:2, y:1): "221" + }; + declare const g31B: Garg31B; + + declare const f31a: { + (): "01"; + (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; + }; + f31a satisfies Garg31A & Garg31B; // should satisfy + + declare const f31b: { + (): "01"; + (x: 1, y: 1): "211"; + (x: 2, y: 2): "221" /*should cause "f31b satisfies" to error */; + (x: 2, y: 1): "221"; + }; + f31b satisfies Garg31A & Garg31B; // should not satisfy + ~~~~~~~~~ +!!! error TS1360: Type '{ (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "221"; (x: 2, y: 1): "221"; }' does not satisfy the expected type 'Garg31A & Garg31B'. +!!! error TS1360: Type '(x: 2, y: 2) => "221"' is not assignable to type '(x: 2, y: 2) => "222"'. +!!! error TS1360: Type '"221"' is not assignable to type '"222"'. + + declare const f31c: { + (): "01"; (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; + (x: 1, y: 2): "221" /*should cause "f31c satisfies" to error */; + }; + f31c satisfies Garg31A & Garg31B; // should not satisfy + ~~~~~~~~~ +!!! error TS1360: Type '{ (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; (x: 1, y: 2): "221"; }' does not satisfy the expected type 'Garg31A & Garg31B'. +!!! error TS1360: Parameters of signature (x: 1, y: 2) => "221" are not assignable to the parameters of any signature in type Garg31A & Garg31B + + declare const f31d:{ + (): "01"; + (x?: 1, y?: 1): "211"; /*should cause "f31d satisfies" to error */ + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; + }; + f31d satisfies Garg31A & Garg31B; // should not satisfy + ~~~~~~~~~ +!!! error TS1360: Type '{ (): "01"; (x?: 1 | undefined, y?: 1 | undefined): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; }' does not satisfy the expected type 'Garg31A & Garg31B'. +!!! error TS1360: Type '(x?: 1 | undefined, y?: 1 | undefined) => "211"' is not assignable to type '() => "01" | () => "02"'. +!!! error TS1360: Type '"211"' is not assignable to type '"01" | "02"'. + + declare const f31f: { + //(): "01"; // missing domain support cannot be detected at compiler time with final never + (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; + } + f31f satisfies Garg31A & Garg31B; // should not satisfy + ~~~~~~~~~ +!!! error TS1360: Type '{ (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; }' does not satisfy the expected type 'Garg31A & Garg31B'. +!!! error TS1360: Type '{ (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; }' is not assignable to type 'Garg31A'. +!!! error TS1360: There is no signature in type { (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } such that its parameters are assignable to the parameters of signature () => any + + + + } + + + /**********************/ +==== -57087-133.ts (0 errors) ==== + namespace ns5 { + interface Garg33A { + (): "01"; + (x:1, y?:1): "111"; + (...args: [...1[]]): "101"; + }; + interface Garg33B { + (): "02"; + (x:1, y?:1): "211"; + (...args:1[]): "201"; + (x:2, y?:any): "221" + }; + + declare const f33a: { + (): "02"; + (x:1, y?:1): "211"; + (...args:1[]): "201"; + (x:2, y?:any): "221" + } + f33b satisfies Garg33A & Garg33B; // should satisfy + // because (...args: [...1[]]):=>"101" === (...args:1[]) => "201"; + + + declare const f33b: { + (): "02"; + (x:1, y?:1): "211"; + (...args: [...1[]]): "101"; + (...args:1[]): "201"; + (x:2, y?:any): "221" + } + f33b satisfies Garg33A & Garg33B; // should satisfy + + declare const f33c: { + (x:2, y?:any): "221" + (...args:1[]): "201"; + (...args: [...1[]]): "101"; + (x:1, y?:1): "211"; + (): "02"; + } + f33c satisfies Garg33A & Garg33B; // should satisfy (even though reversed order of overloads) + + + + } + + + /**********************/ +==== -57087-135.ts (0 errors) ==== + namespace ns6 { + interface Garg35A { + ({x,y}:{x?:1, y?:Garg35B}): "A1" + ({x,y}:{x?:2, y?:Garg35C}): "A2" + }; + interface Garg35B { + ({x,y}:{x?:2, y?:Garg35C}): "B1" + ({x,y}:{x:2, y?:Garg35A}): "B2"; + }; + interface Garg35C { + ({x,y}:{x:2, y?:Garg35A}): "C1"; + ({x,y}:{x?:1, y?:Garg35B}): "C2" + }; + + declare const f35a: { + ({x,y}:{x?:1, y?:Garg35B}): "A1" + ({x,y}:{x:2, y?:Garg35A}): "B2"; + ({x,y}:{x?:2, y?:Garg35C}): "A2" + } + f35a satisfies Garg35A & Garg35B & Garg35C; // should satisfy + + declare const f35b: { + ({x,y}:{x:2, y?:Garg35A}): "C1"; + ({x,y}:{x?:1, y?:Garg35B}): "C2" + ({x,y}:{x?:2, y?:Garg35C}): "B1" + } + f35b satisfies typeof f35a & Garg35A & Garg35B & Garg35C; // should satisfy + + + } \ No newline at end of file diff --git a/tests/baselines/reference/checkOverloadsRelatedToIntersection.js b/tests/baselines/reference/checkOverloadsRelatedToIntersection.js new file mode 100644 index 0000000000000..8ae632d13b5bd --- /dev/null +++ b/tests/baselines/reference/checkOverloadsRelatedToIntersection.js @@ -0,0 +1,661 @@ +//// [tests/cases/compiler/checkOverloadsRelatedToIntersection.ts] //// + +//// [-57087-101.ts] +/**********************/ + +namespace ns0 { +interface FMap { + f:(x:T)=>R + g(f:(x:T)=>R):R; +} +declare const x1: FMap<1|2,1|2>; +x1.g(x1.f); // no error +declare const x2: FMap<2|3,"2"|"3">; +x2.g(x2.f); // no error +const x = Math.random() < 0.5 ? x1 : x2; +x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" + +/* + * Exact expansion of x.g, with the intersection of the two function types expanded. + * Catch-all with "never" return is not required to pass the test. + */ +function ft0(x:1|2):1|2; +function ft0(x:2|3):"2"|"3"; +function ft0(x:1|2|3){ + if (x!==3) return x1.f(x); + else return x2.f(x); +} +x.g(ft0); // should not be error + +/* + * Condtion for passing are: + * (a1) Every source overload is matches at least one target overload + * (a2) Every target overload is matched by at least one souce overload + * where "matching" is defined as + * (b1) the target result is void OR the target result and source result overlap // should be source result subset of target result ? + * (b2) the target and source parameters match identically up to the number of required source parameters. + * This test case fails because: source (x:1) is not identical to target (x:1|2) or (x:2|3) + */ + +function ft1(x:1):1; +function ft1(x:2):2; +function ft1(x:3):"3"; +function ft1(x:1|2|3) { + switch (x) { + case 1: return 1; + case 2: return 2; + case 3: return "3"; + } + throw "unexpected error" +} +x.g(ft1); // should be error + + +} + + +/**********************/ +//// [-57087-102.ts] +namespace ns1 { +interface FMap { + f:(x:T)=>R + g(f:(x:T)=>R):R; +} +declare const x1: FMap<1|2,1|2>; +x1.g(x1.f); // no error +declare const x2: FMap<2|3,"2"|"3">; +x2.g(x2.f); // no error +const x = Math.random() < 0.5 ? x1 : x2; +x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" + + +/** + * The following function ft3 should fail. However, it currently does not + * The new code only handles cases that fail the in the original code. + * However, using such long overload chains is not desireable anyway - so we don't need to fix this? + * Maybe fail on when the number of source overloads is greater than the total number of target overloads? + */ + +function ft3(x:1):"3"; // should cause x.g(ft3) to error +function ft3(x:3):"3"; +function ft3(x:2):2|"2"; +function ft3(x:1|2):1|2; // (4) identical to x1.f +function ft3(x:2|3):"2"|"3"; // (5) identical to x2.f +function ft3(x:1|2|3){ + if (x===1) return x1.f(x); + if (x===3) return x2.f(x); + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); +} +x.g(ft3); // should error (but currently doesn't) + +/** + * The following function ft4 should not fail, and it currently does not. + * However, using such long overload chains is not friendly anyway, so it is irrelevant. + */ + +function ft4(x:1):1; +function ft4(x:3):"3"; +function ft4(x:2):2|"2"; +function ft4(x:1|2):1|2; // (4) identical to x1.f +function ft4(x:2|3):"2"|"3"; // (5) identical to x2.f +function ft4(x:1|2|3){ + if (x===1) return x1.f(x); + if (x===3) return x2.f(x); + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); +} +x.g(ft4); // should not error + + +} + + +/**********************/ +//// [-57087-104.ts] +namespace ns2 { +interface C { + (x:1):"1"; + (x:2):"20"; + (x:number):number | "1" | "20"; +}; +interface B { + (x:2):"2" + (x:3):"30" + (x:number):number | "2" | "30"; +}; +interface A { + (x:3):"3" + (x:1):"10" + (x:number):number | "3" | "10"; +}; + +type W = (A & B & C)|(A & C & B)|(B & A & C)|(B & C & A)|(C & A & B)|(C & B & A); + +/* +* Scenario: +* (1) Overloads: Usng fully expanded domain support for C & B & A, so that all errors are detected at compile time +* (2) Implementation: +* - Note extra lines added to make the function signature compatible with the implementation +* Disadvatage: More verbosity in number of overloads and in implementation. +* Number of overloads could impact compile time, and makes life harder for downstream users of the function +*/ +function foo2(x:1):"1"; +function foo2(x:2):"20"; +function foo2(x:number):number; +function foo2(x:2):"2" +function foo2(x:3):"30" +function foo2(x:number):number; +function foo2(x:3):"3" +function foo2(x:1):"10" +function foo2(x:number):number; +function foo2(x:number){ + if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + // (*) These nonsense unused extra lines need to be added to make the function signature compatible with the implementation + if (x===1) return "10"; + if (x===2) return "20"; + if (x===3) return "30"; + return x; +} + +foo2 satisfies A & B & C; // should satisfy +foo2 satisfies A & C & B; // should satisfy +foo2 satisfies B & A & C; // should satisfy +foo2 satisfies B & C & A; // should satisfy +foo2 satisfies C & A & B; // should satisfy +foo2 satisfies C & B & A; // should satisfy +foo2 satisfies W; // should satisfy + + +/* +* Scenario: Select some overloads from the orignal set of overloads. +* Advantages: +* - Less verbosity in number of overloads +* - Less verbosity in implementation +* Number of overloads could impact compile time, and makes life harder for downstream users of the function +*/ +function foo1(x:1):"1"; +function foo1(x:2):"2"; +function foo1(x:3):"3"; +function foo1(x:number):number; +function foo1(x:number){ + if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + return x; +} + +// The `&`-intersection operator result should be independent of the order of it's operands. +foo1 satisfies A & B & C; // should not error +foo1 satisfies A & C & B; // should not error +foo1 satisfies B & A & C; // should not error +foo1 satisfies B & C & A; // should not error +foo1 satisfies C & A & B; // should not error +foo1 satisfies C & B & A; // should not error +foo1 satisfies W; // should not error + +/* +*/ + +//function foo3(x:1):"1"; // Omitted domain support should cause satisfies error +function foo3(x:2):"2"; +function foo3(x:3):"3"; +function foo3(x:number):number; +function foo3(x:number): number | "1" | "2" | "3"{ + //if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + return x; + // In this case, a final throw "unexpected error" would never be reached anyway. + // if (typeof x === "number") return x; // pointless + // throw "unexpected error"; +} + +foo3 satisfies A & B & C; // should be error +foo3 satisfies A & C & B; // should be error +foo3 satisfies B & A & C; // should be error +foo3 satisfies B & C & A; // should be error +foo3 satisfies C & A & B; // should be error +foo3 satisfies C & B & A; // should be error + + +foo3 satisfies W; // should be error + + +} + + +/**********************/ +//// [-57087-105.ts] +namespace ns3 { +type A = { a: string }; +type B = { b: 1 }; +type C = { c: number }; + + +interface X1 { + f(x:A):string + f(x:B):1 + g(f: X1["f"],arg:A|B):()=>ReturnType +} +interface X2 { + f(x:C):number + f(x:B):"1"; + g(f: X2["f"],arg:C|B):()=>ReturnType +} + +declare const x1: X1; +declare const arg1: A|B; +x1.g(x1.f,arg1); // should be no error +declare const x2: X2; +declare const arg2: C|B; +x2.g(x2.f,arg2); // should be no error +const x = Math.random() < 0.5 ? x1 : x2; +x.g; +const arg = Math.random() < 0.5 ? arg1 : arg2; + + + +type ArgCastType = (A & C) | (A & B) | (B & C); + + +function ftw(x:A):string; +function ftw(x:C):number; +function ftw(x:B):1; +function ftw(x: A|B|C) { + if ("a" in x) return x.a; + if ("c" in x) return x.c; + return 1; +} + +// The necessity of the argument cast is a separate issue! +x.g(ftw,arg as any as any as ArgCastType); // should not be error + +function ftx(x:A):string; +function ftx(x:C):number; +function ftx(x:B):string; // should cause x.g(ft2) to error +function ftx(x: A|B|C) { + if ("a" in x) return x.a; + if ("c" in x) return x.c; + return x.b; +} + +// The necessity of the argument cast is a separate issue! +x.g(ftx,arg as any as any as ArgCastType); // should be error + +//function fty(x:A):string; // should cause x.g(ft2) to error +function fty(x:C):number; +function fty(x:B):1; +function fty(x: {a?: string, c?: number, b?: 1|"1"}) { + if (x.a) return x.a; + if (x.c) return x.c; + if (x.b) return x.b; + throw "unexpected error" +} + +// The necessity of the argument cast is a separate issue! +x.g(fty,arg as any as any as ArgCastType); // should be error + +function ftz(x:{a?:string}):string; // should cause x.g(ft2) to error +function ftz(x:C):number; +function ftz(x:B):1; +function ftz(x: {a?: string, c?: number, b?: 1|"1"}) { + if (x.a) return x.a; + if (x.c) return x.c; + if (x.b) return x.b; + throw "unexpected error" +} + +// The necessity of the argument cast is a separate issue! +x.g(ftz,arg as any as any as ArgCastType); // should be error + +} + + +/**********************/ +//// [-57087-131.ts] +namespace ns4 { +interface Garg31A { + (): "01"; + (x:1, y:1): "211" +}; +declare const g31A: Garg31A; + +interface Garg31B { + (): "02"; + (x:2, y:2): "222"; + (x:2, y:1): "221" +}; +declare const g31B: Garg31B; + +declare const f31a: { + (): "01"; + (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; +}; +f31a satisfies Garg31A & Garg31B; // should satisfy + +declare const f31b: { + (): "01"; + (x: 1, y: 1): "211"; + (x: 2, y: 2): "221" /*should cause "f31b satisfies" to error */; + (x: 2, y: 1): "221"; +}; +f31b satisfies Garg31A & Garg31B; // should not satisfy + +declare const f31c: { + (): "01"; (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; + (x: 1, y: 2): "221" /*should cause "f31c satisfies" to error */; +}; +f31c satisfies Garg31A & Garg31B; // should not satisfy + +declare const f31d:{ + (): "01"; + (x?: 1, y?: 1): "211"; /*should cause "f31d satisfies" to error */ + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; +}; +f31d satisfies Garg31A & Garg31B; // should not satisfy + +declare const f31f: { + //(): "01"; // missing domain support cannot be detected at compiler time with final never + (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; +} +f31f satisfies Garg31A & Garg31B; // should not satisfy + + + +} + + +/**********************/ +//// [-57087-133.ts] +namespace ns5 { +interface Garg33A { + (): "01"; + (x:1, y?:1): "111"; + (...args: [...1[]]): "101"; +}; +interface Garg33B { + (): "02"; + (x:1, y?:1): "211"; + (...args:1[]): "201"; + (x:2, y?:any): "221" +}; + +declare const f33a: { + (): "02"; + (x:1, y?:1): "211"; + (...args:1[]): "201"; + (x:2, y?:any): "221" +} +f33b satisfies Garg33A & Garg33B; // should satisfy +// because (...args: [...1[]]):=>"101" === (...args:1[]) => "201"; + + +declare const f33b: { + (): "02"; + (x:1, y?:1): "211"; + (...args: [...1[]]): "101"; + (...args:1[]): "201"; + (x:2, y?:any): "221" +} +f33b satisfies Garg33A & Garg33B; // should satisfy + +declare const f33c: { + (x:2, y?:any): "221" + (...args:1[]): "201"; + (...args: [...1[]]): "101"; + (x:1, y?:1): "211"; + (): "02"; +} +f33c satisfies Garg33A & Garg33B; // should satisfy (even though reversed order of overloads) + + + +} + + +/**********************/ +//// [-57087-135.ts] +namespace ns6 { +interface Garg35A { + ({x,y}:{x?:1, y?:Garg35B}): "A1" + ({x,y}:{x?:2, y?:Garg35C}): "A2" +}; +interface Garg35B { + ({x,y}:{x?:2, y?:Garg35C}): "B1" + ({x,y}:{x:2, y?:Garg35A}): "B2"; +}; +interface Garg35C { + ({x,y}:{x:2, y?:Garg35A}): "C1"; + ({x,y}:{x?:1, y?:Garg35B}): "C2" +}; + +declare const f35a: { + ({x,y}:{x?:1, y?:Garg35B}): "A1" + ({x,y}:{x:2, y?:Garg35A}): "B2"; + ({x,y}:{x?:2, y?:Garg35C}): "A2" +} +f35a satisfies Garg35A & Garg35B & Garg35C; // should satisfy + +declare const f35b: { + ({x,y}:{x:2, y?:Garg35A}): "C1"; + ({x,y}:{x?:1, y?:Garg35B}): "C2" + ({x,y}:{x?:2, y?:Garg35C}): "B1" +} +f35b satisfies typeof f35a & Garg35A & Garg35B & Garg35C; // should satisfy + + +} + +//// [-57087-101.js] +"use strict"; +/**********************/ +var ns0; +(function (ns0) { + x1.g(x1.f); // no error + x2.g(x2.f); // no error + const x = Math.random() < 0.5 ? x1 : x2; + x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" + function ft0(x) { + if (x !== 3) + return x1.f(x); + else + return x2.f(x); + } + x.g(ft0); // should not be error + function ft1(x) { + switch (x) { + case 1: return 1; + case 2: return 2; + case 3: return "3"; + } + throw "unexpected error"; + } + x.g(ft1); // should be error +})(ns0 || (ns0 = {})); +/**********************/ +//// [-57087-102.js] +"use strict"; +var ns1; +(function (ns1) { + x1.g(x1.f); // no error + x2.g(x2.f); // no error + const x = Math.random() < 0.5 ? x1 : x2; + x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" + function ft3(x) { + if (x === 1) + return x1.f(x); + if (x === 3) + return x2.f(x); + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); + } + x.g(ft3); // should error (but currently doesn't) + function ft4(x) { + if (x === 1) + return x1.f(x); + if (x === 3) + return x2.f(x); + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); + } + x.g(ft4); // should not error +})(ns1 || (ns1 = {})); +/**********************/ +//// [-57087-104.js] +"use strict"; +var ns2; +(function (ns2) { + ; + ; + ; + function foo2(x) { + if (x === 1) + return "1"; + if (x === 2) + return "2"; + if (x === 3) + return "3"; + // (*) These nonsense unused extra lines need to be added to make the function signature compatible with the implementation + if (x === 1) + return "10"; + if (x === 2) + return "20"; + if (x === 3) + return "30"; + return x; + } + foo2; // should satisfy + foo2; // should satisfy + foo2; // should satisfy + foo2; // should satisfy + foo2; // should satisfy + foo2; // should satisfy + foo2; // should satisfy + function foo1(x) { + if (x === 1) + return "1"; + if (x === 2) + return "2"; + if (x === 3) + return "3"; + return x; + } + // The `&`-intersection operator result should be independent of the order of it's operands. + foo1; // should not error + foo1; // should not error + foo1; // should not error + foo1; // should not error + foo1; // should not error + foo1; // should not error + foo1; // should not error + function foo3(x) { + //if (x===1) return "1"; + if (x === 2) + return "2"; + if (x === 3) + return "3"; + return x; + // In this case, a final throw "unexpected error" would never be reached anyway. + // if (typeof x === "number") return x; // pointless + // throw "unexpected error"; + } + foo3; // should be error + foo3; // should be error + foo3; // should be error + foo3; // should be error + foo3; // should be error + foo3; // should be error + foo3; // should be error +})(ns2 || (ns2 = {})); +/**********************/ +//// [-57087-105.js] +"use strict"; +var ns3; +(function (ns3) { + x1.g(x1.f, arg1); // should be no error + x2.g(x2.f, arg2); // should be no error + const x = Math.random() < 0.5 ? x1 : x2; + x.g; + const arg = Math.random() < 0.5 ? arg1 : arg2; + function ftw(x) { + if ("a" in x) + return x.a; + if ("c" in x) + return x.c; + return 1; + } + // The necessity of the argument cast is a separate issue! + x.g(ftw, arg); // should not be error + function ftx(x) { + if ("a" in x) + return x.a; + if ("c" in x) + return x.c; + return x.b; + } + // The necessity of the argument cast is a separate issue! + x.g(ftx, arg); // should be error + function fty(x) { + if (x.a) + return x.a; + if (x.c) + return x.c; + if (x.b) + return x.b; + throw "unexpected error"; + } + // The necessity of the argument cast is a separate issue! + x.g(fty, arg); // should be error + function ftz(x) { + if (x.a) + return x.a; + if (x.c) + return x.c; + if (x.b) + return x.b; + throw "unexpected error"; + } + // The necessity of the argument cast is a separate issue! + x.g(ftz, arg); // should be error +})(ns3 || (ns3 = {})); +/**********************/ +//// [-57087-131.js] +"use strict"; +var ns4; +(function (ns4) { + ; + ; + f31a; // should satisfy + f31b; // should not satisfy + f31c; // should not satisfy + f31d; // should not satisfy + f31f; // should not satisfy +})(ns4 || (ns4 = {})); +/**********************/ +//// [-57087-133.js] +"use strict"; +var ns5; +(function (ns5) { + ; + ; + f33b; // should satisfy + f33b; // should satisfy + f33c; // should satisfy (even though reversed order of overloads) +})(ns5 || (ns5 = {})); +/**********************/ +//// [-57087-135.js] +"use strict"; +var ns6; +(function (ns6) { + ; + ; + ; + f35a; // should satisfy + f35b; // should satisfy +})(ns6 || (ns6 = {})); diff --git a/tests/baselines/reference/checkOverloadsRelatedToIntersection.symbols b/tests/baselines/reference/checkOverloadsRelatedToIntersection.symbols new file mode 100644 index 0000000000000..55d4e6dcbd703 --- /dev/null +++ b/tests/baselines/reference/checkOverloadsRelatedToIntersection.symbols @@ -0,0 +1,1403 @@ +//// [tests/cases/compiler/checkOverloadsRelatedToIntersection.ts] //// + +=== -57087-101.ts === +/**********************/ + +namespace ns0 { +>ns0 : Symbol(ns0, Decl(-57087-101.ts, 0, 0)) + +interface FMap { +>FMap : Symbol(FMap, Decl(-57087-101.ts, 2, 15)) +>T : Symbol(T, Decl(-57087-101.ts, 3, 15)) +>R : Symbol(R, Decl(-57087-101.ts, 3, 17)) + + f:(x:T)=>R +>f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) +>x : Symbol(x, Decl(-57087-101.ts, 4, 7)) +>T : Symbol(T, Decl(-57087-101.ts, 3, 15)) +>R : Symbol(R, Decl(-57087-101.ts, 3, 17)) + + g(f:(x:T)=>R):R; +>g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14)) +>f : Symbol(f, Decl(-57087-101.ts, 5, 6)) +>x : Symbol(x, Decl(-57087-101.ts, 5, 9)) +>T : Symbol(T, Decl(-57087-101.ts, 3, 15)) +>R : Symbol(R, Decl(-57087-101.ts, 3, 17)) +>R : Symbol(R, Decl(-57087-101.ts, 3, 17)) +} +declare const x1: FMap<1|2,1|2>; +>x1 : Symbol(x1, Decl(-57087-101.ts, 7, 13)) +>FMap : Symbol(FMap, Decl(-57087-101.ts, 2, 15)) + +x1.g(x1.f); // no error +>x1.g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14)) +>x1 : Symbol(x1, Decl(-57087-101.ts, 7, 13)) +>g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14)) +>x1.f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) +>x1 : Symbol(x1, Decl(-57087-101.ts, 7, 13)) +>f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) + +declare const x2: FMap<2|3,"2"|"3">; +>x2 : Symbol(x2, Decl(-57087-101.ts, 9, 13)) +>FMap : Symbol(FMap, Decl(-57087-101.ts, 2, 15)) + +x2.g(x2.f); // no error +>x2.g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14)) +>x2 : Symbol(x2, Decl(-57087-101.ts, 9, 13)) +>g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14)) +>x2.f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) +>x2 : Symbol(x2, Decl(-57087-101.ts, 9, 13)) +>f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) + +const x = Math.random() < 0.5 ? x1 : x2; +>x : Symbol(x, Decl(-57087-101.ts, 11, 5)) +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>x1 : Symbol(x1, Decl(-57087-101.ts, 7, 13)) +>x2 : Symbol(x2, Decl(-57087-101.ts, 9, 13)) + +x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" +>x.g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14), Decl(-57087-101.ts, 4, 14)) +>x : Symbol(x, Decl(-57087-101.ts, 11, 5)) +>g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14), Decl(-57087-101.ts, 4, 14)) + +/* + * Exact expansion of x.g, with the intersection of the two function types expanded. + * Catch-all with "never" return is not required to pass the test. + */ +function ft0(x:1|2):1|2; +>ft0 : Symbol(ft0, Decl(-57087-101.ts, 12, 4), Decl(-57087-101.ts, 18, 24), Decl(-57087-101.ts, 19, 28)) +>x : Symbol(x, Decl(-57087-101.ts, 18, 13)) + +function ft0(x:2|3):"2"|"3"; +>ft0 : Symbol(ft0, Decl(-57087-101.ts, 12, 4), Decl(-57087-101.ts, 18, 24), Decl(-57087-101.ts, 19, 28)) +>x : Symbol(x, Decl(-57087-101.ts, 19, 13)) + +function ft0(x:1|2|3){ +>ft0 : Symbol(ft0, Decl(-57087-101.ts, 12, 4), Decl(-57087-101.ts, 18, 24), Decl(-57087-101.ts, 19, 28)) +>x : Symbol(x, Decl(-57087-101.ts, 20, 13)) + + if (x!==3) return x1.f(x); +>x : Symbol(x, Decl(-57087-101.ts, 20, 13)) +>x1.f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) +>x1 : Symbol(x1, Decl(-57087-101.ts, 7, 13)) +>f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) +>x : Symbol(x, Decl(-57087-101.ts, 20, 13)) + + else return x2.f(x); +>x2.f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) +>x2 : Symbol(x2, Decl(-57087-101.ts, 9, 13)) +>f : Symbol(FMap.f, Decl(-57087-101.ts, 3, 21)) +>x : Symbol(x, Decl(-57087-101.ts, 20, 13)) +} +x.g(ft0); // should not be error +>x.g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14), Decl(-57087-101.ts, 4, 14)) +>x : Symbol(x, Decl(-57087-101.ts, 11, 5)) +>g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14), Decl(-57087-101.ts, 4, 14)) +>ft0 : Symbol(ft0, Decl(-57087-101.ts, 12, 4), Decl(-57087-101.ts, 18, 24), Decl(-57087-101.ts, 19, 28)) + +/* + * Condtion for passing are: + * (a1) Every source overload is matches at least one target overload + * (a2) Every target overload is matched by at least one souce overload + * where "matching" is defined as + * (b1) the target result is void OR the target result and source result overlap // should be source result subset of target result ? + * (b2) the target and source parameters match identically up to the number of required source parameters. + * This test case fails because: source (x:1) is not identical to target (x:1|2) or (x:2|3) + */ + +function ft1(x:1):1; +>ft1 : Symbol(ft1, Decl(-57087-101.ts, 24, 9), Decl(-57087-101.ts, 36, 20), Decl(-57087-101.ts, 37, 20), Decl(-57087-101.ts, 38, 22)) +>x : Symbol(x, Decl(-57087-101.ts, 36, 13)) + +function ft1(x:2):2; +>ft1 : Symbol(ft1, Decl(-57087-101.ts, 24, 9), Decl(-57087-101.ts, 36, 20), Decl(-57087-101.ts, 37, 20), Decl(-57087-101.ts, 38, 22)) +>x : Symbol(x, Decl(-57087-101.ts, 37, 13)) + +function ft1(x:3):"3"; +>ft1 : Symbol(ft1, Decl(-57087-101.ts, 24, 9), Decl(-57087-101.ts, 36, 20), Decl(-57087-101.ts, 37, 20), Decl(-57087-101.ts, 38, 22)) +>x : Symbol(x, Decl(-57087-101.ts, 38, 13)) + +function ft1(x:1|2|3) { +>ft1 : Symbol(ft1, Decl(-57087-101.ts, 24, 9), Decl(-57087-101.ts, 36, 20), Decl(-57087-101.ts, 37, 20), Decl(-57087-101.ts, 38, 22)) +>x : Symbol(x, Decl(-57087-101.ts, 39, 13)) + + switch (x) { +>x : Symbol(x, Decl(-57087-101.ts, 39, 13)) + + case 1: return 1; + case 2: return 2; + case 3: return "3"; + } + throw "unexpected error" +} +x.g(ft1); // should be error +>x.g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14), Decl(-57087-101.ts, 4, 14)) +>x : Symbol(x, Decl(-57087-101.ts, 11, 5)) +>g : Symbol(FMap.g, Decl(-57087-101.ts, 4, 14), Decl(-57087-101.ts, 4, 14)) +>ft1 : Symbol(ft1, Decl(-57087-101.ts, 24, 9), Decl(-57087-101.ts, 36, 20), Decl(-57087-101.ts, 37, 20), Decl(-57087-101.ts, 38, 22)) + + +} + + +/**********************/ +=== -57087-102.ts === +namespace ns1 { +>ns1 : Symbol(ns1, Decl(-57087-102.ts, 0, 0)) + +interface FMap { +>FMap : Symbol(FMap, Decl(-57087-102.ts, 0, 15)) +>T : Symbol(T, Decl(-57087-102.ts, 1, 15)) +>R : Symbol(R, Decl(-57087-102.ts, 1, 17)) + + f:(x:T)=>R +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 2, 7)) +>T : Symbol(T, Decl(-57087-102.ts, 1, 15)) +>R : Symbol(R, Decl(-57087-102.ts, 1, 17)) + + g(f:(x:T)=>R):R; +>g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14)) +>f : Symbol(f, Decl(-57087-102.ts, 3, 6)) +>x : Symbol(x, Decl(-57087-102.ts, 3, 9)) +>T : Symbol(T, Decl(-57087-102.ts, 1, 15)) +>R : Symbol(R, Decl(-57087-102.ts, 1, 17)) +>R : Symbol(R, Decl(-57087-102.ts, 1, 17)) +} +declare const x1: FMap<1|2,1|2>; +>x1 : Symbol(x1, Decl(-57087-102.ts, 5, 13)) +>FMap : Symbol(FMap, Decl(-57087-102.ts, 0, 15)) + +x1.g(x1.f); // no error +>x1.g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14)) +>x1 : Symbol(x1, Decl(-57087-102.ts, 5, 13)) +>g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14)) +>x1.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x1 : Symbol(x1, Decl(-57087-102.ts, 5, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) + +declare const x2: FMap<2|3,"2"|"3">; +>x2 : Symbol(x2, Decl(-57087-102.ts, 7, 13)) +>FMap : Symbol(FMap, Decl(-57087-102.ts, 0, 15)) + +x2.g(x2.f); // no error +>x2.g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14)) +>x2 : Symbol(x2, Decl(-57087-102.ts, 7, 13)) +>g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14)) +>x2.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x2 : Symbol(x2, Decl(-57087-102.ts, 7, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) + +const x = Math.random() < 0.5 ? x1 : x2; +>x : Symbol(x, Decl(-57087-102.ts, 9, 5)) +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>x1 : Symbol(x1, Decl(-57087-102.ts, 5, 13)) +>x2 : Symbol(x2, Decl(-57087-102.ts, 7, 13)) + +x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" +>x.g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14), Decl(-57087-102.ts, 2, 14)) +>x : Symbol(x, Decl(-57087-102.ts, 9, 5)) +>g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14), Decl(-57087-102.ts, 2, 14)) + + +/** + * The following function ft3 should fail. However, it currently does not + * The new code only handles cases that fail the in the original code. + * However, using such long overload chains is not desireable anyway - so we don't need to fix this? + * Maybe fail on when the number of source overloads is greater than the total number of target overloads? + */ + +function ft3(x:1):"3"; // should cause x.g(ft3) to error +>ft3 : Symbol(ft3, Decl(-57087-102.ts, 10, 4), Decl(-57087-102.ts, 20, 22), Decl(-57087-102.ts, 21, 22), Decl(-57087-102.ts, 22, 24), Decl(-57087-102.ts, 23, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 20, 13)) + +function ft3(x:3):"3"; +>ft3 : Symbol(ft3, Decl(-57087-102.ts, 10, 4), Decl(-57087-102.ts, 20, 22), Decl(-57087-102.ts, 21, 22), Decl(-57087-102.ts, 22, 24), Decl(-57087-102.ts, 23, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 21, 13)) + +function ft3(x:2):2|"2"; +>ft3 : Symbol(ft3, Decl(-57087-102.ts, 10, 4), Decl(-57087-102.ts, 20, 22), Decl(-57087-102.ts, 21, 22), Decl(-57087-102.ts, 22, 24), Decl(-57087-102.ts, 23, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 22, 13)) + +function ft3(x:1|2):1|2; // (4) identical to x1.f +>ft3 : Symbol(ft3, Decl(-57087-102.ts, 10, 4), Decl(-57087-102.ts, 20, 22), Decl(-57087-102.ts, 21, 22), Decl(-57087-102.ts, 22, 24), Decl(-57087-102.ts, 23, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 23, 13)) + +function ft3(x:2|3):"2"|"3"; // (5) identical to x2.f +>ft3 : Symbol(ft3, Decl(-57087-102.ts, 10, 4), Decl(-57087-102.ts, 20, 22), Decl(-57087-102.ts, 21, 22), Decl(-57087-102.ts, 22, 24), Decl(-57087-102.ts, 23, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 24, 13)) + +function ft3(x:1|2|3){ +>ft3 : Symbol(ft3, Decl(-57087-102.ts, 10, 4), Decl(-57087-102.ts, 20, 22), Decl(-57087-102.ts, 21, 22), Decl(-57087-102.ts, 22, 24), Decl(-57087-102.ts, 23, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 25, 13)) + + if (x===1) return x1.f(x); +>x : Symbol(x, Decl(-57087-102.ts, 25, 13)) +>x1.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x1 : Symbol(x1, Decl(-57087-102.ts, 5, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 25, 13)) + + if (x===3) return x2.f(x); +>x : Symbol(x, Decl(-57087-102.ts, 25, 13)) +>x2.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x2 : Symbol(x2, Decl(-57087-102.ts, 7, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 25, 13)) + + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>x1.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x1 : Symbol(x1, Decl(-57087-102.ts, 5, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 25, 13)) +>x2.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x2 : Symbol(x2, Decl(-57087-102.ts, 7, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 25, 13)) +} +x.g(ft3); // should error (but currently doesn't) +>x.g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14), Decl(-57087-102.ts, 2, 14)) +>x : Symbol(x, Decl(-57087-102.ts, 9, 5)) +>g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14), Decl(-57087-102.ts, 2, 14)) +>ft3 : Symbol(ft3, Decl(-57087-102.ts, 10, 4), Decl(-57087-102.ts, 20, 22), Decl(-57087-102.ts, 21, 22), Decl(-57087-102.ts, 22, 24), Decl(-57087-102.ts, 23, 24) ... and 1 more) + +/** + * The following function ft4 should not fail, and it currently does not. + * However, using such long overload chains is not friendly anyway, so it is irrelevant. + */ + +function ft4(x:1):1; +>ft4 : Symbol(ft4, Decl(-57087-102.ts, 30, 9), Decl(-57087-102.ts, 37, 20), Decl(-57087-102.ts, 38, 22), Decl(-57087-102.ts, 39, 24), Decl(-57087-102.ts, 40, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 37, 13)) + +function ft4(x:3):"3"; +>ft4 : Symbol(ft4, Decl(-57087-102.ts, 30, 9), Decl(-57087-102.ts, 37, 20), Decl(-57087-102.ts, 38, 22), Decl(-57087-102.ts, 39, 24), Decl(-57087-102.ts, 40, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 38, 13)) + +function ft4(x:2):2|"2"; +>ft4 : Symbol(ft4, Decl(-57087-102.ts, 30, 9), Decl(-57087-102.ts, 37, 20), Decl(-57087-102.ts, 38, 22), Decl(-57087-102.ts, 39, 24), Decl(-57087-102.ts, 40, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 39, 13)) + +function ft4(x:1|2):1|2; // (4) identical to x1.f +>ft4 : Symbol(ft4, Decl(-57087-102.ts, 30, 9), Decl(-57087-102.ts, 37, 20), Decl(-57087-102.ts, 38, 22), Decl(-57087-102.ts, 39, 24), Decl(-57087-102.ts, 40, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 40, 13)) + +function ft4(x:2|3):"2"|"3"; // (5) identical to x2.f +>ft4 : Symbol(ft4, Decl(-57087-102.ts, 30, 9), Decl(-57087-102.ts, 37, 20), Decl(-57087-102.ts, 38, 22), Decl(-57087-102.ts, 39, 24), Decl(-57087-102.ts, 40, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 41, 13)) + +function ft4(x:1|2|3){ +>ft4 : Symbol(ft4, Decl(-57087-102.ts, 30, 9), Decl(-57087-102.ts, 37, 20), Decl(-57087-102.ts, 38, 22), Decl(-57087-102.ts, 39, 24), Decl(-57087-102.ts, 40, 24) ... and 1 more) +>x : Symbol(x, Decl(-57087-102.ts, 42, 13)) + + if (x===1) return x1.f(x); +>x : Symbol(x, Decl(-57087-102.ts, 42, 13)) +>x1.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x1 : Symbol(x1, Decl(-57087-102.ts, 5, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 42, 13)) + + if (x===3) return x2.f(x); +>x : Symbol(x, Decl(-57087-102.ts, 42, 13)) +>x2.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x2 : Symbol(x2, Decl(-57087-102.ts, 7, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 42, 13)) + + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>x1.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x1 : Symbol(x1, Decl(-57087-102.ts, 5, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 42, 13)) +>x2.f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x2 : Symbol(x2, Decl(-57087-102.ts, 7, 13)) +>f : Symbol(FMap.f, Decl(-57087-102.ts, 1, 21)) +>x : Symbol(x, Decl(-57087-102.ts, 42, 13)) +} +x.g(ft4); // should not error +>x.g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14), Decl(-57087-102.ts, 2, 14)) +>x : Symbol(x, Decl(-57087-102.ts, 9, 5)) +>g : Symbol(FMap.g, Decl(-57087-102.ts, 2, 14), Decl(-57087-102.ts, 2, 14)) +>ft4 : Symbol(ft4, Decl(-57087-102.ts, 30, 9), Decl(-57087-102.ts, 37, 20), Decl(-57087-102.ts, 38, 22), Decl(-57087-102.ts, 39, 24), Decl(-57087-102.ts, 40, 24) ... and 1 more) + + +} + + +/**********************/ +=== -57087-104.ts === +namespace ns2 { +>ns2 : Symbol(ns2, Decl(-57087-104.ts, 0, 0)) + +interface C { +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) + + (x:1):"1"; +>x : Symbol(x, Decl(-57087-104.ts, 2, 3)) + + (x:2):"20"; +>x : Symbol(x, Decl(-57087-104.ts, 3, 3)) + + (x:number):number | "1" | "20"; +>x : Symbol(x, Decl(-57087-104.ts, 4, 3)) + +}; +interface B { +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) + + (x:2):"2" +>x : Symbol(x, Decl(-57087-104.ts, 7, 3)) + + (x:3):"30" +>x : Symbol(x, Decl(-57087-104.ts, 8, 3)) + + (x:number):number | "2" | "30"; +>x : Symbol(x, Decl(-57087-104.ts, 9, 3)) + +}; +interface A { +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) + + (x:3):"3" +>x : Symbol(x, Decl(-57087-104.ts, 12, 3)) + + (x:1):"10" +>x : Symbol(x, Decl(-57087-104.ts, 13, 3)) + + (x:number):number | "3" | "10"; +>x : Symbol(x, Decl(-57087-104.ts, 14, 3)) + +}; + +type W = (A & B & C)|(A & C & B)|(B & A & C)|(B & C & A)|(C & A & B)|(C & B & A); +>W : Symbol(W, Decl(-57087-104.ts, 15, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) + +/* +* Scenario: +* (1) Overloads: Usng fully expanded domain support for C & B & A, so that all errors are detected at compile time +* (2) Implementation: +* - Note extra lines added to make the function signature compatible with the implementation +* Disadvatage: More verbosity in number of overloads and in implementation. +* Number of overloads could impact compile time, and makes life harder for downstream users of the function +*/ +function foo2(x:1):"1"; +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 27, 14)) + +function foo2(x:2):"20"; +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 28, 14)) + +function foo2(x:number):number; +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 29, 14)) + +function foo2(x:2):"2" +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 30, 14)) + +function foo2(x:3):"30" +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 31, 14)) + +function foo2(x:number):number; +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 32, 14)) + +function foo2(x:3):"3" +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 33, 14)) + +function foo2(x:1):"10" +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 34, 14)) + +function foo2(x:number):number; +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 35, 14)) + +function foo2(x:number){ +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>x : Symbol(x, Decl(-57087-104.ts, 36, 14)) + + if (x===1) return "1"; +>x : Symbol(x, Decl(-57087-104.ts, 36, 14)) + + if (x===2) return "2"; +>x : Symbol(x, Decl(-57087-104.ts, 36, 14)) + + if (x===3) return "3"; +>x : Symbol(x, Decl(-57087-104.ts, 36, 14)) + + // (*) These nonsense unused extra lines need to be added to make the function signature compatible with the implementation + if (x===1) return "10"; +>x : Symbol(x, Decl(-57087-104.ts, 36, 14)) + + if (x===2) return "20"; +>x : Symbol(x, Decl(-57087-104.ts, 36, 14)) + + if (x===3) return "30"; +>x : Symbol(x, Decl(-57087-104.ts, 36, 14)) + + return x; +>x : Symbol(x, Decl(-57087-104.ts, 36, 14)) +} + +foo2 satisfies A & B & C; // should satisfy +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) + +foo2 satisfies A & C & B; // should satisfy +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) + +foo2 satisfies B & A & C; // should satisfy +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) + +foo2 satisfies B & C & A; // should satisfy +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) + +foo2 satisfies C & A & B; // should satisfy +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) + +foo2 satisfies C & B & A; // should satisfy +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) + +foo2 satisfies W; // should satisfy +>foo2 : Symbol(foo2, Decl(-57087-104.ts, 17, 81), Decl(-57087-104.ts, 27, 23), Decl(-57087-104.ts, 28, 24), Decl(-57087-104.ts, 29, 31), Decl(-57087-104.ts, 30, 22) ... and 5 more) +>W : Symbol(W, Decl(-57087-104.ts, 15, 2)) + + +/* +* Scenario: Select some overloads from the orignal set of overloads. +* Advantages: +* - Less verbosity in number of overloads +* - Less verbosity in implementation +* Number of overloads could impact compile time, and makes life harder for downstream users of the function +*/ +function foo1(x:1):"1"; +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 63, 14)) + +function foo1(x:2):"2"; +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 64, 14)) + +function foo1(x:3):"3"; +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 65, 14)) + +function foo1(x:number):number; +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 66, 14)) + +function foo1(x:number){ +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 67, 14)) + + if (x===1) return "1"; +>x : Symbol(x, Decl(-57087-104.ts, 67, 14)) + + if (x===2) return "2"; +>x : Symbol(x, Decl(-57087-104.ts, 67, 14)) + + if (x===3) return "3"; +>x : Symbol(x, Decl(-57087-104.ts, 67, 14)) + + return x; +>x : Symbol(x, Decl(-57087-104.ts, 67, 14)) +} + +// The `&`-intersection operator result should be independent of the order of it's operands. +foo1 satisfies A & B & C; // should not error +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) + +foo1 satisfies A & C & B; // should not error +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) + +foo1 satisfies B & A & C; // should not error +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) + +foo1 satisfies B & C & A; // should not error +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) + +foo1 satisfies C & A & B; // should not error +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) + +foo1 satisfies C & B & A; // should not error +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) + +foo1 satisfies W; // should not error +>foo1 : Symbol(foo1, Decl(-57087-104.ts, 53, 17), Decl(-57087-104.ts, 63, 23), Decl(-57087-104.ts, 64, 23), Decl(-57087-104.ts, 65, 23), Decl(-57087-104.ts, 66, 31)) +>W : Symbol(W, Decl(-57087-104.ts, 15, 2)) + +/* +*/ + +//function foo3(x:1):"1"; // Omitted domain support should cause satisfies error +function foo3(x:2):"2"; +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 87, 14)) + +function foo3(x:3):"3"; +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 88, 14)) + +function foo3(x:number):number; +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 89, 14)) + +function foo3(x:number): number | "1" | "2" | "3"{ +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>x : Symbol(x, Decl(-57087-104.ts, 90, 14)) + + //if (x===1) return "1"; + if (x===2) return "2"; +>x : Symbol(x, Decl(-57087-104.ts, 90, 14)) + + if (x===3) return "3"; +>x : Symbol(x, Decl(-57087-104.ts, 90, 14)) + + return x; +>x : Symbol(x, Decl(-57087-104.ts, 90, 14)) + + // In this case, a final throw "unexpected error" would never be reached anyway. + // if (typeof x === "number") return x; // pointless + // throw "unexpected error"; +} + +foo3 satisfies A & B & C; // should be error +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) + +foo3 satisfies A & C & B; // should be error +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) + +foo3 satisfies B & A & C; // should be error +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) + +foo3 satisfies B & C & A; // should be error +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) + +foo3 satisfies C & A & B; // should be error +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) + +foo3 satisfies C & B & A; // should be error +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>C : Symbol(C, Decl(-57087-104.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-104.ts, 5, 2)) +>A : Symbol(A, Decl(-57087-104.ts, 10, 2)) + + +foo3 satisfies W; // should be error +>foo3 : Symbol(foo3, Decl(-57087-104.ts, 81, 17), Decl(-57087-104.ts, 87, 23), Decl(-57087-104.ts, 88, 23), Decl(-57087-104.ts, 89, 31)) +>W : Symbol(W, Decl(-57087-104.ts, 15, 2)) + + +} + + +/**********************/ +=== -57087-105.ts === +namespace ns3 { +>ns3 : Symbol(ns3, Decl(-57087-105.ts, 0, 0)) + +type A = { a: string }; +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) +>a : Symbol(a, Decl(-57087-105.ts, 1, 10)) + +type B = { b: 1 }; +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) +>b : Symbol(b, Decl(-57087-105.ts, 2, 10)) + +type C = { c: number }; +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) +>c : Symbol(c, Decl(-57087-105.ts, 3, 10)) + + +interface X1 { +>X1 : Symbol(X1, Decl(-57087-105.ts, 3, 23)) + + f(x:A):string +>f : Symbol(X1.f, Decl(-57087-105.ts, 6, 14), Decl(-57087-105.ts, 7, 17)) +>x : Symbol(x, Decl(-57087-105.ts, 7, 6)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) + + f(x:B):1 +>f : Symbol(X1.f, Decl(-57087-105.ts, 6, 14), Decl(-57087-105.ts, 7, 17)) +>x : Symbol(x, Decl(-57087-105.ts, 8, 6)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) + + g(f: X1["f"],arg:A|B):()=>ReturnType +>g : Symbol(X1.g, Decl(-57087-105.ts, 8, 12)) +>f : Symbol(f, Decl(-57087-105.ts, 9, 6)) +>X1 : Symbol(X1, Decl(-57087-105.ts, 3, 23)) +>arg : Symbol(arg, Decl(-57087-105.ts, 9, 17)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) +>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --)) +>X1 : Symbol(X1, Decl(-57087-105.ts, 3, 23)) +} +interface X2 { +>X2 : Symbol(X2, Decl(-57087-105.ts, 10, 1)) + + f(x:C):number +>f : Symbol(X2.f, Decl(-57087-105.ts, 11, 14), Decl(-57087-105.ts, 12, 17)) +>x : Symbol(x, Decl(-57087-105.ts, 12, 6)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) + + f(x:B):"1"; +>f : Symbol(X2.f, Decl(-57087-105.ts, 11, 14), Decl(-57087-105.ts, 12, 17)) +>x : Symbol(x, Decl(-57087-105.ts, 13, 6)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) + + g(f: X2["f"],arg:C|B):()=>ReturnType +>g : Symbol(X2.g, Decl(-57087-105.ts, 13, 15)) +>f : Symbol(f, Decl(-57087-105.ts, 14, 6)) +>X2 : Symbol(X2, Decl(-57087-105.ts, 10, 1)) +>arg : Symbol(arg, Decl(-57087-105.ts, 14, 17)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) +>ReturnType : Symbol(ReturnType, Decl(lib.es5.d.ts, --, --)) +>X2 : Symbol(X2, Decl(-57087-105.ts, 10, 1)) +} + +declare const x1: X1; +>x1 : Symbol(x1, Decl(-57087-105.ts, 17, 13)) +>X1 : Symbol(X1, Decl(-57087-105.ts, 3, 23)) + +declare const arg1: A|B; +>arg1 : Symbol(arg1, Decl(-57087-105.ts, 18, 13)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) + +x1.g(x1.f,arg1); // should be no error +>x1.g : Symbol(X1.g, Decl(-57087-105.ts, 8, 12)) +>x1 : Symbol(x1, Decl(-57087-105.ts, 17, 13)) +>g : Symbol(X1.g, Decl(-57087-105.ts, 8, 12)) +>x1.f : Symbol(X1.f, Decl(-57087-105.ts, 6, 14), Decl(-57087-105.ts, 7, 17)) +>x1 : Symbol(x1, Decl(-57087-105.ts, 17, 13)) +>f : Symbol(X1.f, Decl(-57087-105.ts, 6, 14), Decl(-57087-105.ts, 7, 17)) +>arg1 : Symbol(arg1, Decl(-57087-105.ts, 18, 13)) + +declare const x2: X2; +>x2 : Symbol(x2, Decl(-57087-105.ts, 20, 13)) +>X2 : Symbol(X2, Decl(-57087-105.ts, 10, 1)) + +declare const arg2: C|B; +>arg2 : Symbol(arg2, Decl(-57087-105.ts, 21, 13)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) + +x2.g(x2.f,arg2); // should be no error +>x2.g : Symbol(X2.g, Decl(-57087-105.ts, 13, 15)) +>x2 : Symbol(x2, Decl(-57087-105.ts, 20, 13)) +>g : Symbol(X2.g, Decl(-57087-105.ts, 13, 15)) +>x2.f : Symbol(X2.f, Decl(-57087-105.ts, 11, 14), Decl(-57087-105.ts, 12, 17)) +>x2 : Symbol(x2, Decl(-57087-105.ts, 20, 13)) +>f : Symbol(X2.f, Decl(-57087-105.ts, 11, 14), Decl(-57087-105.ts, 12, 17)) +>arg2 : Symbol(arg2, Decl(-57087-105.ts, 21, 13)) + +const x = Math.random() < 0.5 ? x1 : x2; +>x : Symbol(x, Decl(-57087-105.ts, 23, 5)) +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>x1 : Symbol(x1, Decl(-57087-105.ts, 17, 13)) +>x2 : Symbol(x2, Decl(-57087-105.ts, 20, 13)) + +x.g; +>x.g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>x : Symbol(x, Decl(-57087-105.ts, 23, 5)) +>g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) + +const arg = Math.random() < 0.5 ? arg1 : arg2; +>arg : Symbol(arg, Decl(-57087-105.ts, 25, 5)) +>Math.random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>Math : Symbol(Math, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --)) +>random : Symbol(Math.random, Decl(lib.es5.d.ts, --, --)) +>arg1 : Symbol(arg1, Decl(-57087-105.ts, 18, 13)) +>arg2 : Symbol(arg2, Decl(-57087-105.ts, 21, 13)) + + + +type ArgCastType = (A & C) | (A & B) | (B & C); +>ArgCastType : Symbol(ArgCastType, Decl(-57087-105.ts, 25, 46)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) + + +function ftw(x:A):string; +>ftw : Symbol(ftw, Decl(-57087-105.ts, 29, 47), Decl(-57087-105.ts, 32, 25), Decl(-57087-105.ts, 33, 25), Decl(-57087-105.ts, 34, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 32, 13)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) + +function ftw(x:C):number; +>ftw : Symbol(ftw, Decl(-57087-105.ts, 29, 47), Decl(-57087-105.ts, 32, 25), Decl(-57087-105.ts, 33, 25), Decl(-57087-105.ts, 34, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 33, 13)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) + +function ftw(x:B):1; +>ftw : Symbol(ftw, Decl(-57087-105.ts, 29, 47), Decl(-57087-105.ts, 32, 25), Decl(-57087-105.ts, 33, 25), Decl(-57087-105.ts, 34, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 34, 13)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) + +function ftw(x: A|B|C) { +>ftw : Symbol(ftw, Decl(-57087-105.ts, 29, 47), Decl(-57087-105.ts, 32, 25), Decl(-57087-105.ts, 33, 25), Decl(-57087-105.ts, 34, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 35, 13)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) + + if ("a" in x) return x.a; +>x : Symbol(x, Decl(-57087-105.ts, 35, 13)) +>x.a : Symbol(a, Decl(-57087-105.ts, 1, 10)) +>x : Symbol(x, Decl(-57087-105.ts, 35, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 1, 10)) + + if ("c" in x) return x.c; +>x : Symbol(x, Decl(-57087-105.ts, 35, 13)) +>x.c : Symbol(c, Decl(-57087-105.ts, 3, 10)) +>x : Symbol(x, Decl(-57087-105.ts, 35, 13)) +>c : Symbol(c, Decl(-57087-105.ts, 3, 10)) + + return 1; +} + +// The necessity of the argument cast is a separate issue! +x.g(ftw,arg as any as any as ArgCastType); // should not be error +>x.g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>x : Symbol(x, Decl(-57087-105.ts, 23, 5)) +>g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>ftw : Symbol(ftw, Decl(-57087-105.ts, 29, 47), Decl(-57087-105.ts, 32, 25), Decl(-57087-105.ts, 33, 25), Decl(-57087-105.ts, 34, 20)) +>arg : Symbol(arg, Decl(-57087-105.ts, 25, 5)) +>ArgCastType : Symbol(ArgCastType, Decl(-57087-105.ts, 25, 46)) + +function ftx(x:A):string; +>ftx : Symbol(ftx, Decl(-57087-105.ts, 42, 42), Decl(-57087-105.ts, 44, 25), Decl(-57087-105.ts, 45, 25), Decl(-57087-105.ts, 46, 25)) +>x : Symbol(x, Decl(-57087-105.ts, 44, 13)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) + +function ftx(x:C):number; +>ftx : Symbol(ftx, Decl(-57087-105.ts, 42, 42), Decl(-57087-105.ts, 44, 25), Decl(-57087-105.ts, 45, 25), Decl(-57087-105.ts, 46, 25)) +>x : Symbol(x, Decl(-57087-105.ts, 45, 13)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) + +function ftx(x:B):string; // should cause x.g(ft2) to error +>ftx : Symbol(ftx, Decl(-57087-105.ts, 42, 42), Decl(-57087-105.ts, 44, 25), Decl(-57087-105.ts, 45, 25), Decl(-57087-105.ts, 46, 25)) +>x : Symbol(x, Decl(-57087-105.ts, 46, 13)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) + +function ftx(x: A|B|C) { +>ftx : Symbol(ftx, Decl(-57087-105.ts, 42, 42), Decl(-57087-105.ts, 44, 25), Decl(-57087-105.ts, 45, 25), Decl(-57087-105.ts, 46, 25)) +>x : Symbol(x, Decl(-57087-105.ts, 47, 13)) +>A : Symbol(A, Decl(-57087-105.ts, 0, 15)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) + + if ("a" in x) return x.a; +>x : Symbol(x, Decl(-57087-105.ts, 47, 13)) +>x.a : Symbol(a, Decl(-57087-105.ts, 1, 10)) +>x : Symbol(x, Decl(-57087-105.ts, 47, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 1, 10)) + + if ("c" in x) return x.c; +>x : Symbol(x, Decl(-57087-105.ts, 47, 13)) +>x.c : Symbol(c, Decl(-57087-105.ts, 3, 10)) +>x : Symbol(x, Decl(-57087-105.ts, 47, 13)) +>c : Symbol(c, Decl(-57087-105.ts, 3, 10)) + + return x.b; +>x.b : Symbol(b, Decl(-57087-105.ts, 2, 10)) +>x : Symbol(x, Decl(-57087-105.ts, 47, 13)) +>b : Symbol(b, Decl(-57087-105.ts, 2, 10)) +} + +// The necessity of the argument cast is a separate issue! +x.g(ftx,arg as any as any as ArgCastType); // should be error +>x.g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>x : Symbol(x, Decl(-57087-105.ts, 23, 5)) +>g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>ftx : Symbol(ftx, Decl(-57087-105.ts, 42, 42), Decl(-57087-105.ts, 44, 25), Decl(-57087-105.ts, 45, 25), Decl(-57087-105.ts, 46, 25)) +>arg : Symbol(arg, Decl(-57087-105.ts, 25, 5)) +>ArgCastType : Symbol(ArgCastType, Decl(-57087-105.ts, 25, 46)) + +//function fty(x:A):string; // should cause x.g(ft2) to error +function fty(x:C):number; +>fty : Symbol(fty, Decl(-57087-105.ts, 54, 42), Decl(-57087-105.ts, 57, 25), Decl(-57087-105.ts, 58, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 57, 13)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) + +function fty(x:B):1; +>fty : Symbol(fty, Decl(-57087-105.ts, 54, 42), Decl(-57087-105.ts, 57, 25), Decl(-57087-105.ts, 58, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 58, 13)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) + +function fty(x: {a?: string, c?: number, b?: 1|"1"}) { +>fty : Symbol(fty, Decl(-57087-105.ts, 54, 42), Decl(-57087-105.ts, 57, 25), Decl(-57087-105.ts, 58, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 59, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 59, 17)) +>c : Symbol(c, Decl(-57087-105.ts, 59, 28)) +>b : Symbol(b, Decl(-57087-105.ts, 59, 40)) + + if (x.a) return x.a; +>x.a : Symbol(a, Decl(-57087-105.ts, 59, 17)) +>x : Symbol(x, Decl(-57087-105.ts, 59, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 59, 17)) +>x.a : Symbol(a, Decl(-57087-105.ts, 59, 17)) +>x : Symbol(x, Decl(-57087-105.ts, 59, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 59, 17)) + + if (x.c) return x.c; +>x.c : Symbol(c, Decl(-57087-105.ts, 59, 28)) +>x : Symbol(x, Decl(-57087-105.ts, 59, 13)) +>c : Symbol(c, Decl(-57087-105.ts, 59, 28)) +>x.c : Symbol(c, Decl(-57087-105.ts, 59, 28)) +>x : Symbol(x, Decl(-57087-105.ts, 59, 13)) +>c : Symbol(c, Decl(-57087-105.ts, 59, 28)) + + if (x.b) return x.b; +>x.b : Symbol(b, Decl(-57087-105.ts, 59, 40)) +>x : Symbol(x, Decl(-57087-105.ts, 59, 13)) +>b : Symbol(b, Decl(-57087-105.ts, 59, 40)) +>x.b : Symbol(b, Decl(-57087-105.ts, 59, 40)) +>x : Symbol(x, Decl(-57087-105.ts, 59, 13)) +>b : Symbol(b, Decl(-57087-105.ts, 59, 40)) + + throw "unexpected error" +} + +// The necessity of the argument cast is a separate issue! +x.g(fty,arg as any as any as ArgCastType); // should be error +>x.g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>x : Symbol(x, Decl(-57087-105.ts, 23, 5)) +>g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>fty : Symbol(fty, Decl(-57087-105.ts, 54, 42), Decl(-57087-105.ts, 57, 25), Decl(-57087-105.ts, 58, 20)) +>arg : Symbol(arg, Decl(-57087-105.ts, 25, 5)) +>ArgCastType : Symbol(ArgCastType, Decl(-57087-105.ts, 25, 46)) + +function ftz(x:{a?:string}):string; // should cause x.g(ft2) to error +>ftz : Symbol(ftz, Decl(-57087-105.ts, 67, 42), Decl(-57087-105.ts, 69, 35), Decl(-57087-105.ts, 70, 25), Decl(-57087-105.ts, 71, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 69, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 69, 16)) + +function ftz(x:C):number; +>ftz : Symbol(ftz, Decl(-57087-105.ts, 67, 42), Decl(-57087-105.ts, 69, 35), Decl(-57087-105.ts, 70, 25), Decl(-57087-105.ts, 71, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 70, 13)) +>C : Symbol(C, Decl(-57087-105.ts, 2, 18)) + +function ftz(x:B):1; +>ftz : Symbol(ftz, Decl(-57087-105.ts, 67, 42), Decl(-57087-105.ts, 69, 35), Decl(-57087-105.ts, 70, 25), Decl(-57087-105.ts, 71, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 71, 13)) +>B : Symbol(B, Decl(-57087-105.ts, 1, 23)) + +function ftz(x: {a?: string, c?: number, b?: 1|"1"}) { +>ftz : Symbol(ftz, Decl(-57087-105.ts, 67, 42), Decl(-57087-105.ts, 69, 35), Decl(-57087-105.ts, 70, 25), Decl(-57087-105.ts, 71, 20)) +>x : Symbol(x, Decl(-57087-105.ts, 72, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 72, 17)) +>c : Symbol(c, Decl(-57087-105.ts, 72, 28)) +>b : Symbol(b, Decl(-57087-105.ts, 72, 40)) + + if (x.a) return x.a; +>x.a : Symbol(a, Decl(-57087-105.ts, 72, 17)) +>x : Symbol(x, Decl(-57087-105.ts, 72, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 72, 17)) +>x.a : Symbol(a, Decl(-57087-105.ts, 72, 17)) +>x : Symbol(x, Decl(-57087-105.ts, 72, 13)) +>a : Symbol(a, Decl(-57087-105.ts, 72, 17)) + + if (x.c) return x.c; +>x.c : Symbol(c, Decl(-57087-105.ts, 72, 28)) +>x : Symbol(x, Decl(-57087-105.ts, 72, 13)) +>c : Symbol(c, Decl(-57087-105.ts, 72, 28)) +>x.c : Symbol(c, Decl(-57087-105.ts, 72, 28)) +>x : Symbol(x, Decl(-57087-105.ts, 72, 13)) +>c : Symbol(c, Decl(-57087-105.ts, 72, 28)) + + if (x.b) return x.b; +>x.b : Symbol(b, Decl(-57087-105.ts, 72, 40)) +>x : Symbol(x, Decl(-57087-105.ts, 72, 13)) +>b : Symbol(b, Decl(-57087-105.ts, 72, 40)) +>x.b : Symbol(b, Decl(-57087-105.ts, 72, 40)) +>x : Symbol(x, Decl(-57087-105.ts, 72, 13)) +>b : Symbol(b, Decl(-57087-105.ts, 72, 40)) + + throw "unexpected error" +} + +// The necessity of the argument cast is a separate issue! +x.g(ftz,arg as any as any as ArgCastType); // should be error +>x.g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>x : Symbol(x, Decl(-57087-105.ts, 23, 5)) +>g : Symbol(g, Decl(-57087-105.ts, 8, 12), Decl(-57087-105.ts, 13, 15)) +>ftz : Symbol(ftz, Decl(-57087-105.ts, 67, 42), Decl(-57087-105.ts, 69, 35), Decl(-57087-105.ts, 70, 25), Decl(-57087-105.ts, 71, 20)) +>arg : Symbol(arg, Decl(-57087-105.ts, 25, 5)) +>ArgCastType : Symbol(ArgCastType, Decl(-57087-105.ts, 25, 46)) + +} + + +/**********************/ +=== -57087-131.ts === +namespace ns4 { +>ns4 : Symbol(ns4, Decl(-57087-131.ts, 0, 0)) + +interface Garg31A { +>Garg31A : Symbol(Garg31A, Decl(-57087-131.ts, 0, 15)) + + (): "01"; + (x:1, y:1): "211" +>x : Symbol(x, Decl(-57087-131.ts, 3, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 3, 9)) + +}; +declare const g31A: Garg31A; +>g31A : Symbol(g31A, Decl(-57087-131.ts, 5, 13)) +>Garg31A : Symbol(Garg31A, Decl(-57087-131.ts, 0, 15)) + +interface Garg31B { +>Garg31B : Symbol(Garg31B, Decl(-57087-131.ts, 5, 28)) + + (): "02"; + (x:2, y:2): "222"; +>x : Symbol(x, Decl(-57087-131.ts, 9, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 9, 9)) + + (x:2, y:1): "221" +>x : Symbol(x, Decl(-57087-131.ts, 10, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 10, 9)) + +}; +declare const g31B: Garg31B; +>g31B : Symbol(g31B, Decl(-57087-131.ts, 12, 13)) +>Garg31B : Symbol(Garg31B, Decl(-57087-131.ts, 5, 28)) + +declare const f31a: { +>f31a : Symbol(f31a, Decl(-57087-131.ts, 14, 13)) + + (): "01"; + (x: 1, y: 1): "211"; +>x : Symbol(x, Decl(-57087-131.ts, 16, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 16, 10)) + + (x: 2, y: 2): "222"; +>x : Symbol(x, Decl(-57087-131.ts, 17, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 17, 10)) + + (x: 2, y: 1): "221"; +>x : Symbol(x, Decl(-57087-131.ts, 18, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 18, 10)) + +}; +f31a satisfies Garg31A & Garg31B; // should satisfy +>f31a : Symbol(f31a, Decl(-57087-131.ts, 14, 13)) +>Garg31A : Symbol(Garg31A, Decl(-57087-131.ts, 0, 15)) +>Garg31B : Symbol(Garg31B, Decl(-57087-131.ts, 5, 28)) + +declare const f31b: { +>f31b : Symbol(f31b, Decl(-57087-131.ts, 22, 13)) + + (): "01"; + (x: 1, y: 1): "211"; +>x : Symbol(x, Decl(-57087-131.ts, 24, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 24, 10)) + + (x: 2, y: 2): "221" /*should cause "f31b satisfies" to error */; +>x : Symbol(x, Decl(-57087-131.ts, 25, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 25, 10)) + + (x: 2, y: 1): "221"; +>x : Symbol(x, Decl(-57087-131.ts, 26, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 26, 10)) + +}; +f31b satisfies Garg31A & Garg31B; // should not satisfy +>f31b : Symbol(f31b, Decl(-57087-131.ts, 22, 13)) +>Garg31A : Symbol(Garg31A, Decl(-57087-131.ts, 0, 15)) +>Garg31B : Symbol(Garg31B, Decl(-57087-131.ts, 5, 28)) + +declare const f31c: { +>f31c : Symbol(f31c, Decl(-57087-131.ts, 30, 13)) + + (): "01"; (x: 1, y: 1): "211"; +>x : Symbol(x, Decl(-57087-131.ts, 31, 15)) +>y : Symbol(y, Decl(-57087-131.ts, 31, 20)) + + (x: 2, y: 2): "222"; +>x : Symbol(x, Decl(-57087-131.ts, 32, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 32, 10)) + + (x: 2, y: 1): "221"; +>x : Symbol(x, Decl(-57087-131.ts, 33, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 33, 10)) + + (x: 1, y: 2): "221" /*should cause "f31c satisfies" to error */; +>x : Symbol(x, Decl(-57087-131.ts, 34, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 34, 10)) + +}; +f31c satisfies Garg31A & Garg31B; // should not satisfy +>f31c : Symbol(f31c, Decl(-57087-131.ts, 30, 13)) +>Garg31A : Symbol(Garg31A, Decl(-57087-131.ts, 0, 15)) +>Garg31B : Symbol(Garg31B, Decl(-57087-131.ts, 5, 28)) + +declare const f31d:{ +>f31d : Symbol(f31d, Decl(-57087-131.ts, 38, 13)) + + (): "01"; + (x?: 1, y?: 1): "211"; /*should cause "f31d satisfies" to error */ +>x : Symbol(x, Decl(-57087-131.ts, 40, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 40, 11)) + + (x: 2, y: 2): "222"; +>x : Symbol(x, Decl(-57087-131.ts, 41, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 41, 10)) + + (x: 2, y: 1): "221"; +>x : Symbol(x, Decl(-57087-131.ts, 42, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 42, 10)) + +}; +f31d satisfies Garg31A & Garg31B; // should not satisfy +>f31d : Symbol(f31d, Decl(-57087-131.ts, 38, 13)) +>Garg31A : Symbol(Garg31A, Decl(-57087-131.ts, 0, 15)) +>Garg31B : Symbol(Garg31B, Decl(-57087-131.ts, 5, 28)) + +declare const f31f: { +>f31f : Symbol(f31f, Decl(-57087-131.ts, 46, 13)) + + //(): "01"; // missing domain support cannot be detected at compiler time with final never + (x: 1, y: 1): "211"; +>x : Symbol(x, Decl(-57087-131.ts, 48, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 48, 10)) + + (x: 2, y: 2): "222"; +>x : Symbol(x, Decl(-57087-131.ts, 49, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 49, 10)) + + (x: 2, y: 1): "221"; +>x : Symbol(x, Decl(-57087-131.ts, 50, 5)) +>y : Symbol(y, Decl(-57087-131.ts, 50, 10)) +} +f31f satisfies Garg31A & Garg31B; // should not satisfy +>f31f : Symbol(f31f, Decl(-57087-131.ts, 46, 13)) +>Garg31A : Symbol(Garg31A, Decl(-57087-131.ts, 0, 15)) +>Garg31B : Symbol(Garg31B, Decl(-57087-131.ts, 5, 28)) + + + +} + + +/**********************/ +=== -57087-133.ts === +namespace ns5 { +>ns5 : Symbol(ns5, Decl(-57087-133.ts, 0, 0)) + +interface Garg33A { +>Garg33A : Symbol(Garg33A, Decl(-57087-133.ts, 0, 15)) + + (): "01"; + (x:1, y?:1): "111"; +>x : Symbol(x, Decl(-57087-133.ts, 3, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 3, 9)) + + (...args: [...1[]]): "101"; +>args : Symbol(args, Decl(-57087-133.ts, 4, 5)) + +}; +interface Garg33B { +>Garg33B : Symbol(Garg33B, Decl(-57087-133.ts, 5, 2)) + + (): "02"; + (x:1, y?:1): "211"; +>x : Symbol(x, Decl(-57087-133.ts, 8, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 8, 9)) + + (...args:1[]): "201"; +>args : Symbol(args, Decl(-57087-133.ts, 9, 5)) + + (x:2, y?:any): "221" +>x : Symbol(x, Decl(-57087-133.ts, 10, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 10, 9)) + +}; + +declare const f33a: { +>f33a : Symbol(f33a, Decl(-57087-133.ts, 13, 13)) + + (): "02"; + (x:1, y?:1): "211"; +>x : Symbol(x, Decl(-57087-133.ts, 15, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 15, 9)) + + (...args:1[]): "201"; +>args : Symbol(args, Decl(-57087-133.ts, 16, 5)) + + (x:2, y?:any): "221" +>x : Symbol(x, Decl(-57087-133.ts, 17, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 17, 9)) +} +f33b satisfies Garg33A & Garg33B; // should satisfy +>f33b : Symbol(f33b, Decl(-57087-133.ts, 23, 13)) +>Garg33A : Symbol(Garg33A, Decl(-57087-133.ts, 0, 15)) +>Garg33B : Symbol(Garg33B, Decl(-57087-133.ts, 5, 2)) + +// because (...args: [...1[]]):=>"101" === (...args:1[]) => "201"; + + +declare const f33b: { +>f33b : Symbol(f33b, Decl(-57087-133.ts, 23, 13)) + + (): "02"; + (x:1, y?:1): "211"; +>x : Symbol(x, Decl(-57087-133.ts, 25, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 25, 9)) + + (...args: [...1[]]): "101"; +>args : Symbol(args, Decl(-57087-133.ts, 26, 5)) + + (...args:1[]): "201"; +>args : Symbol(args, Decl(-57087-133.ts, 27, 5)) + + (x:2, y?:any): "221" +>x : Symbol(x, Decl(-57087-133.ts, 28, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 28, 9)) +} +f33b satisfies Garg33A & Garg33B; // should satisfy +>f33b : Symbol(f33b, Decl(-57087-133.ts, 23, 13)) +>Garg33A : Symbol(Garg33A, Decl(-57087-133.ts, 0, 15)) +>Garg33B : Symbol(Garg33B, Decl(-57087-133.ts, 5, 2)) + +declare const f33c: { +>f33c : Symbol(f33c, Decl(-57087-133.ts, 32, 13)) + + (x:2, y?:any): "221" +>x : Symbol(x, Decl(-57087-133.ts, 33, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 33, 9)) + + (...args:1[]): "201"; +>args : Symbol(args, Decl(-57087-133.ts, 34, 5)) + + (...args: [...1[]]): "101"; +>args : Symbol(args, Decl(-57087-133.ts, 35, 5)) + + (x:1, y?:1): "211"; +>x : Symbol(x, Decl(-57087-133.ts, 36, 5)) +>y : Symbol(y, Decl(-57087-133.ts, 36, 9)) + + (): "02"; +} +f33c satisfies Garg33A & Garg33B; // should satisfy (even though reversed order of overloads) +>f33c : Symbol(f33c, Decl(-57087-133.ts, 32, 13)) +>Garg33A : Symbol(Garg33A, Decl(-57087-133.ts, 0, 15)) +>Garg33B : Symbol(Garg33B, Decl(-57087-133.ts, 5, 2)) + + + +} + + +/**********************/ +=== -57087-135.ts === +namespace ns6 { +>ns6 : Symbol(ns6, Decl(-57087-135.ts, 0, 0)) + +interface Garg35A { +>Garg35A : Symbol(Garg35A, Decl(-57087-135.ts, 0, 15)) + + ({x,y}:{x?:1, y?:Garg35B}): "A1" +>x : Symbol(x, Decl(-57087-135.ts, 2, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 2, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 2, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 2, 17)) +>Garg35B : Symbol(Garg35B, Decl(-57087-135.ts, 4, 2)) + + ({x,y}:{x?:2, y?:Garg35C}): "A2" +>x : Symbol(x, Decl(-57087-135.ts, 3, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 3, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 3, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 3, 17)) +>Garg35C : Symbol(Garg35C, Decl(-57087-135.ts, 8, 2)) + +}; +interface Garg35B { +>Garg35B : Symbol(Garg35B, Decl(-57087-135.ts, 4, 2)) + + ({x,y}:{x?:2, y?:Garg35C}): "B1" +>x : Symbol(x, Decl(-57087-135.ts, 6, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 6, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 6, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 6, 17)) +>Garg35C : Symbol(Garg35C, Decl(-57087-135.ts, 8, 2)) + + ({x,y}:{x:2, y?:Garg35A}): "B2"; +>x : Symbol(x, Decl(-57087-135.ts, 7, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 7, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 7, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 7, 16)) +>Garg35A : Symbol(Garg35A, Decl(-57087-135.ts, 0, 15)) + +}; +interface Garg35C { +>Garg35C : Symbol(Garg35C, Decl(-57087-135.ts, 8, 2)) + + ({x,y}:{x:2, y?:Garg35A}): "C1"; +>x : Symbol(x, Decl(-57087-135.ts, 10, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 10, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 10, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 10, 16)) +>Garg35A : Symbol(Garg35A, Decl(-57087-135.ts, 0, 15)) + + ({x,y}:{x?:1, y?:Garg35B}): "C2" +>x : Symbol(x, Decl(-57087-135.ts, 11, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 11, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 11, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 11, 17)) +>Garg35B : Symbol(Garg35B, Decl(-57087-135.ts, 4, 2)) + +}; + +declare const f35a: { +>f35a : Symbol(f35a, Decl(-57087-135.ts, 14, 13)) + + ({x,y}:{x?:1, y?:Garg35B}): "A1" +>x : Symbol(x, Decl(-57087-135.ts, 15, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 15, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 15, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 15, 17)) +>Garg35B : Symbol(Garg35B, Decl(-57087-135.ts, 4, 2)) + + ({x,y}:{x:2, y?:Garg35A}): "B2"; +>x : Symbol(x, Decl(-57087-135.ts, 16, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 16, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 16, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 16, 16)) +>Garg35A : Symbol(Garg35A, Decl(-57087-135.ts, 0, 15)) + + ({x,y}:{x?:2, y?:Garg35C}): "A2" +>x : Symbol(x, Decl(-57087-135.ts, 17, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 17, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 17, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 17, 17)) +>Garg35C : Symbol(Garg35C, Decl(-57087-135.ts, 8, 2)) +} +f35a satisfies Garg35A & Garg35B & Garg35C; // should satisfy +>f35a : Symbol(f35a, Decl(-57087-135.ts, 14, 13)) +>Garg35A : Symbol(Garg35A, Decl(-57087-135.ts, 0, 15)) +>Garg35B : Symbol(Garg35B, Decl(-57087-135.ts, 4, 2)) +>Garg35C : Symbol(Garg35C, Decl(-57087-135.ts, 8, 2)) + +declare const f35b: { +>f35b : Symbol(f35b, Decl(-57087-135.ts, 21, 13)) + + ({x,y}:{x:2, y?:Garg35A}): "C1"; +>x : Symbol(x, Decl(-57087-135.ts, 22, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 22, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 22, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 22, 16)) +>Garg35A : Symbol(Garg35A, Decl(-57087-135.ts, 0, 15)) + + ({x,y}:{x?:1, y?:Garg35B}): "C2" +>x : Symbol(x, Decl(-57087-135.ts, 23, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 23, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 23, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 23, 17)) +>Garg35B : Symbol(Garg35B, Decl(-57087-135.ts, 4, 2)) + + ({x,y}:{x?:2, y?:Garg35C}): "B1" +>x : Symbol(x, Decl(-57087-135.ts, 24, 6)) +>y : Symbol(y, Decl(-57087-135.ts, 24, 8)) +>x : Symbol(x, Decl(-57087-135.ts, 24, 12)) +>y : Symbol(y, Decl(-57087-135.ts, 24, 17)) +>Garg35C : Symbol(Garg35C, Decl(-57087-135.ts, 8, 2)) +} +f35b satisfies typeof f35a & Garg35A & Garg35B & Garg35C; // should satisfy +>f35b : Symbol(f35b, Decl(-57087-135.ts, 21, 13)) +>f35a : Symbol(f35a, Decl(-57087-135.ts, 14, 13)) +>Garg35A : Symbol(Garg35A, Decl(-57087-135.ts, 0, 15)) +>Garg35B : Symbol(Garg35B, Decl(-57087-135.ts, 4, 2)) +>Garg35C : Symbol(Garg35C, Decl(-57087-135.ts, 8, 2)) + + +} diff --git a/tests/baselines/reference/checkOverloadsRelatedToIntersection.types b/tests/baselines/reference/checkOverloadsRelatedToIntersection.types new file mode 100644 index 0000000000000..fed69884dd22a --- /dev/null +++ b/tests/baselines/reference/checkOverloadsRelatedToIntersection.types @@ -0,0 +1,1354 @@ +//// [tests/cases/compiler/checkOverloadsRelatedToIntersection.ts] //// + +=== -57087-101.ts === +/**********************/ + +namespace ns0 { +>ns0 : typeof ns0 + +interface FMap { + f:(x:T)=>R +>f : (x: T) => R +>x : T + + g(f:(x:T)=>R):R; +>g : (f: (x: T) => R) => R +>f : (x: T) => R +>x : T +} +declare const x1: FMap<1|2,1|2>; +>x1 : FMap<1 | 2, 1 | 2> + +x1.g(x1.f); // no error +>x1.g(x1.f) : 1 | 2 +>x1.g : (f: (x: 1 | 2) => 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>g : (f: (x: 1 | 2) => 1 | 2) => 1 | 2 +>x1.f : (x: 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>f : (x: 1 | 2) => 1 | 2 + +declare const x2: FMap<2|3,"2"|"3">; +>x2 : FMap<2 | 3, "2" | "3"> + +x2.g(x2.f); // no error +>x2.g(x2.f) : "2" | "3" +>x2.g : (f: (x: 2 | 3) => "2" | "3") => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>g : (f: (x: 2 | 3) => "2" | "3") => "2" | "3" +>x2.f : (x: 2 | 3) => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>f : (x: 2 | 3) => "2" | "3" + +const x = Math.random() < 0.5 ? x1 : x2; +>x : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>Math.random() < 0.5 ? x1 : x2 : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>Math.random() < 0.5 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.5 : 0.5 +>x1 : FMap<1 | 2, 1 | 2> +>x2 : FMap<2 | 3, "2" | "3"> + +x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" +>x.g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>x : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") + +/* + * Exact expansion of x.g, with the intersection of the two function types expanded. + * Catch-all with "never" return is not required to pass the test. + */ +function ft0(x:1|2):1|2; +>ft0 : { (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 1 | 2 + +function ft0(x:2|3):"2"|"3"; +>ft0 : { (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 2 | 3 + +function ft0(x:1|2|3){ +>ft0 : { (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 1 | 2 | 3 + + if (x!==3) return x1.f(x); +>x!==3 : boolean +>x : 1 | 2 | 3 +>3 : 3 +>x1.f(x) : 1 | 2 +>x1.f : (x: 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>f : (x: 1 | 2) => 1 | 2 +>x : 1 | 2 + + else return x2.f(x); +>x2.f(x) : "2" | "3" +>x2.f : (x: 2 | 3) => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>f : (x: 2 | 3) => "2" | "3" +>x : 3 +} +x.g(ft0); // should not be error +>x.g(ft0) : 1 | 2 | "2" | "3" +>x.g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>x : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>ft0 : { (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } + +/* + * Condtion for passing are: + * (a1) Every source overload is matches at least one target overload + * (a2) Every target overload is matched by at least one souce overload + * where "matching" is defined as + * (b1) the target result is void OR the target result and source result overlap // should be source result subset of target result ? + * (b2) the target and source parameters match identically up to the number of required source parameters. + * This test case fails because: source (x:1) is not identical to target (x:1|2) or (x:2|3) + */ + +function ft1(x:1):1; +>ft1 : { (x: 1): 1; (x: 2): 2; (x: 3): "3"; } +>x : 1 + +function ft1(x:2):2; +>ft1 : { (x: 1): 1; (x: 2): 2; (x: 3): "3"; } +>x : 2 + +function ft1(x:3):"3"; +>ft1 : { (x: 1): 1; (x: 2): 2; (x: 3): "3"; } +>x : 3 + +function ft1(x:1|2|3) { +>ft1 : { (x: 1): 1; (x: 2): 2; (x: 3): "3"; } +>x : 1 | 2 | 3 + + switch (x) { +>x : 1 | 2 | 3 + + case 1: return 1; +>1 : 1 +>1 : 1 + + case 2: return 2; +>2 : 2 +>2 : 2 + + case 3: return "3"; +>3 : 3 +>"3" : "3" + } + throw "unexpected error" +>"unexpected error" : "unexpected error" +} +x.g(ft1); // should be error +>x.g(ft1) : 1 | 2 | "2" | "3" +>x.g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>x : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>ft1 : { (x: 1): 1; (x: 2): 2; (x: 3): "3"; } + + +} + + +/**********************/ +=== -57087-102.ts === +namespace ns1 { +>ns1 : typeof ns1 + +interface FMap { + f:(x:T)=>R +>f : (x: T) => R +>x : T + + g(f:(x:T)=>R):R; +>g : (f: (x: T) => R) => R +>f : (x: T) => R +>x : T +} +declare const x1: FMap<1|2,1|2>; +>x1 : FMap<1 | 2, 1 | 2> + +x1.g(x1.f); // no error +>x1.g(x1.f) : 1 | 2 +>x1.g : (f: (x: 1 | 2) => 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>g : (f: (x: 1 | 2) => 1 | 2) => 1 | 2 +>x1.f : (x: 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>f : (x: 1 | 2) => 1 | 2 + +declare const x2: FMap<2|3,"2"|"3">; +>x2 : FMap<2 | 3, "2" | "3"> + +x2.g(x2.f); // no error +>x2.g(x2.f) : "2" | "3" +>x2.g : (f: (x: 2 | 3) => "2" | "3") => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>g : (f: (x: 2 | 3) => "2" | "3") => "2" | "3" +>x2.f : (x: 2 | 3) => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>f : (x: 2 | 3) => "2" | "3" + +const x = Math.random() < 0.5 ? x1 : x2; +>x : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>Math.random() < 0.5 ? x1 : x2 : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>Math.random() < 0.5 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.5 : 0.5 +>x1 : FMap<1 | 2, 1 | 2> +>x2 : FMap<2 | 3, "2" | "3"> + +x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" +>x.g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>x : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") + + +/** + * The following function ft3 should fail. However, it currently does not + * The new code only handles cases that fail the in the original code. + * However, using such long overload chains is not desireable anyway - so we don't need to fix this? + * Maybe fail on when the number of source overloads is greater than the total number of target overloads? + */ + +function ft3(x:1):"3"; // should cause x.g(ft3) to error +>ft3 : { (x: 1): "3"; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 1 + +function ft3(x:3):"3"; +>ft3 : { (x: 1): "3"; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 3 + +function ft3(x:2):2|"2"; +>ft3 : { (x: 1): "3"; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 2 + +function ft3(x:1|2):1|2; // (4) identical to x1.f +>ft3 : { (x: 1): "3"; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 1 | 2 + +function ft3(x:2|3):"2"|"3"; // (5) identical to x2.f +>ft3 : { (x: 1): "3"; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 2 | 3 + +function ft3(x:1|2|3){ +>ft3 : { (x: 1): "3"; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 1 | 2 | 3 + + if (x===1) return x1.f(x); +>x===1 : boolean +>x : 1 | 2 | 3 +>1 : 1 +>x1.f(x) : 1 | 2 +>x1.f : (x: 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>f : (x: 1 | 2) => 1 | 2 +>x : 1 + + if (x===3) return x2.f(x); +>x===3 : boolean +>x : 2 | 3 +>3 : 3 +>x2.f(x) : "2" | "3" +>x2.f : (x: 2 | 3) => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>f : (x: 2 | 3) => "2" | "3" +>x : 3 + + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); +>Math.random() < 0.5 ? x1.f(x) : x2.f(x) : 1 | 2 | "2" | "3" +>Math.random() < 0.5 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.5 : 0.5 +>x1.f(x) : 1 | 2 +>x1.f : (x: 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>f : (x: 1 | 2) => 1 | 2 +>x : 2 +>x2.f(x) : "2" | "3" +>x2.f : (x: 2 | 3) => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>f : (x: 2 | 3) => "2" | "3" +>x : 2 +} +x.g(ft3); // should error (but currently doesn't) +>x.g(ft3) : 1 | 2 | "2" | "3" +>x.g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>x : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>ft3 : { (x: 1): "3"; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } + +/** + * The following function ft4 should not fail, and it currently does not. + * However, using such long overload chains is not friendly anyway, so it is irrelevant. + */ + +function ft4(x:1):1; +>ft4 : { (x: 1): 1; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 1 + +function ft4(x:3):"3"; +>ft4 : { (x: 1): 1; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 3 + +function ft4(x:2):2|"2"; +>ft4 : { (x: 1): 1; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 2 + +function ft4(x:1|2):1|2; // (4) identical to x1.f +>ft4 : { (x: 1): 1; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 1 | 2 + +function ft4(x:2|3):"2"|"3"; // (5) identical to x2.f +>ft4 : { (x: 1): 1; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 2 | 3 + +function ft4(x:1|2|3){ +>ft4 : { (x: 1): 1; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } +>x : 1 | 2 | 3 + + if (x===1) return x1.f(x); +>x===1 : boolean +>x : 1 | 2 | 3 +>1 : 1 +>x1.f(x) : 1 | 2 +>x1.f : (x: 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>f : (x: 1 | 2) => 1 | 2 +>x : 1 + + if (x===3) return x2.f(x); +>x===3 : boolean +>x : 2 | 3 +>3 : 3 +>x2.f(x) : "2" | "3" +>x2.f : (x: 2 | 3) => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>f : (x: 2 | 3) => "2" | "3" +>x : 3 + + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); +>Math.random() < 0.5 ? x1.f(x) : x2.f(x) : 1 | 2 | "2" | "3" +>Math.random() < 0.5 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.5 : 0.5 +>x1.f(x) : 1 | 2 +>x1.f : (x: 1 | 2) => 1 | 2 +>x1 : FMap<1 | 2, 1 | 2> +>f : (x: 1 | 2) => 1 | 2 +>x : 2 +>x2.f(x) : "2" | "3" +>x2.f : (x: 2 | 3) => "2" | "3" +>x2 : FMap<2 | 3, "2" | "3"> +>f : (x: 2 | 3) => "2" | "3" +>x : 2 +} +x.g(ft4); // should not error +>x.g(ft4) : 1 | 2 | "2" | "3" +>x.g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>x : FMap<1 | 2, 1 | 2> | FMap<2 | 3, "2" | "3"> +>g : ((f: (x: 1 | 2) => 1 | 2) => 1 | 2) | ((f: (x: 2 | 3) => "2" | "3") => "2" | "3") +>ft4 : { (x: 1): 1; (x: 3): "3"; (x: 2): 2 | "2"; (x: 1 | 2): 1 | 2; (x: 2 | 3): "2" | "3"; } + + +} + + +/**********************/ +=== -57087-104.ts === +namespace ns2 { +>ns2 : typeof ns2 + +interface C { + (x:1):"1"; +>x : 1 + + (x:2):"20"; +>x : 2 + + (x:number):number | "1" | "20"; +>x : number + +}; +interface B { + (x:2):"2" +>x : 2 + + (x:3):"30" +>x : 3 + + (x:number):number | "2" | "30"; +>x : number + +}; +interface A { + (x:3):"3" +>x : 3 + + (x:1):"10" +>x : 1 + + (x:number):number | "3" | "10"; +>x : number + +}; + +type W = (A & B & C)|(A & C & B)|(B & A & C)|(B & C & A)|(C & A & B)|(C & B & A); +>W : (A & B & C) | (A & C & B) | (B & A & C) | (B & C & A) | (C & A & B) | (C & B & A) + +/* +* Scenario: +* (1) Overloads: Usng fully expanded domain support for C & B & A, so that all errors are detected at compile time +* (2) Implementation: +* - Note extra lines added to make the function signature compatible with the implementation +* Disadvatage: More verbosity in number of overloads and in implementation. +* Number of overloads could impact compile time, and makes life harder for downstream users of the function +*/ +function foo2(x:1):"1"; +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : 1 + +function foo2(x:2):"20"; +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : 2 + +function foo2(x:number):number; +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : number + +function foo2(x:2):"2" +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : 2 + +function foo2(x:3):"30" +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : 3 + +function foo2(x:number):number; +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : number + +function foo2(x:3):"3" +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : 3 + +function foo2(x:1):"10" +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : 1 + +function foo2(x:number):number; +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : number + +function foo2(x:number){ +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>x : number + + if (x===1) return "1"; +>x===1 : boolean +>x : number +>1 : 1 +>"1" : "1" + + if (x===2) return "2"; +>x===2 : boolean +>x : number +>2 : 2 +>"2" : "2" + + if (x===3) return "3"; +>x===3 : boolean +>x : number +>3 : 3 +>"3" : "3" + + // (*) These nonsense unused extra lines need to be added to make the function signature compatible with the implementation + if (x===1) return "10"; +>x===1 : boolean +>x : number +>1 : 1 +>"10" : "10" + + if (x===2) return "20"; +>x===2 : boolean +>x : number +>2 : 2 +>"20" : "20" + + if (x===3) return "30"; +>x===3 : boolean +>x : number +>3 : 3 +>"30" : "30" + + return x; +>x : number +} + +foo2 satisfies A & B & C; // should satisfy +>foo2 satisfies A & B & C : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } + +foo2 satisfies A & C & B; // should satisfy +>foo2 satisfies A & C & B : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } + +foo2 satisfies B & A & C; // should satisfy +>foo2 satisfies B & A & C : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } + +foo2 satisfies B & C & A; // should satisfy +>foo2 satisfies B & C & A : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } + +foo2 satisfies C & A & B; // should satisfy +>foo2 satisfies C & A & B : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } + +foo2 satisfies C & B & A; // should satisfy +>foo2 satisfies C & B & A : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } + +foo2 satisfies W; // should satisfy +>foo2 satisfies W : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } +>foo2 : { (x: 1): "1"; (x: 2): "20"; (x: number): number; (x: 2): "2"; (x: 3): "30"; (x: number): number; (x: 3): "3"; (x: 1): "10"; (x: number): number; } + + +/* +* Scenario: Select some overloads from the orignal set of overloads. +* Advantages: +* - Less verbosity in number of overloads +* - Less verbosity in implementation +* Number of overloads could impact compile time, and makes life harder for downstream users of the function +*/ +function foo1(x:1):"1"; +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : 1 + +function foo1(x:2):"2"; +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : 2 + +function foo1(x:3):"3"; +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : 3 + +function foo1(x:number):number; +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : number + +function foo1(x:number){ +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : number + + if (x===1) return "1"; +>x===1 : boolean +>x : number +>1 : 1 +>"1" : "1" + + if (x===2) return "2"; +>x===2 : boolean +>x : number +>2 : 2 +>"2" : "2" + + if (x===3) return "3"; +>x===3 : boolean +>x : number +>3 : 3 +>"3" : "3" + + return x; +>x : number +} + +// The `&`-intersection operator result should be independent of the order of it's operands. +foo1 satisfies A & B & C; // should not error +>foo1 satisfies A & B & C : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo1 satisfies A & C & B; // should not error +>foo1 satisfies A & C & B : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo1 satisfies B & A & C; // should not error +>foo1 satisfies B & A & C : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo1 satisfies B & C & A; // should not error +>foo1 satisfies B & C & A : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo1 satisfies C & A & B; // should not error +>foo1 satisfies C & A & B : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo1 satisfies C & B & A; // should not error +>foo1 satisfies C & B & A : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo1 satisfies W; // should not error +>foo1 satisfies W : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo1 : { (x: 1): "1"; (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +/* +*/ + +//function foo3(x:1):"1"; // Omitted domain support should cause satisfies error +function foo3(x:2):"2"; +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : 2 + +function foo3(x:3):"3"; +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : 3 + +function foo3(x:number):number; +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : number + +function foo3(x:number): number | "1" | "2" | "3"{ +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>x : number + + //if (x===1) return "1"; + if (x===2) return "2"; +>x===2 : boolean +>x : number +>2 : 2 +>"2" : "2" + + if (x===3) return "3"; +>x===3 : boolean +>x : number +>3 : 3 +>"3" : "3" + + return x; +>x : number + + // In this case, a final throw "unexpected error" would never be reached anyway. + // if (typeof x === "number") return x; // pointless + // throw "unexpected error"; +} + +foo3 satisfies A & B & C; // should be error +>foo3 satisfies A & B & C : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo3 satisfies A & C & B; // should be error +>foo3 satisfies A & C & B : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo3 satisfies B & A & C; // should be error +>foo3 satisfies B & A & C : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo3 satisfies B & C & A; // should be error +>foo3 satisfies B & C & A : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo3 satisfies C & A & B; // should be error +>foo3 satisfies C & A & B : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } + +foo3 satisfies C & B & A; // should be error +>foo3 satisfies C & B & A : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } + + +foo3 satisfies W; // should be error +>foo3 satisfies W : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } +>foo3 : { (x: 2): "2"; (x: 3): "3"; (x: number): number; } + + +} + + +/**********************/ +=== -57087-105.ts === +namespace ns3 { +>ns3 : typeof ns3 + +type A = { a: string }; +>A : { a: string; } +>a : string + +type B = { b: 1 }; +>B : { b: 1; } +>b : 1 + +type C = { c: number }; +>C : { c: number; } +>c : number + + +interface X1 { + f(x:A):string +>f : { (x: A): string; (x: B): 1; } +>x : A + + f(x:B):1 +>f : { (x: A): string; (x: B): 1; } +>x : B + + g(f: X1["f"],arg:A|B):()=>ReturnType +>g : (f: X1["f"], arg: A | B) => () => ReturnType +>f : { (x: A): string; (x: B): 1; } +>arg : A | B +} +interface X2 { + f(x:C):number +>f : { (x: C): number; (x: B): "1"; } +>x : C + + f(x:B):"1"; +>f : { (x: C): number; (x: B): "1"; } +>x : B + + g(f: X2["f"],arg:C|B):()=>ReturnType +>g : (f: X2["f"], arg: C | B) => () => ReturnType +>f : { (x: C): number; (x: B): "1"; } +>arg : B | C +} + +declare const x1: X1; +>x1 : X1 + +declare const arg1: A|B; +>arg1 : A | B + +x1.g(x1.f,arg1); // should be no error +>x1.g(x1.f,arg1) : () => 1 +>x1.g : (f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1 +>x1 : X1 +>g : (f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1 +>x1.f : { (x: A): string; (x: B): 1; } +>x1 : X1 +>f : { (x: A): string; (x: B): 1; } +>arg1 : A | B + +declare const x2: X2; +>x2 : X2 + +declare const arg2: C|B; +>arg2 : B | C + +x2.g(x2.f,arg2); // should be no error +>x2.g(x2.f,arg2) : () => "1" +>x2.g : (f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1" +>x2 : X2 +>g : (f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1" +>x2.f : { (x: C): number; (x: B): "1"; } +>x2 : X2 +>f : { (x: C): number; (x: B): "1"; } +>arg2 : B | C + +const x = Math.random() < 0.5 ? x1 : x2; +>x : X1 | X2 +>Math.random() < 0.5 ? x1 : x2 : X1 | X2 +>Math.random() < 0.5 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.5 : 0.5 +>x1 : X1 +>x2 : X2 + +x.g; +>x.g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>x : X1 | X2 +>g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") + +const arg = Math.random() < 0.5 ? arg1 : arg2; +>arg : A | B | C +>Math.random() < 0.5 ? arg1 : arg2 : A | B | C +>Math.random() < 0.5 : boolean +>Math.random() : number +>Math.random : () => number +>Math : Math +>random : () => number +>0.5 : 0.5 +>arg1 : A | B +>arg2 : B | C + + + +type ArgCastType = (A & C) | (A & B) | (B & C); +>ArgCastType : (A & C) | (A & B) | (B & C) + + +function ftw(x:A):string; +>ftw : { (x: A): string; (x: C): number; (x: B): 1; } +>x : A + +function ftw(x:C):number; +>ftw : { (x: A): string; (x: C): number; (x: B): 1; } +>x : C + +function ftw(x:B):1; +>ftw : { (x: A): string; (x: C): number; (x: B): 1; } +>x : B + +function ftw(x: A|B|C) { +>ftw : { (x: A): string; (x: C): number; (x: B): 1; } +>x : A | B | C + + if ("a" in x) return x.a; +>"a" in x : boolean +>"a" : "a" +>x : A | B | C +>x.a : string +>x : A +>a : string + + if ("c" in x) return x.c; +>"c" in x : boolean +>"c" : "c" +>x : B | C +>x.c : number +>x : C +>c : number + + return 1; +>1 : 1 +} + +// The necessity of the argument cast is a separate issue! +x.g(ftw,arg as any as any as ArgCastType); // should not be error +>x.g(ftw,arg as any as any as ArgCastType) : (() => 1) | (() => "1") +>x.g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>x : X1 | X2 +>g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>ftw : { (x: A): string; (x: C): number; (x: B): 1; } +>arg as any as any as ArgCastType : ArgCastType +>arg as any as any : any +>arg as any : any +>arg : A | B | C + +function ftx(x:A):string; +>ftx : { (x: A): string; (x: C): number; (x: B): string; } +>x : A + +function ftx(x:C):number; +>ftx : { (x: A): string; (x: C): number; (x: B): string; } +>x : C + +function ftx(x:B):string; // should cause x.g(ft2) to error +>ftx : { (x: A): string; (x: C): number; (x: B): string; } +>x : B + +function ftx(x: A|B|C) { +>ftx : { (x: A): string; (x: C): number; (x: B): string; } +>x : A | B | C + + if ("a" in x) return x.a; +>"a" in x : boolean +>"a" : "a" +>x : A | B | C +>x.a : string +>x : A +>a : string + + if ("c" in x) return x.c; +>"c" in x : boolean +>"c" : "c" +>x : B | C +>x.c : number +>x : C +>c : number + + return x.b; +>x.b : 1 +>x : B +>b : 1 +} + +// The necessity of the argument cast is a separate issue! +x.g(ftx,arg as any as any as ArgCastType); // should be error +>x.g(ftx,arg as any as any as ArgCastType) : (() => 1) | (() => "1") +>x.g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>x : X1 | X2 +>g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>ftx : { (x: A): string; (x: C): number; (x: B): string; } +>arg as any as any as ArgCastType : ArgCastType +>arg as any as any : any +>arg as any : any +>arg : A | B | C + +//function fty(x:A):string; // should cause x.g(ft2) to error +function fty(x:C):number; +>fty : { (x: C): number; (x: B): 1; } +>x : C + +function fty(x:B):1; +>fty : { (x: C): number; (x: B): 1; } +>x : B + +function fty(x: {a?: string, c?: number, b?: 1|"1"}) { +>fty : { (x: C): number; (x: B): 1; } +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>a : string | undefined +>c : number | undefined +>b : 1 | "1" | undefined + + if (x.a) return x.a; +>x.a : string | undefined +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>a : string | undefined +>x.a : string +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>a : string + + if (x.c) return x.c; +>x.c : number | undefined +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>c : number | undefined +>x.c : number +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>c : number + + if (x.b) return x.b; +>x.b : 1 | "1" | undefined +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>b : 1 | "1" | undefined +>x.b : 1 | "1" +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>b : 1 | "1" + + throw "unexpected error" +>"unexpected error" : "unexpected error" +} + +// The necessity of the argument cast is a separate issue! +x.g(fty,arg as any as any as ArgCastType); // should be error +>x.g(fty,arg as any as any as ArgCastType) : (() => 1) | (() => "1") +>x.g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>x : X1 | X2 +>g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>fty : { (x: C): number; (x: B): 1; } +>arg as any as any as ArgCastType : ArgCastType +>arg as any as any : any +>arg as any : any +>arg : A | B | C + +function ftz(x:{a?:string}):string; // should cause x.g(ft2) to error +>ftz : { (x: { a?: string;}): string; (x: C): number; (x: B): 1; } +>x : { a?: string | undefined; } +>a : string | undefined + +function ftz(x:C):number; +>ftz : { (x: { a?: string | undefined; }): string; (x: C): number; (x: B): 1; } +>x : C + +function ftz(x:B):1; +>ftz : { (x: { a?: string | undefined; }): string; (x: C): number; (x: B): 1; } +>x : B + +function ftz(x: {a?: string, c?: number, b?: 1|"1"}) { +>ftz : { (x: { a?: string | undefined; }): string; (x: C): number; (x: B): 1; } +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>a : string | undefined +>c : number | undefined +>b : 1 | "1" | undefined + + if (x.a) return x.a; +>x.a : string | undefined +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>a : string | undefined +>x.a : string +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>a : string + + if (x.c) return x.c; +>x.c : number | undefined +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>c : number | undefined +>x.c : number +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>c : number + + if (x.b) return x.b; +>x.b : 1 | "1" | undefined +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>b : 1 | "1" | undefined +>x.b : 1 | "1" +>x : { a?: string | undefined; c?: number | undefined; b?: 1 | "1" | undefined; } +>b : 1 | "1" + + throw "unexpected error" +>"unexpected error" : "unexpected error" +} + +// The necessity of the argument cast is a separate issue! +x.g(ftz,arg as any as any as ArgCastType); // should be error +>x.g(ftz,arg as any as any as ArgCastType) : (() => 1) | (() => "1") +>x.g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>x : X1 | X2 +>g : ((f: { (x: A): string; (x: B): 1; }, arg: A | B) => () => 1) | ((f: { (x: C): number; (x: B): "1"; }, arg: B | C) => () => "1") +>ftz : { (x: { a?: string | undefined; }): string; (x: C): number; (x: B): 1; } +>arg as any as any as ArgCastType : ArgCastType +>arg as any as any : any +>arg as any : any +>arg : A | B | C + +} + + +/**********************/ +=== -57087-131.ts === +namespace ns4 { +>ns4 : typeof ns4 + +interface Garg31A { + (): "01"; + (x:1, y:1): "211" +>x : 1 +>y : 1 + +}; +declare const g31A: Garg31A; +>g31A : Garg31A + +interface Garg31B { + (): "02"; + (x:2, y:2): "222"; +>x : 2 +>y : 2 + + (x:2, y:1): "221" +>x : 2 +>y : 1 + +}; +declare const g31B: Garg31B; +>g31B : Garg31B + +declare const f31a: { +>f31a : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } + + (): "01"; + (x: 1, y: 1): "211"; +>x : 1 +>y : 1 + + (x: 2, y: 2): "222"; +>x : 2 +>y : 2 + + (x: 2, y: 1): "221"; +>x : 2 +>y : 1 + +}; +f31a satisfies Garg31A & Garg31B; // should satisfy +>f31a satisfies Garg31A & Garg31B : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } +>f31a : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } + +declare const f31b: { +>f31b : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "221"; (x: 2, y: 1): "221"; } + + (): "01"; + (x: 1, y: 1): "211"; +>x : 1 +>y : 1 + + (x: 2, y: 2): "221" /*should cause "f31b satisfies" to error */; +>x : 2 +>y : 2 + + (x: 2, y: 1): "221"; +>x : 2 +>y : 1 + +}; +f31b satisfies Garg31A & Garg31B; // should not satisfy +>f31b satisfies Garg31A & Garg31B : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "221"; (x: 2, y: 1): "221"; } +>f31b : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "221"; (x: 2, y: 1): "221"; } + +declare const f31c: { +>f31c : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; (x: 1, y: 2): "221"; } + + (): "01"; (x: 1, y: 1): "211"; +>x : 1 +>y : 1 + + (x: 2, y: 2): "222"; +>x : 2 +>y : 2 + + (x: 2, y: 1): "221"; +>x : 2 +>y : 1 + + (x: 1, y: 2): "221" /*should cause "f31c satisfies" to error */; +>x : 1 +>y : 2 + +}; +f31c satisfies Garg31A & Garg31B; // should not satisfy +>f31c satisfies Garg31A & Garg31B : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; (x: 1, y: 2): "221"; } +>f31c : { (): "01"; (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; (x: 1, y: 2): "221"; } + +declare const f31d:{ +>f31d : { (): "01"; (x?: 1, y?: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } + + (): "01"; + (x?: 1, y?: 1): "211"; /*should cause "f31d satisfies" to error */ +>x : 1 | undefined +>y : 1 | undefined + + (x: 2, y: 2): "222"; +>x : 2 +>y : 2 + + (x: 2, y: 1): "221"; +>x : 2 +>y : 1 + +}; +f31d satisfies Garg31A & Garg31B; // should not satisfy +>f31d satisfies Garg31A & Garg31B : { (): "01"; (x?: 1 | undefined, y?: 1 | undefined): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } +>f31d : { (): "01"; (x?: 1 | undefined, y?: 1 | undefined): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } + +declare const f31f: { +>f31f : { (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } + + //(): "01"; // missing domain support cannot be detected at compiler time with final never + (x: 1, y: 1): "211"; +>x : 1 +>y : 1 + + (x: 2, y: 2): "222"; +>x : 2 +>y : 2 + + (x: 2, y: 1): "221"; +>x : 2 +>y : 1 +} +f31f satisfies Garg31A & Garg31B; // should not satisfy +>f31f satisfies Garg31A & Garg31B : { (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } +>f31f : { (x: 1, y: 1): "211"; (x: 2, y: 2): "222"; (x: 2, y: 1): "221"; } + + + +} + + +/**********************/ +=== -57087-133.ts === +namespace ns5 { +>ns5 : typeof ns5 + +interface Garg33A { + (): "01"; + (x:1, y?:1): "111"; +>x : 1 +>y : 1 | undefined + + (...args: [...1[]]): "101"; +>args : 1[] + +}; +interface Garg33B { + (): "02"; + (x:1, y?:1): "211"; +>x : 1 +>y : 1 | undefined + + (...args:1[]): "201"; +>args : 1[] + + (x:2, y?:any): "221" +>x : 2 +>y : any + +}; + +declare const f33a: { +>f33a : { (): "02"; (x: 1, y?: 1): "211"; (...args: 1[]): "201"; (x: 2, y?: any): "221"; } + + (): "02"; + (x:1, y?:1): "211"; +>x : 1 +>y : 1 | undefined + + (...args:1[]): "201"; +>args : 1[] + + (x:2, y?:any): "221" +>x : 2 +>y : any +} +f33b satisfies Garg33A & Garg33B; // should satisfy +>f33b satisfies Garg33A & Garg33B : { (): "02"; (x: 1, y?: 1 | undefined): "211"; (...args: 1[]): "101"; (...args: 1[]): "201"; (x: 2, y?: any): "221"; } +>f33b : { (): "02"; (x: 1, y?: 1 | undefined): "211"; (...args: 1[]): "101"; (...args: 1[]): "201"; (x: 2, y?: any): "221"; } + +// because (...args: [...1[]]):=>"101" === (...args:1[]) => "201"; + + +declare const f33b: { +>f33b : { (): "02"; (x: 1, y?: 1): "211"; (...args: [...1[]]): "101"; (...args: 1[]): "201"; (x: 2, y?: any): "221"; } + + (): "02"; + (x:1, y?:1): "211"; +>x : 1 +>y : 1 | undefined + + (...args: [...1[]]): "101"; +>args : 1[] + + (...args:1[]): "201"; +>args : 1[] + + (x:2, y?:any): "221" +>x : 2 +>y : any +} +f33b satisfies Garg33A & Garg33B; // should satisfy +>f33b satisfies Garg33A & Garg33B : { (): "02"; (x: 1, y?: 1 | undefined): "211"; (...args: 1[]): "101"; (...args: 1[]): "201"; (x: 2, y?: any): "221"; } +>f33b : { (): "02"; (x: 1, y?: 1 | undefined): "211"; (...args: 1[]): "101"; (...args: 1[]): "201"; (x: 2, y?: any): "221"; } + +declare const f33c: { +>f33c : { (x: 2, y?: any): "221"; (...args: 1[]): "201"; (...args: [...1[]]): "101"; (x: 1, y?: 1): "211"; (): "02"; } + + (x:2, y?:any): "221" +>x : 2 +>y : any + + (...args:1[]): "201"; +>args : 1[] + + (...args: [...1[]]): "101"; +>args : 1[] + + (x:1, y?:1): "211"; +>x : 1 +>y : 1 | undefined + + (): "02"; +} +f33c satisfies Garg33A & Garg33B; // should satisfy (even though reversed order of overloads) +>f33c satisfies Garg33A & Garg33B : { (x: 2, y?: any): "221"; (...args: 1[]): "201"; (...args: 1[]): "101"; (x: 1, y?: 1 | undefined): "211"; (): "02"; } +>f33c : { (x: 2, y?: any): "221"; (...args: 1[]): "201"; (...args: 1[]): "101"; (x: 1, y?: 1 | undefined): "211"; (): "02"; } + + + +} + + +/**********************/ +=== -57087-135.ts === +namespace ns6 { +>ns6 : typeof ns6 + +interface Garg35A { + ({x,y}:{x?:1, y?:Garg35B}): "A1" +>x : 1 | undefined +>y : Garg35B | undefined +>x : 1 | undefined +>y : Garg35B | undefined + + ({x,y}:{x?:2, y?:Garg35C}): "A2" +>x : 2 | undefined +>y : Garg35C | undefined +>x : 2 | undefined +>y : Garg35C | undefined + +}; +interface Garg35B { + ({x,y}:{x?:2, y?:Garg35C}): "B1" +>x : 2 | undefined +>y : Garg35C | undefined +>x : 2 | undefined +>y : Garg35C | undefined + + ({x,y}:{x:2, y?:Garg35A}): "B2"; +>x : 2 +>y : Garg35A | undefined +>x : 2 +>y : Garg35A | undefined + +}; +interface Garg35C { + ({x,y}:{x:2, y?:Garg35A}): "C1"; +>x : 2 +>y : Garg35A | undefined +>x : 2 +>y : Garg35A | undefined + + ({x,y}:{x?:1, y?:Garg35B}): "C2" +>x : 1 | undefined +>y : Garg35B | undefined +>x : 1 | undefined +>y : Garg35B | undefined + +}; + +declare const f35a: { +>f35a : { ({ x, y }: { x?: 1 | undefined; y?: Garg35B | undefined; }): "A1"; ({ x, y }: { x: 2; y?: Garg35A | undefined; }): "B2"; ({ x, y }: { x?: 2 | undefined; y?: Garg35C | undefined; }): "A2"; } + + ({x,y}:{x?:1, y?:Garg35B}): "A1" +>x : 1 | undefined +>y : Garg35B | undefined +>x : 1 | undefined +>y : Garg35B | undefined + + ({x,y}:{x:2, y?:Garg35A}): "B2"; +>x : 2 +>y : Garg35A | undefined +>x : 2 +>y : Garg35A | undefined + + ({x,y}:{x?:2, y?:Garg35C}): "A2" +>x : 2 | undefined +>y : Garg35C | undefined +>x : 2 | undefined +>y : Garg35C | undefined +} +f35a satisfies Garg35A & Garg35B & Garg35C; // should satisfy +>f35a satisfies Garg35A & Garg35B & Garg35C : { ({ x, y }: { x?: 1 | undefined; y?: Garg35B | undefined; }): "A1"; ({ x, y }: { x: 2; y?: Garg35A | undefined; }): "B2"; ({ x, y }: { x?: 2 | undefined; y?: Garg35C | undefined; }): "A2"; } +>f35a : { ({ x, y }: { x?: 1 | undefined; y?: Garg35B | undefined; }): "A1"; ({ x, y }: { x: 2; y?: Garg35A | undefined; }): "B2"; ({ x, y }: { x?: 2 | undefined; y?: Garg35C | undefined; }): "A2"; } + +declare const f35b: { +>f35b : { ({ x, y }: { x: 2; y?: Garg35A | undefined; }): "C1"; ({ x, y }: { x?: 1 | undefined; y?: Garg35B | undefined; }): "C2"; ({ x, y }: { x?: 2 | undefined; y?: Garg35C | undefined; }): "B1"; } + + ({x,y}:{x:2, y?:Garg35A}): "C1"; +>x : 2 +>y : Garg35A | undefined +>x : 2 +>y : Garg35A | undefined + + ({x,y}:{x?:1, y?:Garg35B}): "C2" +>x : 1 | undefined +>y : Garg35B | undefined +>x : 1 | undefined +>y : Garg35B | undefined + + ({x,y}:{x?:2, y?:Garg35C}): "B1" +>x : 2 | undefined +>y : Garg35C | undefined +>x : 2 | undefined +>y : Garg35C | undefined +} +f35b satisfies typeof f35a & Garg35A & Garg35B & Garg35C; // should satisfy +>f35b satisfies typeof f35a & Garg35A & Garg35B & Garg35C : { ({ x, y }: { x: 2; y?: Garg35A | undefined; }): "C1"; ({ x, y }: { x?: 1 | undefined; y?: Garg35B | undefined; }): "C2"; ({ x, y }: { x?: 2 | undefined; y?: Garg35C | undefined; }): "B1"; } +>f35b : { ({ x, y }: { x: 2; y?: Garg35A | undefined; }): "C1"; ({ x, y }: { x?: 1 | undefined; y?: Garg35B | undefined; }): "C2"; ({ x, y }: { x?: 2 | undefined; y?: Garg35C | undefined; }): "B1"; } +>f35a : { ({ x, y }: { x?: 1 | undefined; y?: Garg35B | undefined; }): "A1"; ({ x, y }: { x: 2; y?: Garg35A | undefined; }): "B2"; ({ x, y }: { x?: 2 | undefined; y?: Garg35C | undefined; }): "A2"; } + + +} diff --git a/tests/cases/compiler/checkOverloadsRelatedToIntersection.ts b/tests/cases/compiler/checkOverloadsRelatedToIntersection.ts new file mode 100644 index 0000000000000..8454d11ad0d4a --- /dev/null +++ b/tests/cases/compiler/checkOverloadsRelatedToIntersection.ts @@ -0,0 +1,463 @@ +// @strict: true +// @target: esnext + + +/**********************/ +// @filename:-57087-101.ts + +namespace ns0 { +interface FMap { + f:(x:T)=>R + g(f:(x:T)=>R):R; +} +declare const x1: FMap<1|2,1|2>; +x1.g(x1.f); // no error +declare const x2: FMap<2|3,"2"|"3">; +x2.g(x2.f); // no error +const x = Math.random() < 0.5 ? x1 : x2; +x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" + +/* + * Exact expansion of x.g, with the intersection of the two function types expanded. + * Catch-all with "never" return is not required to pass the test. + */ +function ft0(x:1|2):1|2; +function ft0(x:2|3):"2"|"3"; +function ft0(x:1|2|3){ + if (x!==3) return x1.f(x); + else return x2.f(x); +} +x.g(ft0); // should not be error + +/* + * Condtion for passing are: + * (a1) Every source overload is matches at least one target overload + * (a2) Every target overload is matched by at least one souce overload + * where "matching" is defined as + * (b1) the target result is void OR the target result and source result overlap // should be source result subset of target result ? + * (b2) the target and source parameters match identically up to the number of required source parameters. + * This test case fails because: source (x:1) is not identical to target (x:1|2) or (x:2|3) + */ + +function ft1(x:1):1; +function ft1(x:2):2; +function ft1(x:3):"3"; +function ft1(x:1|2|3) { + switch (x) { + case 1: return 1; + case 2: return 2; + case 3: return "3"; + } + throw "unexpected error" +} +x.g(ft1); // should be error + + +} + + +/**********************/ +// @filename:-57087-102.ts + +namespace ns1 { +interface FMap { + f:(x:T)=>R + g(f:(x:T)=>R):R; +} +declare const x1: FMap<1|2,1|2>; +x1.g(x1.f); // no error +declare const x2: FMap<2|3,"2"|"3">; +x2.g(x2.f); // no error +const x = Math.random() < 0.5 ? x1 : x2; +x.g; // (method) FMap.g(f: ((x: 1 | 2) => 1 | 2) & ((x: 2 | 3) => "2" | "3")): 1 | 2 | "2" | "3" + + +/** + * The following function ft3 should fail. However, it currently does not + * The new code only handles cases that fail the in the original code. + * However, using such long overload chains is not desireable anyway - so we don't need to fix this? + * Maybe fail on when the number of source overloads is greater than the total number of target overloads? + */ + +function ft3(x:1):"3"; // should cause x.g(ft3) to error +function ft3(x:3):"3"; +function ft3(x:2):2|"2"; +function ft3(x:1|2):1|2; // (4) identical to x1.f +function ft3(x:2|3):"2"|"3"; // (5) identical to x2.f +function ft3(x:1|2|3){ + if (x===1) return x1.f(x); + if (x===3) return x2.f(x); + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); +} +x.g(ft3); // should error (but currently doesn't) + +/** + * The following function ft4 should not fail, and it currently does not. + * However, using such long overload chains is not friendly anyway, so it is irrelevant. + */ + +function ft4(x:1):1; +function ft4(x:3):"3"; +function ft4(x:2):2|"2"; +function ft4(x:1|2):1|2; // (4) identical to x1.f +function ft4(x:2|3):"2"|"3"; // (5) identical to x2.f +function ft4(x:1|2|3){ + if (x===1) return x1.f(x); + if (x===3) return x2.f(x); + return Math.random() < 0.5 ? x1.f(x) : x2.f(x); +} +x.g(ft4); // should not error + + +} + + +/**********************/ +// @filename:-57087-104.ts + +namespace ns2 { +interface C { + (x:1):"1"; + (x:2):"20"; + (x:number):number | "1" | "20"; +}; +interface B { + (x:2):"2" + (x:3):"30" + (x:number):number | "2" | "30"; +}; +interface A { + (x:3):"3" + (x:1):"10" + (x:number):number | "3" | "10"; +}; + +type W = (A & B & C)|(A & C & B)|(B & A & C)|(B & C & A)|(C & A & B)|(C & B & A); + +/* +* Scenario: +* (1) Overloads: Usng fully expanded domain support for C & B & A, so that all errors are detected at compile time +* (2) Implementation: +* - Note extra lines added to make the function signature compatible with the implementation +* Disadvatage: More verbosity in number of overloads and in implementation. +* Number of overloads could impact compile time, and makes life harder for downstream users of the function +*/ +function foo2(x:1):"1"; +function foo2(x:2):"20"; +function foo2(x:number):number; +function foo2(x:2):"2" +function foo2(x:3):"30" +function foo2(x:number):number; +function foo2(x:3):"3" +function foo2(x:1):"10" +function foo2(x:number):number; +function foo2(x:number){ + if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + // (*) These nonsense unused extra lines need to be added to make the function signature compatible with the implementation + if (x===1) return "10"; + if (x===2) return "20"; + if (x===3) return "30"; + return x; +} + +foo2 satisfies A & B & C; // should satisfy +foo2 satisfies A & C & B; // should satisfy +foo2 satisfies B & A & C; // should satisfy +foo2 satisfies B & C & A; // should satisfy +foo2 satisfies C & A & B; // should satisfy +foo2 satisfies C & B & A; // should satisfy +foo2 satisfies W; // should satisfy + + +/* +* Scenario: Select some overloads from the orignal set of overloads. +* Advantages: +* - Less verbosity in number of overloads +* - Less verbosity in implementation +* Number of overloads could impact compile time, and makes life harder for downstream users of the function +*/ +function foo1(x:1):"1"; +function foo1(x:2):"2"; +function foo1(x:3):"3"; +function foo1(x:number):number; +function foo1(x:number){ + if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + return x; +} + +// The `&`-intersection operator result should be independent of the order of it's operands. +foo1 satisfies A & B & C; // should not error +foo1 satisfies A & C & B; // should not error +foo1 satisfies B & A & C; // should not error +foo1 satisfies B & C & A; // should not error +foo1 satisfies C & A & B; // should not error +foo1 satisfies C & B & A; // should not error +foo1 satisfies W; // should not error + +/* +*/ + +//function foo3(x:1):"1"; // Omitted domain support should cause satisfies error +function foo3(x:2):"2"; +function foo3(x:3):"3"; +function foo3(x:number):number; +function foo3(x:number): number | "1" | "2" | "3"{ + //if (x===1) return "1"; + if (x===2) return "2"; + if (x===3) return "3"; + return x; + // In this case, a final throw "unexpected error" would never be reached anyway. + // if (typeof x === "number") return x; // pointless + // throw "unexpected error"; +} + +foo3 satisfies A & B & C; // should be error +foo3 satisfies A & C & B; // should be error +foo3 satisfies B & A & C; // should be error +foo3 satisfies B & C & A; // should be error +foo3 satisfies C & A & B; // should be error +foo3 satisfies C & B & A; // should be error + + +foo3 satisfies W; // should be error + + +} + + +/**********************/ +// @filename:-57087-105.ts + +namespace ns3 { +type A = { a: string }; +type B = { b: 1 }; +type C = { c: number }; + + +interface X1 { + f(x:A):string + f(x:B):1 + g(f: X1["f"],arg:A|B):()=>ReturnType +} +interface X2 { + f(x:C):number + f(x:B):"1"; + g(f: X2["f"],arg:C|B):()=>ReturnType +} + +declare const x1: X1; +declare const arg1: A|B; +x1.g(x1.f,arg1); // should be no error +declare const x2: X2; +declare const arg2: C|B; +x2.g(x2.f,arg2); // should be no error +const x = Math.random() < 0.5 ? x1 : x2; +x.g; +const arg = Math.random() < 0.5 ? arg1 : arg2; + + + +type ArgCastType = (A & C) | (A & B) | (B & C); + + +function ftw(x:A):string; +function ftw(x:C):number; +function ftw(x:B):1; +function ftw(x: A|B|C) { + if ("a" in x) return x.a; + if ("c" in x) return x.c; + return 1; +} + +// The necessity of the argument cast is a separate issue! +x.g(ftw,arg as any as any as ArgCastType); // should not be error + +function ftx(x:A):string; +function ftx(x:C):number; +function ftx(x:B):string; // should cause x.g(ft2) to error +function ftx(x: A|B|C) { + if ("a" in x) return x.a; + if ("c" in x) return x.c; + return x.b; +} + +// The necessity of the argument cast is a separate issue! +x.g(ftx,arg as any as any as ArgCastType); // should be error + +//function fty(x:A):string; // should cause x.g(ft2) to error +function fty(x:C):number; +function fty(x:B):1; +function fty(x: {a?: string, c?: number, b?: 1|"1"}) { + if (x.a) return x.a; + if (x.c) return x.c; + if (x.b) return x.b; + throw "unexpected error" +} + +// The necessity of the argument cast is a separate issue! +x.g(fty,arg as any as any as ArgCastType); // should be error + +function ftz(x:{a?:string}):string; // should cause x.g(ft2) to error +function ftz(x:C):number; +function ftz(x:B):1; +function ftz(x: {a?: string, c?: number, b?: 1|"1"}) { + if (x.a) return x.a; + if (x.c) return x.c; + if (x.b) return x.b; + throw "unexpected error" +} + +// The necessity of the argument cast is a separate issue! +x.g(ftz,arg as any as any as ArgCastType); // should be error + +} + + +/**********************/ +// @filename:-57087-131.ts + +namespace ns4 { +interface Garg31A { + (): "01"; + (x:1, y:1): "211" +}; +declare const g31A: Garg31A; + +interface Garg31B { + (): "02"; + (x:2, y:2): "222"; + (x:2, y:1): "221" +}; +declare const g31B: Garg31B; + +declare const f31a: { + (): "01"; + (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; +}; +f31a satisfies Garg31A & Garg31B; // should satisfy + +declare const f31b: { + (): "01"; + (x: 1, y: 1): "211"; + (x: 2, y: 2): "221" /*should cause "f31b satisfies" to error */; + (x: 2, y: 1): "221"; +}; +f31b satisfies Garg31A & Garg31B; // should not satisfy + +declare const f31c: { + (): "01"; (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; + (x: 1, y: 2): "221" /*should cause "f31c satisfies" to error */; +}; +f31c satisfies Garg31A & Garg31B; // should not satisfy + +declare const f31d:{ + (): "01"; + (x?: 1, y?: 1): "211"; /*should cause "f31d satisfies" to error */ + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; +}; +f31d satisfies Garg31A & Garg31B; // should not satisfy + +declare const f31f: { + //(): "01"; // missing domain support cannot be detected at compiler time with final never + (x: 1, y: 1): "211"; + (x: 2, y: 2): "222"; + (x: 2, y: 1): "221"; +} +f31f satisfies Garg31A & Garg31B; // should not satisfy + + + +} + + +/**********************/ +// @filename:-57087-133.ts + +namespace ns5 { +interface Garg33A { + (): "01"; + (x:1, y?:1): "111"; + (...args: [...1[]]): "101"; +}; +interface Garg33B { + (): "02"; + (x:1, y?:1): "211"; + (...args:1[]): "201"; + (x:2, y?:any): "221" +}; + +declare const f33a: { + (): "02"; + (x:1, y?:1): "211"; + (...args:1[]): "201"; + (x:2, y?:any): "221" +} +f33b satisfies Garg33A & Garg33B; // should satisfy +// because (...args: [...1[]]):=>"101" === (...args:1[]) => "201"; + + +declare const f33b: { + (): "02"; + (x:1, y?:1): "211"; + (...args: [...1[]]): "101"; + (...args:1[]): "201"; + (x:2, y?:any): "221" +} +f33b satisfies Garg33A & Garg33B; // should satisfy + +declare const f33c: { + (x:2, y?:any): "221" + (...args:1[]): "201"; + (...args: [...1[]]): "101"; + (x:1, y?:1): "211"; + (): "02"; +} +f33c satisfies Garg33A & Garg33B; // should satisfy (even though reversed order of overloads) + + + +} + + +/**********************/ +// @filename:-57087-135.ts + +namespace ns6 { +interface Garg35A { + ({x,y}:{x?:1, y?:Garg35B}): "A1" + ({x,y}:{x?:2, y?:Garg35C}): "A2" +}; +interface Garg35B { + ({x,y}:{x?:2, y?:Garg35C}): "B1" + ({x,y}:{x:2, y?:Garg35A}): "B2"; +}; +interface Garg35C { + ({x,y}:{x:2, y?:Garg35A}): "C1"; + ({x,y}:{x?:1, y?:Garg35B}): "C2" +}; + +declare const f35a: { + ({x,y}:{x?:1, y?:Garg35B}): "A1" + ({x,y}:{x:2, y?:Garg35A}): "B2"; + ({x,y}:{x?:2, y?:Garg35C}): "A2" +} +f35a satisfies Garg35A & Garg35B & Garg35C; // should satisfy + +declare const f35b: { + ({x,y}:{x:2, y?:Garg35A}): "C1"; + ({x,y}:{x?:1, y?:Garg35B}): "C2" + ({x,y}:{x?:2, y?:Garg35C}): "B1" +} +f35b satisfies typeof f35a & Garg35A & Garg35B & Garg35C; // should satisfy + + +} \ No newline at end of file