tools icon indicating copy to clipboard operation
tools copied to clipboard

feat: Support extends constraints on infer type

Open nissy-dev opened this issue 2 years ago • 1 comments

Summary

Part of #2400

This PR is initial implementation for "extends constraints on infer type" released in TS.4.7.

Test Plan

I add some parser tests and confirmed the prettier tests are almost passed. The only following case is not passed, so I'm currently considering about how to pass it.

type X9<U, T> = T extends (infer U extends number ? U : T ) ? U : T

nissy-dev avatar Dec 08 '22 14:12 nissy-dev

Deploy Preview for docs-rometools ready!

Built without sensitive environment variables

Name Link
Latest commit f5c64b547ff0f375abffdca55e2864728cafeebf
Latest deploy log https://app.netlify.com/sites/docs-rometools/deploys/63aec6217424ba000a5e3852
Deploy Preview https://deploy-preview-4018--docs-rometools.netlify.app/playground
Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site settings.

netlify[bot] avatar Dec 08 '22 14:12 netlify[bot]

@MichaReiser Thank you for your review! I updated codes based on your comments. Currently, I struggle with two edge case. The first case (EdgeCase1) is that it is not sufficient for the parser to check one token ahead. The second case (EdgeCase2) is that parse failed because of removing parentheses. I would appreciate if you could give me some advice.

type EdgeCase1<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0;
type EdgeCase2<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;

Log

  ✖ expected `?` but instead found `;`

  > 1 │ type EdgeCase2<T> = T extends (...a: any[]) => infer R extends string ? R : never;
      │                                                                            ^
    2 │

nissy-dev avatar Dec 19 '22 06:12 nissy-dev

@MichaReiser Thank you for your review! I updated codes based on your comments. Currently, I struggle with two edge case. The first case (EdgeCase1) is that it is not sufficient for the parser to check one token ahead. The second case (EdgeCase2) is that parse failed because of removing parentheses. I would appreciate if you could give me some advice.

type EdgeCase1<T> = T extends { [P in infer U extends keyof T ? 1 : 0]: 1; } ? 1 : 0;
type EdgeCase2<T> = T extends ((...a: any[]) => infer R extends string) ? R : never;

Log

  ✖ expected `?` but instead found `;`

  > 1 │ type EdgeCase2<T> = T extends (...a: any[]) => infer R extends string ? R : never;
      │                                                                            ^
    2 │

I looked into this more closely because it wasn't clear to me why the parsing is failing, and I created a draft PR that uses try_parse and allows conditional places in a few more places. In my opinion it would be good to explore if the DisallowConditionalTypes flag would be moved into a new TypesContext that works similar to ExpressionContext and is passed down everywhere where we parse types. It makes it easier to debug and reason about the code (with the downside of it needing to be passed explicitly)

Case 1

You can use the try_parse function for speculative parsing when a fixed lookahead isn't sufficient (as it is in this case because you need to look if the type is followed by a ? token and the type could be of multiple tokens).

Case 2

Not entirely sure but I think the issue here is that you missed to allow conditional types.

MichaReiser avatar Dec 20 '22 10:12 MichaReiser

!bench_parser

MichaReiser avatar Dec 23 '22 08:12 MichaReiser

Thanks for updating the PR.

Do you plan to refactor the code to use a TypeContext instead of extending the ParserState?

There are a few tests failing that should pass

  • type Equals = A extends () => B extends C ? D : E ? F : G;
  • type Equals<A, B, C, D, E, F, G> = A extends (x: B extends C ? D : E) => 0 ? F : G; This one fails for typescript too but should be easy to fix by wrapping the parse_ts_type call in parse_ts_parenthesized_type with an allow()

MichaReiser avatar Dec 23 '22 08:12 MichaReiser

Parser Benchmark Results

group                                 main                                   pr
-----                                 ----                                   --
parser/big5-added.json                1.02    255.6±8.00µs    66.1 MB/sec    1.00    251.6±9.27µs    67.1 MB/sec
parser/canada.json                    1.00    131.7±5.82ms    16.3 MB/sec    1.02    134.5±7.79ms    16.0 MB/sec
parser/checker.ts                     1.01    165.3±5.63ms    15.7 MB/sec    1.00    163.8±5.31ms    15.9 MB/sec
parser/compiler.js                    1.00     95.1±2.44ms    11.0 MB/sec    1.01     95.8±2.85ms    10.9 MB/sec
parser/d3.min.js                      1.01     57.7±2.46ms     4.5 MB/sec    1.00     57.1±2.48ms     4.6 MB/sec
parser/db.json                        1.01      6.4±0.20ms    27.9 MB/sec    1.00      6.3±0.22ms    28.3 MB/sec
parser/dojo.js                        1.01      4.7±0.11ms    14.7 MB/sec    1.00      4.6±0.13ms    14.8 MB/sec
parser/eucjp.json                     1.01   424.7±12.61µs    92.2 MB/sec    1.00   419.5±16.00µs    93.4 MB/sec
parser/ios.d.ts                       1.01    142.5±5.10ms    13.1 MB/sec    1.00    141.0±4.43ms    13.2 MB/sec
parser/jquery.min.js                  1.02     14.8±0.50ms     5.6 MB/sec    1.00     14.5±0.46ms     5.7 MB/sec
parser/math.js                        1.01    115.4±4.57ms     5.6 MB/sec    1.00    114.8±3.98ms     5.6 MB/sec
parser/package-lock.json              1.00      2.6±0.09ms    52.9 MB/sec    1.00      2.6±0.07ms    53.1 MB/sec
parser/parser.ts                      1.02      3.3±0.09ms    14.6 MB/sec    1.00      3.3±0.09ms    14.8 MB/sec
parser/pixi.min.js                    1.03     73.4±2.87ms     6.0 MB/sec    1.00     71.2±2.24ms     6.2 MB/sec
parser/react-dom.production.min.js    1.00     20.3±1.15ms     5.7 MB/sec    1.01     20.5±1.08ms     5.6 MB/sec
parser/react.production.min.js        1.04  1040.6±54.70µs     5.9 MB/sec    1.00  1005.2±35.11µs     6.1 MB/sec
parser/router.ts                      1.00  1308.9±33.94µs    23.5 MB/sec    1.00  1307.9±45.11µs    23.5 MB/sec
parser/tex-chtml-full.js              1.01    155.4±4.52ms     5.9 MB/sec    1.00    153.8±4.54ms     5.9 MB/sec
parser/three.min.js                   1.02     81.0±2.80ms     7.3 MB/sec    1.00     79.7±2.73ms     7.4 MB/sec
parser/typescript.js                  1.01   650.6±12.95ms    14.6 MB/sec    1.00   647.1±12.37ms    14.7 MB/sec
parser/vue.global.prod.js             1.00     25.1±1.20ms     4.8 MB/sec    1.04     26.1±1.23ms     4.6 MB/sec

github-actions[bot] avatar Dec 23 '22 09:12 github-actions[bot]

@MichaReiser Thank you for your reviews and i'm so sorry for a late response. I really appreciate the time you spent on this. I learned a lot about how to handle parser contexts and use try_parse from your PR.

I would like to do the refactoring and fix the failing tests if possible, but it will be the day after tomorrow before I can start. This task might have been a bit difficult for me. Therefore, I am willing to have you continue the task on your end.

nissy-dev avatar Dec 23 '22 15:12 nissy-dev

@MichaReiser

Thank you for your reviews and i'm so sorry for a late response. I really appreciate the time you spent on this. I learned a lot about how to handle parser contexts and use try_parse from your PR.

I would like to do the refactoring and fix the failing tests if possible, but it will be the day after tomorrow before I can start. This task might have been a bit difficult for me. Therefore, I am willing to have you continue the task on your end.

That's alright. We're all taking a few days off. Enjoy the holidays

MichaReiser avatar Dec 23 '22 22:12 MichaReiser

There are a few tests failing that should pass

I could fix these tests and pass all prettier tests!

Do you plan to refactor the code to use a TypeContext instead of extending the ParserState?

I tried to refactor in a few days and made PR https://github.com/nissy-dev/tools/pull/6. If the PR is not so different from your thought, I will merge it into this PR and continue to review.

nissy-dev avatar Dec 25 '22 15:12 nissy-dev

There are a few tests failing that should pass

I could fix these tests and pass all prettier tests!

Do you plan to refactor the code to use a TypeContext instead of extending the ParserState?

I tried to refactor in a few days and made PR nissy-dev#6. If the PR is not so different from your thought, I will merge it into this PR and continue to review.

This PR and your other PR looks good. The only thing that we need to be careful about is to make sure to pass context through correctly and only use TypeContext::default in positions where a type starts a complete new context (because it is parenthesized)

MichaReiser avatar Dec 28 '22 14:12 MichaReiser

The only thing that we need to be careful about is to make sure to pass context through correctly and only use TypeContext::default in positions where a type starts a complete new context (because it is parenthesized)

If the scope of the refactoring is up to making sure the context is passed correctly, I think it is better to separate PR about the refactoring task. This is because there are too many functions which the context should be passed and this refactoring affects many logic.

And then, it is really hard for me to pass context through correctly. I tried, but I couldn't do that. I would like you to do this refactoring on your end if possible.

nissy-dev avatar Dec 29 '22 15:12 nissy-dev

That sounds good to me. Thank you @nissy-dev for another excellent parser contribution!

MichaReiser avatar Dec 30 '22 09:12 MichaReiser

!bench_parser

MichaReiser avatar Dec 30 '22 11:12 MichaReiser

Parser Benchmark Results

group                                 main                                   pr
-----                                 ----                                   --
parser/big5-added.json                1.02    193.1±0.55µs    87.5 MB/sec    1.00    189.4±0.30µs    89.2 MB/sec
parser/canada.json                    1.01     88.3±2.16ms    24.3 MB/sec    1.00     87.8±2.78ms    24.4 MB/sec
parser/checker.ts                     1.00    114.7±1.49ms    22.7 MB/sec    1.02    117.3±1.59ms    22.2 MB/sec
parser/compiler.js                    1.00     65.9±0.86ms    15.9 MB/sec    1.04     68.3±0.71ms    15.3 MB/sec
parser/d3.min.js                      1.00     40.3±0.32ms     6.5 MB/sec    1.05     42.3±0.35ms     6.2 MB/sec
parser/db.json                        1.00      4.8±0.02ms    37.1 MB/sec    1.00      4.9±0.02ms    36.9 MB/sec
parser/dojo.js                        1.00      3.7±0.01ms    18.8 MB/sec    1.05      3.8±0.00ms    17.9 MB/sec
parser/eucjp.json                     1.00    329.7±0.28µs   118.8 MB/sec    1.00    329.6±0.19µs   118.8 MB/sec
parser/ios.d.ts                       1.00     95.7±1.19ms    19.5 MB/sec    1.04     99.6±1.77ms    18.7 MB/sec
parser/jquery.min.js                  1.00     11.0±0.03ms     7.5 MB/sec    1.05     11.6±0.03ms     7.1 MB/sec
parser/math.js                        1.00     78.1±0.84ms     8.3 MB/sec    1.05     82.2±0.86ms     7.9 MB/sec
parser/package-lock.json              1.00      2.0±0.01ms    68.3 MB/sec    1.00      2.0±0.01ms    68.5 MB/sec
parser/parser.ts                      1.00      2.6±0.01ms    18.8 MB/sec    1.04      2.7±0.01ms    18.0 MB/sec
parser/pixi.min.js                    1.00     50.5±0.70ms     8.7 MB/sec    1.03     52.0±0.73ms     8.4 MB/sec
parser/react-dom.production.min.js    1.00     14.7±0.03ms     7.8 MB/sec    1.05     15.5±0.07ms     7.4 MB/sec
parser/react.production.min.js        1.00    737.0±9.81µs     8.3 MB/sec    1.06    777.8±2.23µs     7.9 MB/sec
parser/router.ts                      1.00   1001.8±1.71µs    30.7 MB/sec    1.04   1046.3±6.15µs    29.4 MB/sec
parser/tex-chtml-full.js              1.00    110.0±2.13ms     8.3 MB/sec    1.00    110.6±1.03ms     8.2 MB/sec
parser/three.min.js                   1.00     54.6±0.63ms    10.8 MB/sec    1.05     57.3±0.64ms    10.2 MB/sec
parser/typescript.js                  1.00    438.1±4.36ms    21.7 MB/sec    1.04    456.4±5.08ms    20.8 MB/sec
parser/vue.global.prod.js             1.00     17.9±0.07ms     6.7 MB/sec    1.08     19.2±0.11ms     6.3 MB/sec

github-actions[bot] avatar Dec 30 '22 11:12 github-actions[bot]