-
Notifications
You must be signed in to change notification settings - Fork 12.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
nested generic function inference causes unbound type parameter leak #55467
Comments
This is like the third or fourth bug Iβve seen recently involving an unbound type parameter escaping from a generic. I wonder if they all have the same root causeβ¦ |
I also found type parameters can leak from how TypeScript treats |
This is an interesting one :)
Perhaps using a different priority when inferring from a rest parameter would do the trick here? Even much simpler cases could benefit from this because this one looks like a completely legit call that should succeed: declare function fn<A extends readonly unknown[]>(arg: (...args: A) => void, ...args: A): A
const inferred = fn((a: number) => {}, 1, 2) // Expected 2 arguments, but got 3.(2554)
// ^? const inferred: [a: number] That said, even when I forced the covariant inference in the case from this thread, I still got a leak through the That can be fixed by instantiating the return type of the resolved signature: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 072ed10aa7..12f8872cc4 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -15477,7 +15477,7 @@ export function createTypeChecker(host: TypeCheckerHost): TypeChecker {
if (!pushTypeResolution(signature, TypeSystemPropertyName.ResolvedReturnType)) {
return errorType;
}
- let type = signature.target ? instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper) :
+ let type = signature.target ? instantiateType(instantiateType(getReturnTypeOfSignature(signature.target), signature.mapper), signature.mapper) :
signature.compositeSignatures ? instantiateType(getUnionOrIntersectionType(map(signature.compositeSignatures, getReturnTypeOfSignature), signature.compositeKind, UnionReduction.Subtype), signature.mapper) :
getReturnTypeFromAnnotation(signature.declaration!) ||
(nodeIsMissing((signature.declaration as FunctionLikeDeclaration).body) ? anyType : getReturnTypeFromBody(signature.declaration as FunctionLikeDeclaration)); But even then the type arguments lists are still displayed as uninstantiated so even more work has to be done around this to fix it: const leak = call(wrap(<T,>(x: T) => x), 1)
// ^? const leak: number
// ^? function call<[number], A[0]>(x: { x: (args_0: number) => number; }, args_0: number): number
// ^? function wrap<<A[0]>(x: A[0]) => A[0]>(x: <A[0]>(x: A[0]) => A[0]): { x: <A[0]>(x: A[0]) => A[0]; } That said... this is probably not the only source of such leaks related to nested inferences. So a more general approach would still be needed to avoid them in other situations. This infers something that depends on |
@Andarist is right, there's a lot going wrong here to make this leak happen, though the particulars of how a specific inference is chosen don't matter too much.
I'm working on something that hits up all those points at #57403, but it'll take a bit to find a place for the fix to land that doesn't break anything, particularly with regards to instantiation changes. |
@weswigham funny enough i was also looking at #43961 over the weekend and discovered exactly what u mention here from the point 3 to 5, I had to pause the investigation before I managed to work around the point 5 π itβs worth adding a test case based on that extra issue into ur PR unless it turns out to add another layer of complexity to this that should be fixed later |
π Search Terms
unbound generic, unbound type parameter
π Version & Regression Information
This is the behavior in every version I tried, and I reviewed the FAQ.
β― Playground Link
https://www.typescriptlang.org/play?jsx=0#code/CYUwxgNghgTiAEAzArgOzAFwJYHtXwHcYoAHAHgA0A+ACgA8AueCgSiYG95Hn4BfAKFCRYCFOmx54YKBAhkAgvBB0MIVMADO8KKgCeAbQC6AGngAVWt07caAOnuwA5hqbyW8ALxVzfU-dtOLvBuTGb8-GB4GhjwECBQANaeUjIQNESkNGQW9KHuXlwspgCMLPwA9OXw1fAAegD8-EA
π» Code
π Actual behavior
The type of
leak
involves an unbound type parameter.π Expected behavior
The type of
leak
should benumber
.Additional information about the issue
No response
The text was updated successfully, but these errors were encountered: