Repository: TypeScript
Issue: Inner inference doesn't inherit the contextual type from the outer one in argument position
Labels: Bug

# Bug Report

### 🔎 Search Terms

contextual type nested inference

### 🕗 Version & Regression Information

- This is the behavior in every version I tried

### ⏯ Playground Link

[Playground link with relevant code](https://www.typescriptlang.org/play?ts=5.0.0-dev.20230220#code/MYewdgzgLgBAtgQysAFgUwE4wLwwMoCecARiADYAUARAAJQQC0ADklJmAPSLLoZUCUAbgBQwqASZoYAWSSpMABQwgoIUGQA8ASzBMArlAB8OGAG9hMeHJQAuGBoCShigDcEZPWjsOYAHxg6+lD8OMYuIFoAJiIAviLCOmwYAGYIwFKyPJjaugbG5pYA2tzyGAC6FPx2maVKKmrkOUGGsaLikjAKrOwaCMbYFn4y1tl9g-4UCDBoAB5sYJEQMBhoCJHgZAQwhQhgBAA0MAB0J7sEZYOWlgD8Zsur62Cb2zqRswFgMADWaAQgyTAEGU7F0oEkwL1Cq9ZmVjDFLlc7FNZvNFjAQMQAFZoYBQBE3O4rNYbLaFL4fb6-f6A4GdboYCEIMmwmDwq6IwFCNoSDLWbT9MyDADuWigKA0TGmczQCyWoPB-OcLDB7DsTCqMHCUVi8TewDICBWMGSejAuK04CsPCaeVc7k8dkCBg1NXFTqMIj1BqNJrNUAtn1NAZtUEOTCWKJlaMK8p67sMhxOR1jDJDhkKZVhFEGSeV4IgaogwhdIwwac9OO9Ul95stQvQEPdYalqKWdo8Xg+QRC2GMpq+YBAQrAzkGTBWkS0wCQnaYxeqpfLog4HBgYpAECkKAQLikxGUP0+OmSmBl6SLJXFVAQVCGVGIVGc14ERxFYooQfA1Bv-C5K-ZAGAUBVwAHrXKIl4aM+d4Pk+P6DP+dCMLMki4gwmDKBgOZvigH5gAG1BiloSzETAQrKGAADmAhcpY-6geBwiQdB-j3o+34vjh2Z0auRFLBAKAgHoZCRDAg6wMQUi7NMGCYYcEA6OkMAAAYzMpMACUJIkwJJKkAOQIHpQx6cQenqbsoniSp-aDsOynCg2FAUDMPb5DAZBoLACB2CxMBsSYMyCPcUB6AyMCBay-AIauYHFvE-7rpuMDbruMCgLJOKwMep5mmgF58qYa48j5N4wbeMTOIV7SdtBMT8K+oq4QURWSHYn5gBx-D7NF7KxXV8SQVVxV+aVrEPqylUtTVpV1Q177NYh9DoTMqFQOhskgFhljVW1+FflQfEBEs5HgNRXU9Qxwj9RBBVTSVt5jeVk07SN5X1VxzUvfWMpOS5oR3B5Xn3WVAVBSsIVhRFdXdTxvXgddQA)

### 💻 Code

```ts
const matcher = Symbol("@ts-pattern/matcher");

type MatcherProtocol<input> = {
  match: <I>(value: I | input) => void;
};

interface Matcher<input> {
  [matcher](): MatcherProtocol<input>;
}

type Pattern<a> =
  | Matcher<a>
  | (a extends readonly [any, ...any]
      ? { readonly [index in keyof a]: Pattern<a[index]> }
      : a extends object
      ? { readonly [k in keyof a]: Pattern<a[k]> }
      : a);

type Match<i> = {
  with<p extends Pattern<i>>(pattern: p): void;
};

declare function match<input>(value: input): Match<input>;
declare function union<input, ps extends [Pattern<input>, ...Pattern<input>[]]>(
  ...patterns: ps
): Matcher<input>;
declare function when<input, p extends (value: input) => unknown>(
  predicate: p
): Matcher<input>;

// those have broken inferences
match<"a" | "b">("a").with(union("a"));

match<"a" | "b">("a")
  // @ts-expect-error
  .with(union("this is wrong"));

match<"a" | "b">("a").with(
  // this should not be an error, since `x` should be `'a' | 'b'` and not `unknown`
  when((x) => { let a: "a" | "b" = x; return x; })
);

// those have correct inferences
match<{ type: "a" | "b" }>({ type: "a" }).with({
  type: union("a"),
});

match<{ type: "a" | "b" }>({ type: "a" }).with({
  // @ts-expect-error
  type: union("this is wrong"),
});

match<{ type: "a" | "b" }>({ type: "a" }).with({
  type: when((x) => { let a: "a" | "b" = x; return x; }),
});
```

### 🙁 Actual behavior

In cases with `match<"a" | "b">("a").with(...)` the inference is broken whereas in cases with `match<{ type: "a" | "b" }>({ type: "a" }).with(...)` things work as expected.

### 🙂 Expected behavior

Both cases should work the same as the position in the `with`'s argument should not matter.

---

This is a distilled case from [ts-pattern](https://github.com/gvergnaud/ts-pattern/) by @gvergnaud . The real thing (equivalent of this repro case) can be tested out in this [TS playground](https://www.typescriptlang.org/play?ts=5.0.0-dev.20230220#code/JYWwDg9gTgLgBAbziAhjAxgCwDRwApwC+cAZlBCHAEQwDOAtGGjAKZQB2VA3HAPS9wYATzAtaALjgAWAHQBGGVIBQS-oMwRaLOJhQA3bQCNyAaxbs4wdiTbn0YpagyYAPFRRU4AH2qGqAPgAKdyoAShkAd2AYTEC8GQBXdmAIdmCPUNxAgA9QuABefzhcrhUnLDcPb18A9LClOD4BAAE6ehZs0XQYdqhyKAa4SOjY+KSUtJpMYFpLWYjydgBzMKzcgqKSsrQKkOqqPyCQ8KiYwMH4iMxzQJy8wsRBxrUYmbhaDQSAGwATOHYIPBDNoUBY2P1cLQrPY4AADbKw96fX5wYFwgDkKHR1XRhnRiNBfwB8FhSRMAIi7FhTzgXxY8BQkj2PgOnnyxVKjUaUHpCQ4HMGhEygzuG2KSlCpVUAhimm0ugMcHQ0B53Us1ls7HstEcO1cSGEoiZVRZfiIQQNIhYxs8QuGZ0GCBphut+ESyVSdWFjUI2BF6we2QlUvK+sEVpt+zNhAt4aN1CqdtOsUdNLUrQYHS6PXB0GdEbd409UzebwWqRW3qIfsaosDwe2zhclvjzJq5sCLddeyTI3OjSdXLjrsu1zSdaKg6HtPpcEZCc8prZAuncB5MD5FmynK5Qpr1f9902DaAA).

In the broken case, in `inferTypeParameters` (for the nested call):
- the [`contextualType`](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L32119) is `p`
- the [`inferenceTargetType`](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L32121) is `Matcher<input>`
- and the `instantiatedType` gets calculated as `never` since it's using [the `outerMapper` with `InferenceFlags.NoDefault`](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L32139). This in turn assigns `silentNeverType` to the `inferredType` [here](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L24987-L24990)
- all of this leads to inferring `unknown` when a better inference could have been found (`Pattern<'a' | 'b'>`)

In the working case, within the same `inferTypeParameters` we get those:
- `inferenceTargetType` -> `Matcher<input>`
- `contextualType` -> `Pattern<"a" | "b">`
- `instantiatedType`: `Pattern<"a" | "b">`

It's worth noting down that `outerMapper` is the same in both cases (`p -> never`) but in the working case it's simply not used because the `contextualType` has no type variables so `instantiateTypeWithAlias` returns early with the supplied argument [here](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L18875-L18877) (`Pattern<"a" | "b">`).

Looking at the previous steps we can learn that the returned `contextualType` here is better in the working case because [`getContextualTypeForObjectLiteralElement` checks `getApparentTypeOfContextualType`](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L28989) and there:
- [`contextualType`](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L29133-L29135) -> `p`
- [`instantiatedType`](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L29136) -> `p`
- [`apparentType`](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L29138) -> `Pattern<{ type: "a" | "b"; }>`

Thanks to that the `getTypeOfPropertyOfContextualType` can return `Pattern<"a" | "b">` [here](https://github.dev/microsoft/TypeScript/blob/c6fb2e10dcdf4839924a4288dae1cfd93b3c1c57/src/compiler/checker.ts#L28996) in the `getContextualTypeForObjectLiteralElement`.

It's also worth noting that the current version of `ts-pattern` works OK because we can "observe" this whole `silentNeverType` in the userland (which, I think, shouldn't be possible) [here](https://github.com/gvergnaud/ts-pattern/commit/12aa9d38e935e181d8e49418d0df59742bf9a3ff#diff-2a614f2c1e3a277d612a1442290ba3d24933207799bbcd8ed2fa887e8a8e299fR40-R48) and we can return there what we originally expected there to be computed for us. The minimal repro case from this issue with this "hack" being applied can be found [here](https://www.typescriptlang.org/play?ts=5.0.0-dev.20230220#code/MYewdgzgLgBAtgQysAFgUwE4wLwwMoCecARiADYAUARAAJQQC0ADklJmAPSLLoZUCUAbgBQwqASZoYAWSSpMABQwgoIUGQA8ASzBMArlAB8OGAG9hMeHJQAuGBoCShigDcEZPWjsOYAHxg6+lD8OMYuIFoAJiIAviLCOmwYAGYIwFKyPJjaugbG5pYA2tzyGAC6FPx2maVKKmrkOUGGsaLikjAKrOwaCMbYFn4y1tl9g-4UCDBoAB5sYJEQMBhoCJHgZAQwhQhgBAA0MAB0J7sEZYOWlgD8Zsur62Cb2zqRswFgMADWaAQgyTAEGU7F0oEkwL1Cq9ZmVjDFLlc7FNZvNFjAQMQAFZoYBQBE3O4rNYbLaFL4fb6-f6A4GdboYCEIMmwmDwq6IwFCNoSKQOCAAOTQLmyABV+tsRWVpnM0AsloUwELMFLbgBGGB2AAM3I6NRQ2nFBRgAHctFB9UxpailqDwQbnCwwexvAKlRgNExjCjZWj1bdbT0tMY7EwqjBwlFYvE3sAyAgVjBknowLitOArDwmnlXO5PHZAgYw3qs0YRDG4wmkymoGnPsnayXDkwlt65dsAwyS4ZDicjh2IQWjIUyrCKINe47wRAQxBhEWRu7By1hOX41Iq6n08b0APclAm1afUscx4vB8giFsMZk18wCBjWBnIMmCtIlpgEgz0w59UF134hwHAwOaIAQFIKAIMKMDEMoPyfDoySYLK6SziU+pUAgVBDFQxBUM4GECEcprmhQ9bgNQmH8FygHsrRdH0VcAB61yiGhGgEdhuH4ZRgw0XQjCzJIuIMJgygYOOxEoKRYC1tQ5paEsCkmsoYAAOYCFylg0UxLHCGxHH+DheEUYRkljlpQHyUsEAoCAehkJEMB3rAxBSLs0wYGJhwQDo6QwAABjM-kwDZdkOdBUj+QA5AgUVDFFxBRcFuyOc5AU3neD7+YM26yhQFAzJe+QwGQaCwAgdgGTARkmDMgj3FAegMjAdWsvwvFAcxc4AZZtlgTAEFQaAnk4rACFISmaCodYGimMBPKVZhnFYTEzhze0Z4cTE-BEWaUlGhtdhkWAJn8PsHXsl123xGx60LdVS2GbhrJrfNkiLStO1mUafH0CJMxCVAImeSA4mWIdMDHXJKBKUpxoqepZ0XTpwjXaxM13e9D1YU9K2vRDW1fXtFAHfduUnQVRV3KV5UfcttX1SsjXNa123nRZl0sWjQA)