Skip to content

Improve module method checks #283

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

Merged
merged 17 commits into from
Mar 10, 2025

Conversation

FlandiaYingman
Copy link

@FlandiaYingman FlandiaYingman commented Feb 19, 2025

This PR improves the module method checks introduced in #233, and makes preparation in order to move all the checks to the resolution stage. It also fixes:

the problem that "module" parameters were not treated as modules

:e
fun f8(module m: M) = m

the problem that self referencing modules were not treated as modules

module Foo with
  val self = this

the problem that term definitions returning a module were not treated as modules

module A with
  fun f() = 2

module B with
  val a: module A = A

print(B.a) // B.a should be a module, and should be rejected passing to a regular parameter

@LPTK LPTK marked this pull request as draft February 19, 2025 06:47
@FlandiaYingman FlandiaYingman changed the title [WIP] Improve module method checks Improve module method checks Feb 19, 2025
@FlandiaYingman FlandiaYingman marked this pull request as ready for review February 19, 2025 06:52
@FlandiaYingman FlandiaYingman force-pushed the move-module-method-checks branch from bb1da72 to ce9abc4 Compare February 23, 2025 09:04
@FlandiaYingman
Copy link
Author

class Foo(val z) with
  blah

should now be elaborated into

class Foo(z‹123) with
  val member:z124= z123›
  blah

I didn't differentiate class Foo(val z) and class Foo(z) (they all elaborated to an additional val binding member:z) because all current tests seem to use the latter. But I think this behavior can be easily modified if we want.

FlandiaYingman and others added 2 commits March 7, 2025 20:07
@FlandiaYingman
Copy link
Author

I changed a lot of tests to replace all class definitions that have parameters with data class definitions.

I also checked them so to not add data modifier to some class definitions (especially those in mlscript/basics) that obviously do not require the data semantic.

Copy link
Contributor

@LPTK LPTK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice change, thanks!

Maybe @CAG2Mark you could take a quick look at the lifter changes?

@LPTK LPTK requested a review from CAG2Mark March 8, 2025 09:19
Copy link
Contributor

@CAG2Mark CAG2Mark left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM with regards to the lifter. I've left one minor comment and a reply to another comment.
(p.s. the lifter logic is quite complicated, so good job on figuring it out :P)

BTW @LPTK it seems that VarSymbols are often created inside later IR passes because it's unavoidable, but you mentioned a while ago that VarSymbols all come from user defined variables. I think that in the future, it would be good to add a field to VarSymbol such as isUserDefined to make this distinction more explicit.

@LPTK LPTK assigned FlandiaYingman and unassigned CAG2Mark Mar 8, 2025
@CAG2Mark
Copy link
Contributor

CAG2Mark commented Mar 8, 2025

@AnsonYeung This PR may be of interest to you since it might change the way you need to call super in the handler lowering. I've described the changes here #283 (comment)

@AnsonYeung
Copy link

so preCtor is also for generating the field assignment, is there any reason for handling aux param differently? I don’t think it causes issue with handler lowering. In fact I think if preCtor and ctor is combined into a single block then it would be trivial to fix one of the current broken case with super call being effectful.

@CAG2Mark
Copy link
Contributor

CAG2Mark commented Mar 8, 2025

so preCtor is also for generating the field assignment, is there any reason for handling aux param differently? I don’t think it causes issue with handler lowering. In fact I think if preCtor and ctor is combined into a single block then it would be trivial to fix one of the current broken case with super call being effectful.

Probably because it's currently assumed to be handled by the front-end (but we don't have aux params in the front-end yet) but you're right. Though doing this will require even more changes in the lifter.

@LPTK
Copy link
Contributor

LPTK commented Mar 10, 2025

is there any reason for handling aux param differently?

They should definitely be handled the same. The only difference is that thesae params won't get val semantics implicitly when using data class, unlike the main parameters.

In fact I think if preCtor and ctor is combined into a single block then it would be trivial to fix one of the current broken case with super call being effectful.

Weren't you the one who introduced the preCtor field in the first place? 😛

In e37d8f8#diff-72bbb753659dd44a5e47f3cd0b3954e4ee95fda127ca491a2c267461779c60fbR126

What was the purpose of using a separate block, and does that still make sense now?

@AnsonYeung
Copy link

AnsonYeung commented Mar 10, 2025

I'm not sure about it now. Does lifter need it now (as I think it may need to insert some extra fields)? The original intent was just a hack to insert super calls before JSBuilder emits the field initializations.

In any case, I am completely fine with it being removed now.

@LPTK
Copy link
Contributor

LPTK commented Mar 10, 2025

@AnsonYeung Ok, we'll probably want to remove it in a later PR.

@CAG2Mark
Copy link
Contributor

On another note (sorry for putting so many extra comments in this PR), I think the toString function for classes should also be generated in an earlier phase. This could, for example, allow toString to benefit from stack safe recursion (which was actually a problem we ran into in our benchmarking; it would stack overflow).

@LPTK
Copy link
Contributor

LPTK commented Mar 10, 2025

@CAG2Mark Thanks for the suggestion. I intend for toString to be changed to a simpler call to some rendering function defined externally, so this should no longer be a problem. Note that we already have this problematic test case:

let foo = Foo(null)
//│ foo = Foo(null)
set foo.x = foo
:fixme // Support showing cyclic values
foo
//│ ═══[RUNTIME ERROR] RangeError: Maximum call stack size exceeded

Copy link
Contributor

@LPTK LPTK left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@LPTK LPTK merged commit b0b5a26 into hkust-taco:hkmc2 Mar 10, 2025
1 check passed
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.

4 participants