Skip to content
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

top-down type inference, implements rfc 149 #20091

Merged
merged 23 commits into from
Aug 24, 2022
Merged

Conversation

metagn
Copy link
Collaborator

@metagn metagn commented Jul 26, 2022

refs nim-lang/RFCs#149, closes nim-lang/RFCs#36

Name copied from Haxe manual

Proof of concept for adding top-down type inference on top of the validating style inference used by fitNode. (I think this is called "bidirectional typing"). Each expression can opt-in to this and define their own behaviors.

Todo

  • assignments
  • let/var/const type annotations
  • blocks/statement lists
  • if/case/try branches
  • if/while conditions
  • set literal elements
  • array literal elements
  • seq literal elements (if @ is overloaded, only activates if you call system.`@`)
  • tuple elements
  • object constructors
  • table constructor
  • proc body inference based on return type
  • string literal (cstrings)
  • nil literal
  • generalized overload specification
  • surface level range types
  • document
  • better refactor for expectedType?
  • please review style use etc, don't know the best style to use in many cases here

Notes

Performance should be considered. The biggest performance pitfalls I can think of are the passing of the expectedType parameter everywhere (which isn't that bad because it's basically just an int) and the expectedType != nil checks. Theoretically it should be negligible.

Keeping this as compatible as possible is best, but if needed, it can be made into a compile option (--topDownInference:on) or experimental switch.

fitNode already has errors, so new errors/enforcing expectedType are probably not needed.

Type conversions are left alone.

Current incompatibilities:

Potential extensions outside this PR, can go in new RFC after merge

  • new magic like infer(x: untyped, T: type): T or x as T as opposed to T(x) to ensure compile-time only, costless conversion

  • lambda/do signature inference. not because it would be hard but because I don't want to bother

  • Most useful potential application: Routine arguments. I am not equipped to start this yet but I can think of some ways to do it. All of them could have bad performance.

    • 1. Query all overloads; filter based on param count, named arguments etc; then get the common type of each argument and infer based on those types. Disadvantages are these common types will not give too much information, and varargs/untyped would completely disable arguments where they could be.
    • 2. Gradually type arguments in a row (except untyped arguments) until only 1 overload remains. For example if there are overloads that are like (A, X, Y), (B, X, Y), (C, X, Y), you sem the first argument (not accounting for named arguments) and get A, then only the overload of (A, X, Y) remains, so you know to use X and Y for the remaining arguments. This has the advantage of working with method-style signatures much better. I think this would also be the easiest to do efficiently.
    • 3. Combination of the two. For example if you have (A, X, T1) and (B, X, T2), you can't infer the first argument, you can infer the second argument because the common types are X, but 2 overloads are still remaining, so you can't infer the third argument. This is stronger than 2 (2 cannot infer X) but slower because of the common type calculation.

    I do not see myself doing this any time soon so the implementation details don't have to be up to me.

@Araq
Copy link
Member

Araq commented Jul 26, 2022

Awesome and bounty-worthy!

@metagn metagn changed the title micro implementation of rfc 149 basic implementation of rfc 149 Jul 31, 2022
@metagn metagn changed the title basic implementation of rfc 149 top-down type inference Jul 31, 2022
@metagn metagn changed the title top-down type inference top-down type inference, implements rfc 149 Jul 31, 2022
@Varriount
Copy link
Contributor

Just out of curiosity (I have practically no experience working with the compiler), why use an extra parameter over adding a new field to PContext?

@metagn
Copy link
Collaborator Author

metagn commented Aug 2, 2022

If it could be refactored to that, I would do it, but I am not too confident about it. It would be really hard to keep track of (you would need to think about it for every sem call). For example sometimes you expect bool for if conditions then another type for their branches. Sometimes you are supposed to leave the type empty, like in statement lists until the last statement.

I guess also for now I want the behavior of having nil by default instead of propagating the type. For example if there was a expectType(typ): sem() wrapper, you would have to call expectType(nil): sem() to opt expressions out of it.

@metagn metagn force-pushed the rfc-149 branch 2 times, most recently from b0bfba8 to 33b6f87 Compare August 9, 2022 04:24
metagn added a commit to metagn/Nim that referenced this pull request Aug 11, 2022
Based on what I understand from [Wikipedia](https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year), 2001 does not have 53 weeks, but 2004, 2009, 2015, 2020 do. The years 2000 and 2001 seem to be copy pasted from the `getDaysInYear` example above. The result of `getWeeksInIsoYear` also seem to match up with Wikipedia.

That means these runnableExamples were never tested. Why is this the case? I only discovered this in nim-lang#20091.
ringabout pushed a commit that referenced this pull request Aug 11, 2022
Based on what I understand from [Wikipedia](https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year), 2001 does not have 53 weeks, but 2004, 2009, 2015, 2020 do. The years 2000 and 2001 seem to be copy pasted from the `getDaysInYear` example above. The result of `getWeeksInIsoYear` also seem to match up with Wikipedia.

That means these runnableExamples were never tested. Why is this the case? I only discovered this in #20091.
metagn added a commit to metagn/Nim that referenced this pull request Aug 12, 2022
Based on what I understand from [Wikipedia](https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year), 2001 does not have 53 weeks, but 2004, 2009, 2015, 2020 do. The years 2000 and 2001 seem to be copy pasted from the `getDaysInYear` example above. The result of `getWeeksInIsoYear` also seem to match up with Wikipedia.

That means these runnableExamples were never tested. Why is this the case? I only discovered this in nim-lang#20091.
@metagn metagn marked this pull request as ready for review August 15, 2022 13:16
ringabout added a commit that referenced this pull request Aug 15, 2022
* Improve error message for `strutils.addf` (#20157)

Co-authored-by: ringabout <43030857+ringabout@users.noreply.github.com>

* fixes #20153; do not escape `_` for mysql [backport] (#20164)

* fixes #20153; do not escape `_` for mysql

* add a test

* Update db_mysql.nim

* Update tdb_mysql.nim

Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>

* [minor] don't find `"Hint: gc"` for action (#20170)

* fixes links in the readme (#20167)

* update the docs of arc following up #19749 (#19752)

Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com>

* fixes broken ssl tests (#20181)

* bootstrap the compiler with nimPreviewSlimSystem (#20176)

* bootstrap the compiler with nimPreviewSlimSystem

* threads

* docs: fix some spelling errors (#19816)

* docs: fix some spelling errors

* contributing: fix spelling error

Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>

* Update contributing.md

* Update intern.md

* Update manual.md

* Update manual_experimental_strictnotnil.md

* Update nimgrep_cmdline.txt

* Update pegdocs.txt

* Update testament.md

* Update tut1.md

Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>

* Build compiler with --noNimblePath (#20168)

- Fixes #18840

* help our poor CI; don't run CI on other branches for push (#20184)

* fix broken runnableExamples for getWeeksInIsoYear (#20193)

Based on what I understand from [Wikipedia](https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year), 2001 does not have 53 weeks, but 2004, 2009, 2015, 2020 do. The years 2000 and 2001 seem to be copy pasted from the `getDaysInYear` example above. The result of `getWeeksInIsoYear` also seem to match up with Wikipedia.

That means these runnableExamples were never tested. Why is this the case? I only discovered this in #20091.

* improve deprecation error messages (#20197)

* Show beatutiful html instead of ugly markdown preview (#20196)

* closes #6559; add testcase (#20200)

* CI upgrade to ubuntu-20.04 (#20182)

* CI upgrade to ubuntu-20.04 

The ubuntu-18.04 environment is deprecated, consider switching to ubuntu-20.04(ubuntu-latest), or ubuntu-22.04 instead. For more details see actions/runner-images#6002

* Update azure-pipelines.yml

* Markdown code blocks part 4 (#20189)

No logic was added, just 8 more files have been migrated.

* closes #15316; add testcase (#20213)

* add version-1-6 and version-1-2 to triggered branches (#20214)

* add version-1-6 and version-1-2 to triggered branches

* Update .github/workflows/ci_packages.yml

* use quote

* closes #12955; add testcase (#20223)

* add more

Co-authored-by: konsumlamm <44230978+konsumlamm@users.noreply.github.com>
Co-authored-by: Clay Sweetser <Varriount@users.noreply.github.com>
Co-authored-by: flywind <43030857+xflywind@users.noreply.github.com>
Co-authored-by: ee7 <45465154+ee7@users.noreply.github.com>
Co-authored-by: Ivan Yonchovski <yyoncho@users.noreply.github.com>
Co-authored-by: metagn <metagngn@gmail.com>
Co-authored-by: Andrey Makarov <ph.makarov@gmail.com>
@metagn
Copy link
Collaborator Author

metagn commented Aug 20, 2022

Forgot to comment this is ready for review, it just might be a little painful to do so.

@Araq Araq added the merge_when_passes_CI mergeable once green label Aug 23, 2022
@Araq Araq merged commit 0014b9c into nim-lang:devel Aug 24, 2022
@github-actions
Copy link
Contributor

Thanks for your hard work on this PR!
The lines below are statistics of the Nim compiler built from 0014b9c

Hint: mm: orc; threads: on; opt: speed; options: -d:release
163798 lines; 13.113s; 841.578MiB peakmem

metagn added a commit to metagn/Nim that referenced this pull request Aug 30, 2022
Varriount pushed a commit that referenced this pull request Aug 31, 2022
capocasa pushed a commit to capocasa/Nim that referenced this pull request Mar 31, 2023
Based on what I understand from [Wikipedia](https://en.wikipedia.org/wiki/ISO_week_date#Weeks_per_year), 2001 does not have 53 weeks, but 2004, 2009, 2015, 2020 do. The years 2000 and 2001 seem to be copy pasted from the `getDaysInYear` example above. The result of `getWeeksInIsoYear` also seem to match up with Wikipedia.

That means these runnableExamples were never tested. Why is this the case? I only discovered this in nim-lang#20091.
capocasa pushed a commit to capocasa/Nim that referenced this pull request Mar 31, 2023
* micro implementation of rfc 149

refs nim-lang/RFCs#149

* number/array/seq literals, more statements

* try fix number literal alias issue

* renew expectedType with if/case/try branch types

* fix (nerf) index type handling and float typed int

* use typeAllowed

* tweaks + const test (tested locally) [skip ci]

* fill out more of the checklist

* more literals, change @ order, type conversions

Not copying the full call tree before the typedesc call check
in `semIndirectOp` is also a small performance improvement.

* disable self-conversion warning

* revert type conversions (maybe separate op later)

* deal with CI for now (seems unrelated), try enums

* workaround CI different way

* proper fix

* again

* see sizes

* lol

* overload selection, simplify int literal -> float

* range, new @ solution, try use fitNode for nil

* use new magic

* try fix ranges, new magic, deal with nim-lang#20193

* add documentation, support templates

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
narimiran pushed a commit that referenced this pull request May 11, 2023
* micro implementation of rfc 149

refs nim-lang/RFCs#149

* number/array/seq literals, more statements

* try fix number literal alias issue

* renew expectedType with if/case/try branch types

* fix (nerf) index type handling and float typed int

* use typeAllowed

* tweaks + const test (tested locally) [skip ci]

* fill out more of the checklist

* more literals, change @ order, type conversions

Not copying the full call tree before the typedesc call check
in `semIndirectOp` is also a small performance improvement.

* disable self-conversion warning

* revert type conversions (maybe separate op later)

* deal with CI for now (seems unrelated), try enums

* workaround CI different way

* proper fix

* again

* see sizes

* lol

* overload selection, simplify int literal -> float

* range, new @ solution, try use fitNode for nil

* use new magic

* try fix ranges, new magic, deal with #20193

* add documentation, support templates

Co-authored-by: Andreas Rumpf <rumpf_a@web.de>
(cherry picked from commit 0014b9c)
Araq pushed a commit that referenced this pull request May 10, 2024
refs
#23586 (comment)

In #20091 a bad kind of type inference was mistakenly left in where if
an identifier `abc` had an expected type of an enum type `Enum`, and
`Enum` had a member called `abc`, the identifier would change to be that
enum member. This causes bugs where a local symbol can have the same
name as an enum member but have a different value. I had assumed this
behavior was removed since but it wasn't, and CI seems to pass having it
removed.

A separate PR needs to be made for the 2.0 branch because these lines
were moved around during a refactoring in #23123 which is not in 2.0.
narimiran pushed a commit that referenced this pull request Aug 31, 2024
refs
#23586 (comment)

In #20091 a bad kind of type inference was mistakenly left in where if
an identifier `abc` had an expected type of an enum type `Enum`, and
`Enum` had a member called `abc`, the identifier would change to be that
enum member. This causes bugs where a local symbol can have the same
name as an enum member but have a different value. I had assumed this
behavior was removed since but it wasn't, and CI seems to pass having it
removed.

A separate PR needs to be made for the 2.0 branch because these lines
were moved around during a refactoring in #23123 which is not in 2.0.

(cherry picked from commit c101490)
metagn added a commit to metagn/Nim that referenced this pull request Sep 23, 2024
metagn added a commit that referenced this pull request Sep 23, 2024
…4165)

fixes #24164, regression from #20091

The expression `nil` as the default value of template parameter `x:
untyped` is typechecked with expected type `untyped` since #20091. The
expected type is checked if it matches the `nil` literal with a match
better than a subtype match, and the type is set to it if it does.
However `untyped` matches with a generic match which is better, so the
`nil` literal has type `untyped`. This breaks type matching for the
literal. So if the expected type is `untyped` or `typed`, it is now
ignored and the `nil` literal just has the `nil` type.
narimiran pushed a commit that referenced this pull request Sep 23, 2024
…4165)

fixes #24164, regression from #20091

The expression `nil` as the default value of template parameter `x:
untyped` is typechecked with expected type `untyped` since #20091. The
expected type is checked if it matches the `nil` literal with a match
better than a subtype match, and the type is set to it if it does.
However `untyped` matches with a generic match which is better, so the
`nil` literal has type `untyped`. This breaks type matching for the
literal. So if the expected type is `untyped` or `typed`, it is now
ignored and the `nil` literal just has the `nil` type.

(cherry picked from commit b9de2bb)
metagn added a commit to metagn/Nim that referenced this pull request Nov 19, 2024
Araq pushed a commit that referenced this pull request Nov 19, 2024
closes #24372, refs #20091

This was added in #20091 for some reason but doesn't actually work and
only makes error messages more obscure. So for now, it's disabled.

Can also be backported to 2.0 if necessary.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
merge_when_passes_CI mergeable once green
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[RFC] Change int literal to number literal
3 participants