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

Rework module resolution #11168

Merged
merged 57 commits into from
Oct 20, 2023
Merged

Rework module resolution #11168

merged 57 commits into from
Oct 20, 2023

Conversation

Simn
Copy link
Member

@Simn Simn commented Apr 20, 2023

This changes resolution behavior to consistently consider lexical appearance instead of always preferring enum constructors. Previously, the typer would keep 3 separate lists:

  1. A list of module imports
  2. A list of "global" imports
  3. A list of wildcard imports

This PR merges those into a single list, in which they are distinguished by a variant type. Identifier resolution then walks through that list and compares all imports in-order. This means that this changes the specified resolution behavior and is a breaking change.

Additionally, resolution now treats its own types and statics as if they were imported, and caches this information in ctx.m.own_resolution. This fixes #9197.

Aliasing

The implementation of import X as y was changed by giving all imports an implicit alias name, which is what resolution compares against. For types, it's the type name and for fields it's the field name. As a consequence, we no longer introduce special typedefs to make this work, which caused one display test to fail. I will track this in #8660.

Field imports

One problem with field imports is that by the time we're processing imports initially, we don't know a module's structure yet. To deal with that, the current implementation passed a context_init object around which manages the delays for such fields. I have removed that completely and instead introduced the resolution kind RLazy.

You can think of RLazy as a placeholder in the resolution list, which then expands itself when it's time to resolve a field. So a resolution list like [Type1, Type2, RLazy, Type3] then becomes [Type1, Type2, Field1, Field2, Type3]. This ensures that the lexical order is maintained.

This functionality is also used to deal with enum and enum abstract constructors: When we add a type import, we also add an RLazy in front of it which might resolve to a list of constructors. This gives us the same behavior as before.

Breaking...

I'm not sure how much this will break in practice, but it's definitely a specification change. Once we merge this, I'll consider the path to Haxe 5 open. Before that, I'd appreciate if people could test their codebases on this branch and report problems.

I'll also make sure to run this on https://benchs.haxe.org/ before merging. There's a chance that this linear kind of lookup performs worse than the previous implementation, although that one also wasn't exactly optimized. If this turns out to be a problem, we can look into adding a proper lookup cache, which might be a good idea anyway.

Also closes third-oldest open issue #2729.

@skial skial mentioned this pull request Apr 20, 2023
1 task
@Simn Simn marked this pull request as ready for review April 20, 2023 14:19
@Simn
Copy link
Member Author

Simn commented Apr 20, 2023

This should be ready, or at least as ready as it will be for the time being. I have updated the initial post to explain what's happening. Now waiting for CI to behave so that I can benchmark.

@kLabz Could you try this branch with Shiro codebases, and whatever else you find that might be interesting?

@kLabz
Copy link
Contributor

kLabz commented Apr 20, 2023

I will try to find some time this week-end (worst case I'll do it on Monday)

@Simn
Copy link
Member Author

Simn commented Apr 21, 2023

There's a strange case in heap's Quat.hx module: At the top of the file it has using hxd.Math; which means there's an implied import. Throughout the file, it accesses some fields that clearly come from that class, such as Math.invSqrt and Math.EPSILON.

However, inside the pow function it calls Math.log and Math.exp which do not exist on hxd.Math. This must mean that they are resolved on std/Math, but I don't understand how that's possible because the using hxd.Math should completely shadow that.

I'm currently in a state of confusion.

@Simn
Copy link
Member Author

Simn commented Sep 28, 2023

We're working towards merging this. Some libraries are going to need updates because they rely on unintended importing behavior. However, all fixes required can be made in a way that is compatible with both Haxe 4 and 5.

@Simn
Copy link
Member Author

Simn commented Oct 19, 2023

Unfortunately, the benchmarks for this don't look good:

brave_fqWO2tfhJJ

While it's not massively slower, the graph suggests that this doesn't scale well in larger projects. It's quite difficult to determine the cause of this accurately, but we'll have to look into that.

Edit: Actually, these results are not recent. But I doubt the more recent results will look much different.

@Simn
Copy link
Member Author

Simn commented Oct 20, 2023

Good news: After running the benchmarks again with the current version, the results look much better:

brave_mAf7f439P6

@Simn
Copy link
Member Author

Simn commented Oct 20, 2023

@kLabz Could you check Shiro codebases with https://github.com/HaxeFoundation/haxe/tree/module_resolution_no_weirdness? I still want to make that change too (for #9150), but if it causes too much friction right now we can wait a bit.

for now
@Simn Simn merged commit d0016c9 into development Oct 20, 2023
122 checks passed
@Simn Simn deleted the module_resolution branch October 20, 2023 06:58
0b1kn00b pushed a commit to 0b1kn00b/haxe that referenced this pull request Jan 25, 2024
* start on m.module_resolution

* support static inits

* finish module_globals removal

* remove wildcard_packages

* get cursed resolution tests to pass

* add some debug and a test of the current behavior (see HaxeFoundation#9197)

* remove early import resolving and fix python test

* turn into class

* add RLazy

* (finally) remove context_init

* don't expand for type lookups

* fix 2/3 of broken display test

* rename some things

* make immutable

* add own_resolution

* avoid some duplicate lookuppery

* distinguish class and abstract statics

* move enum expansion to resolution_list

* move to own module

* add test for alias conflict

* add test

#closes 2729

* add actual resolve method and try some caching

* change expected enum typing

* try something different

* merge aliases into resolution_kind

* remove add_l

* add some timers and a type import cache

* deal with weirdness

* remove weird import lookup

see HaxeFoundation#9150

* meh

* asdfg

* keep weird handling for now to have CI green

* investigate

* add timer for flush_pass

* add absurd amount of timers

* Revert "add absurd amount of timers"

This reverts commit 1c49717.

* Revert "add timer for flush_pass"

This reverts commit 935946b.

* Revert "investigate"

This reverts commit de52786.

* fix test

* Remove unused open

* remove timers

for now

---------

Co-authored-by: Rudy Ges <[email protected]>
@kLabz kLabz mentioned this pull request Feb 18, 2024
19 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

enumerators obscure classes
2 participants