Skip to content

Commit 0822f33

Browse files
committed
Rather than creating new type identities, only instantiate argument expressions with the context, rather than the signature mapper
1 parent f5ee1c4 commit 0822f33

6 files changed

+277
-25
lines changed

src/compiler/checker.ts

Lines changed: 12 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15632,16 +15632,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
1563215632
);
1563315633
}
1563415634

15635-
function getImplementationSignature(signature: Signature) {
15636-
return signature.typeParameters ?
15637-
signature.implementationSignatureCache ||= createImplementationSignature(signature) :
15638-
signature;
15639-
}
15640-
15641-
function createImplementationSignature(signature: Signature) {
15642-
return signature.typeParameters ? instantiateSignature(signature, createTypeMapper([], [])) : signature;
15643-
}
15644-
1564515635
function getBaseSignature(signature: Signature) {
1564615636
const typeParameters = signature.typeParameters;
1564715637
if (typeParameters) {
@@ -34256,6 +34246,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3425634246
checkMode: CheckMode,
3425734247
reportErrors: boolean,
3425834248
containingMessageChain: (() => DiagnosticMessageChain | undefined) | undefined,
34249+
inferenceContext: InferenceContext | undefined,
3425934250
): readonly Diagnostic[] | undefined {
3426034251
const errorOutputContainer: { errors?: Diagnostic[]; skipLogging?: boolean; } = { errors: undefined, skipLogging: true };
3426134252
if (isJsxOpeningLikeElement(node)) {
@@ -34290,7 +34281,10 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3429034281
// If one or more arguments are still excluded (as indicated by CheckMode.SkipContextSensitive),
3429134282
// we obtain the regular type of any object literal arguments because we may not have inferred complete
3429234283
// parameter types yet and therefore excess property checks may yield false positives (see #17041).
34293-
const checkArgType = instantiateType(checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType, signature.mapper);
34284+
const regularArgType = checkMode & CheckMode.SkipContextSensitive ? getRegularTypeOfObjectLiteral(argType) : argType;
34285+
// If this was inferred under a given inference context, we may need to instantiate the expression type to finish resolving
34286+
// the type variables in the expression.
34287+
const checkArgType = inferenceContext ? instantiateType(regularArgType, inferenceContext.nonFixingMapper) : regularArgType;
3429434288
const effectiveCheckArgumentNode = getEffectiveCheckNode(arg);
3429534289
if (!checkTypeRelatedToAndOptionallyElaborate(checkArgType, paramType, relation, reportErrors ? effectiveCheckArgumentNode : undefined, effectiveCheckArgumentNode, headMessage, containingMessageChain, errorOutputContainer)) {
3429634290
Debug.assert(!reportErrors || !!errorOutputContainer.errors, "parameter should have errors when reporting errors");
@@ -34754,7 +34748,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3475434748
if (headMessage) {
3475534749
chain = chainDiagnosticMessages(chain, headMessage);
3475634750
}
34757-
const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain);
34751+
const diags = getSignatureApplicabilityError(node, args, last, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, () => chain, /*inferenceContext*/ undefined);
3475834752
if (diags) {
3475934753
for (const d of diags) {
3476034754
if (last.declaration && candidatesForArgumentError.length > 3) {
@@ -34776,7 +34770,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3477634770
let i = 0;
3477734771
for (const c of candidatesForArgumentError) {
3477834772
const chain = () => chainDiagnosticMessages(/*details*/ undefined, Diagnostics.Overload_0_of_1_2_gave_the_following_error, i + 1, candidates.length, signatureToString(c));
34779-
const diags = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, chain);
34773+
const diags = getSignatureApplicabilityError(node, args, c, assignableRelation, CheckMode.Normal, /*reportErrors*/ true, chain, /*inferenceContext*/ undefined);
3478034774
if (diags) {
3478134775
if (diags.length <= min) {
3478234776
min = diags.length;
@@ -34865,15 +34859,15 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3486534859
if (some(typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
3486634860
return undefined;
3486734861
}
34868-
if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
34862+
if (getSignatureApplicabilityError(node, args, candidate, relation, CheckMode.Normal, /*reportErrors*/ false, /*containingMessageChain*/ undefined, /*inferenceContext*/ undefined)) {
3486934863
candidatesForArgumentError = [candidate];
3487034864
return undefined;
3487134865
}
3487234866
return candidate;
3487334867
}
3487434868

3487534869
for (let candidateIndex = 0; candidateIndex < candidates.length; candidateIndex++) {
34876-
let candidate = candidates[candidateIndex];
34870+
const candidate = candidates[candidateIndex];
3487734871
if (!hasCorrectTypeArgumentArity(candidate, typeArguments) || !hasCorrectArity(node, args, candidate, signatureHelpTrailingComma)) {
3487834872
continue;
3487934873
}
@@ -34882,11 +34876,6 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3488234876
let inferenceContext: InferenceContext | undefined;
3488334877

3488434878
if (candidate.typeParameters) {
34885-
// If we are *inside the body of candidate*, we need to create a clone of `candidate` with differing type parameter identities,
34886-
// so our inference results for this call doesn't pollute expression types referencing the outer type parameter!
34887-
if (candidate.declaration && findAncestor(node, a => a === candidate.declaration)) {
34888-
candidate = getImplementationSignature(candidate);
34889-
}
3489034879
let typeArgumentTypes: readonly Type[] | undefined;
3489134880
if (some(typeArguments)) {
3489234881
typeArgumentTypes = checkTypeArguments(candidate, typeArguments, /*reportErrors*/ false);
@@ -34896,7 +34885,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3489634885
}
3489734886
}
3489834887
else {
34899-
inferenceContext = createInferenceContext(candidate.typeParameters!, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
34888+
inferenceContext = createInferenceContext(candidate.typeParameters, candidate, /*flags*/ isInJSFile(node) ? InferenceFlags.AnyDefault : InferenceFlags.None);
3490034889
// The resulting type arguments are instantiated with the inference context mapper, as the inferred types may still contain references to the inference context's
3490134890
// type variables via contextual projection. These are kept generic until all inferences are locked in, so the dependencies expressed can pass constraint checks.
3490234891
typeArgumentTypes = instantiateTypes(inferTypeArguments(node, candidate, args, argCheckMode | CheckMode.SkipGenericFunctions, inferenceContext), inferenceContext.nonFixingMapper);
@@ -34913,7 +34902,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3491334902
else {
3491434903
checkCandidate = candidate;
3491534904
}
34916-
if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
34905+
if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined, inferenceContext)) {
3491734906
// Give preference to error candidates that have no rest parameters (as they are more specific)
3491834907
(candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate);
3491934908
continue;
@@ -34933,7 +34922,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
3493334922
continue;
3493434923
}
3493534924
}
34936-
if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined)) {
34925+
if (getSignatureApplicabilityError(node, args, checkCandidate, relation, argCheckMode, /*reportErrors*/ false, /*containingMessageChain*/ undefined, inferenceContext)) {
3493734926
// Give preference to error candidates that have no rest parameters (as they are more specific)
3493834927
(candidatesForArgumentError || (candidatesForArgumentError = [])).push(checkCandidate);
3493934928
continue;

src/compiler/types.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6819,8 +6819,6 @@ export interface Signature {
68196819
isolatedSignatureType?: ObjectType; // A manufactured type that just contains the signature for purposes of signature comparison
68206820
/** @internal */
68216821
instantiations?: Map<string, Signature>; // Generic signature instantiation cache
6822-
/** @internal */
6823-
implementationSignatureCache?: Signature; // Copy of the signature with fresh type parameters to use in checking the body of a potentially self-referential generic function (deferred)
68246822
}
68256823

68266824
export const enum IndexKind {
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
//// [tests/cases/compiler/genericCallWithinOwnBodyCastTypeParameterIdentity.ts] ////
2+
3+
//// [genericCallWithinOwnBodyCastTypeParameterIdentity.ts]
4+
interface Thenable<Value> {
5+
then<V>(
6+
onFulfilled: (value: Value) => V | Thenable<V>,
7+
): Thenable<V>;
8+
}
9+
10+
const toThenable = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
11+
(input: Input): Thenable<Result> => {
12+
const result = fn(input)
13+
return {
14+
then<V>(onFulfilled: (value: Result) => V | Thenable<V>) {
15+
return toThenable<V, Result>(onFulfilled)(result as Result)
16+
}
17+
};
18+
}
19+
20+
const toThenableInferred = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
21+
(input: Input): Thenable<Result> => {
22+
const result = fn(input)
23+
return {
24+
then(onFulfilled) {
25+
return toThenable(onFulfilled)(result as Result)
26+
}
27+
};
28+
}
29+
30+
31+
//// [genericCallWithinOwnBodyCastTypeParameterIdentity.js]
32+
"use strict";
33+
var toThenable = function (fn) {
34+
return function (input) {
35+
var result = fn(input);
36+
return {
37+
then: function (onFulfilled) {
38+
return toThenable(onFulfilled)(result);
39+
}
40+
};
41+
};
42+
};
43+
var toThenableInferred = function (fn) {
44+
return function (input) {
45+
var result = fn(input);
46+
return {
47+
then: function (onFulfilled) {
48+
return toThenable(onFulfilled)(result);
49+
}
50+
};
51+
};
52+
};
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//// [tests/cases/compiler/genericCallWithinOwnBodyCastTypeParameterIdentity.ts] ////
2+
3+
=== genericCallWithinOwnBodyCastTypeParameterIdentity.ts ===
4+
interface Thenable<Value> {
5+
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
6+
>Value : Symbol(Value, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 19))
7+
8+
then<V>(
9+
>then : Symbol(Thenable.then, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 27))
10+
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 9))
11+
12+
onFulfilled: (value: Value) => V | Thenable<V>,
13+
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 12))
14+
>value : Symbol(value, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 2, 22))
15+
>Value : Symbol(Value, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 19))
16+
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 9))
17+
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
18+
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 9))
19+
20+
): Thenable<V>;
21+
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
22+
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 1, 9))
23+
}
24+
25+
const toThenable = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
26+
>toThenable : Symbol(toThenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 5))
27+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
28+
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 27))
29+
>fn : Symbol(fn, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 35))
30+
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 40))
31+
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 27))
32+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
33+
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
34+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
35+
36+
(input: Input): Thenable<Result> => {
37+
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 7, 5))
38+
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 27))
39+
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
40+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
41+
42+
const result = fn(input)
43+
>result : Symbol(result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 8, 13))
44+
>fn : Symbol(fn, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 35))
45+
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 7, 5))
46+
47+
return {
48+
then<V>(onFulfilled: (value: Result) => V | Thenable<V>) {
49+
>then : Symbol(then, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 9, 16))
50+
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 17))
51+
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 20))
52+
>value : Symbol(value, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 34))
53+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
54+
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 17))
55+
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
56+
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 17))
57+
58+
return toThenable<V, Result>(onFulfilled)(result as Result)
59+
>toThenable : Symbol(toThenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 5))
60+
>V : Symbol(V, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 17))
61+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
62+
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 10, 20))
63+
>result : Symbol(result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 8, 13))
64+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 20))
65+
}
66+
};
67+
}
68+
69+
const toThenableInferred = <Result, Input>(fn: (input: Input) => Result | Thenable<Result>) =>
70+
>toThenableInferred : Symbol(toThenableInferred, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 5))
71+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
72+
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 35))
73+
>fn : Symbol(fn, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 43))
74+
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 48))
75+
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 35))
76+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
77+
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
78+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
79+
80+
(input: Input): Thenable<Result> => {
81+
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 17, 5))
82+
>Input : Symbol(Input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 35))
83+
>Thenable : Symbol(Thenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 0, 0))
84+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
85+
86+
const result = fn(input)
87+
>result : Symbol(result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 18, 13))
88+
>fn : Symbol(fn, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 43))
89+
>input : Symbol(input, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 17, 5))
90+
91+
return {
92+
then(onFulfilled) {
93+
>then : Symbol(then, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 19, 16))
94+
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 20, 17))
95+
96+
return toThenable(onFulfilled)(result as Result)
97+
>toThenable : Symbol(toThenable, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 6, 5))
98+
>onFulfilled : Symbol(onFulfilled, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 20, 17))
99+
>result : Symbol(result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 18, 13))
100+
>Result : Symbol(Result, Decl(genericCallWithinOwnBodyCastTypeParameterIdentity.ts, 16, 28))
101+
}
102+
};
103+
}
104+

0 commit comments

Comments
 (0)