-
-
Notifications
You must be signed in to change notification settings - Fork 661
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
Class build loop detection breaks everything. #6567
Comments
To get an idea about what's happening you can remove the |
If you don't want to change the compiler, try sending a minimal reproducible example without any library involved |
This seems to be a case of follow-when-building, I reduced the example to this: Main.hx @:build(Macro.build())
class BuiltBase {}
class Base extends BuiltBase {}
class A extends Base {}
class B extends Base {} VDom.hx class VDom {
static function f() new HtmlFragment();
} HtmlFragment .hx class HtmlFragment {
public function new() {}
} Macro.hx #if macro
import haxe.macro.Context;
class Macro {
static function build() {
switch Context.getType("VDom") {
case TInst(_.get() => cl, _):
for (f in cl.statics.get())
Context.follow(f.type);
case _:
}
return [];
}
}
#end |
Sanitized cdebug for that:
|
I'm not sure what do to with this. Trying to type things while in a build macro is unsound. Depending on the things being currently on the typing stack (in our case build Main.Base) we might enter an infinite loop which is what happens here. This is because typing requires all classes to be built. Typing without it if we want to turn the whole thing into a lazy process would require to perform a cl_build() everytime we access a TInst class value in the whole compiler code... Now it's true that before we might have let things error silently so if you were lucky you didn't hit into a problem, but that does not mean it was correctly working. @back2dos do you perform / trigger typing in your example ? What's the basis for it ? |
The problem comes from subclasses with build macro. We require before entering typing that all classes are built, but we can't built the subclasses because we are currently building the superclass. An approach would be to ignore such cases, but then that would require to store theses "skipped builds" somewhere and put them back into the task list after we have finished building the superclass so they don't get skipped (which would cause problems later) |
Stupid question: why exactly does the typing of Because as it is, there is nothing cyclic in the code. It's not like the build macro of B triggers building of A which then goes to access the fields of B or something. Otherwise put: shouldn't |
It's not about cycle. Before entering expression typing we need to make sure that all pending classes structure are correctly populated, so we need to build all of them, because we will not check/trigger such build everytime we access the class structure/fields |
What if we had something like this: and tclass_structure = {
mutable cl_fields : (string, tclass_field) PMap.t;
mutable cl_statics : (string, tclass_field) PMap.t;
mutable cl_ordered_statics : tclass_field list;
mutable cl_ordered_fields : tclass_field list;
}
and tclass = {
mutable cl_structure : unit -> tclass_structure;
} And then the |
I guess |
That is not an easy change.
…On Tue, Sep 26, 2017 at 10:05 AM, Simon Krajewski ***@***.***> wrote:
I guess cl_constructor would have to go in there too...
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#6567 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AA-bwDelRtc5jYPal26ICPZzSwSMFrn8ks5smLBjgaJpZM4PRVUO>
.
|
Generally, having the build of one class depend on the structure of another is very useful. It's what syntactic delegation works in tink_lang. And it's how one would have to implement something like But: in all of these use cases, one doesn't need "the full information". Would it be any easier if we said that getting the fields doesn't require to start expression typing? I think one really only needs to know that the field is a |
FWIW I found my way around this. But I'm personally still a bit worried/puzzled by "Trying to type things while in a build macro is unsound." although I haven't fully grasped the implications. I think there are good use cases for the build macro of one class being able to operate based on the structure of another class and it would be great to have some information on when that's possible and when it isn't. |
It's a limitation due to our architecture. But acknowledging that and addressing it are two separate things here. |
@Simn is there any solution for it? |
When in a build macro, try to avoid triggering expression typing. For example, you might be able to generate macro calls in the returned fields, that will get run later, i.e. during the expression typing. |
@back2dos thank you for the tip. |
Does anyone know what the status is here? We fixed some related things. |
Hmm, dunno. The status is that the commit I linked introduced a regression. I suppose there are good reasons, but it's not exactly transparent why this restriction got added or even really what the restriction is. I've found ways not to run into this, but it feels like flying blind. So yeah, if this works as intended, some sort of explanation would be great. Thanks ;) |
This is still reproducible |
The problem is that the compiler tries to flush all the types, while it should only flush types pulled by haxe/src/typing/typeloadModule.ml Lines 975 to 977 in c4d5230
|
We can't do partial flushes atm :-/
…On Wed, Jul 3, 2019 at 9:26 AM Aleksandr Kuzmenko ***@***.***> wrote:
The problem is that the compiler tries to flush all the types, while it
should only flush types pulled by Context.getType("VDom"):
https://github.com/HaxeFoundation/haxe/blob/c4d523088e1767c608132ba5a2590c7a663e5328/src/typing/typeloadModule.ml#L975-L977
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#6567?email_source=notifications&email_token=AAHZXQALJOKB6UU5UAKI2XLP5RIC5A5CNFSM4D2FKUHKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODZDRJLI#issuecomment-507974829>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAHZXQBDS7B4D5NKZ7YUSLDP5RIC5ANCNFSM4D2FKUHA>
.
|
This is occuring subequent to a parse with the usage of tink_await. I am trying to isolate the issue, but it is very confusing. Effectively in a class hierarchy (C extends B extends A), there is It says effectively: C.hx (lines from the Type signature to the end): Loop in class building prevent compiler termination (B) The confusing part is that this is occurring in a Map class hierarchy (effectively advanced Map classes of increasing functionality). I have an almost identical class hierarchy for Array, where this is not occurring. I thought I would try to isolate in my code first instead of building an example from scratch, but it's very unclear why this is happening on Map but not Array, I think it may have to do entirely with ordering. The Array.B type equivalent is parsed and built almost immedietly (maybe because the letter A(rray) comes a lot earlier than M(ap)), and the map types are hit recursively for parsing from an edge from a different type instead of through their direct position in the packages directory structure. |
|
Good to know, however my base Map does use StringMap. This was not resolved for my issue even with significant debugging but not examining compiler code, My issue is super weird, if I take the content of B and put it in C, it compiles. B doesn't have any tink_await calls or any building at all except for SyntaxHub and my autoBuild whih doesn't do anything. |
Personally, I think I found my ways to not running into this anymore. Is there a chance someone who understands how and when this does and doesn't work adding an explanation to the manual under macro-limitations or macro-type-building? Otherwise, please close. |
Reopening this because I'm currently working on the typer pass system, and I'd at least try to address this. Nadakos example is very nicely isolated and should allow some investigation. |
Are there any updates about this issue? |
I get this error a lot: acaa3ec#diff-4a35a028da1fe67ee6a21fbd5305d08cR3127
Minimal example (save as
WindowManager.hx
and compile withhaxe -lib coconut.vdom WindowManager -js whatever.js
):There is nothing cyclic going on anywhere, so I wonder if the detection logic itself is flawed/based on assumptions that I break. My guess is that the issue could be caused by the fact that there's two build macros, one being
@:autoBuild
oncoconut.ui.View
and one being a global one (per--macro addGlobalMetadata
) from tink_syntaxhub.FWIW this code (well actually, the whole project, which is far more complex) certainly did not prevent the compiler from terminating, so I have to wonder what's wrong here.
The text was updated successfully, but these errors were encountered: