Skip to content

Commit

Permalink
[hxb] detect need for local context in nested anons (#11617)
Browse files Browse the repository at this point in the history
* [hxb] detect need for local context in nested anons

* [hxb] add compiler failure message

* [tests] add tests for 11589

* [tests] add original Hide issue too

* [hxb] handle another edge case
  • Loading branch information
kLabz committed Mar 27, 2024
1 parent 1423a5f commit ea964ad
Show file tree
Hide file tree
Showing 6 changed files with 75 additions and 15 deletions.
17 changes: 16 additions & 1 deletion src/compiler/hxb/hxbReader.ml
Original file line number Diff line number Diff line change
Expand Up @@ -1973,11 +1973,26 @@ class hxb_reader
| EOM ->
incr stats.modules_fully_restored;

method private die chunk msg =
let msg =
(Printf.sprintf "Compiler failure while reading hxb chunk %s of %s: %s\n" (string_of_chunk_kind chunk) (s_type_path mpath) (msg))
^ "Please submit an issue at https://github.com/HaxeFoundation/haxe/issues/new\n"
^ "Attach the following information:"
in
let backtrace = Printexc.raw_backtrace_to_string (Printexc.get_raw_backtrace ()) in
let s = Printf.sprintf "%s\nHaxe: %s\n%s" msg s_version_full backtrace in
failwith s

method private read_chunk_data kind =
let path = String.concat "_" (ExtLib.String.nsplit (s_type_path mpath) ".") in
let id = ["hxb";"read";string_of_chunk_kind kind;path] in
let close = Timer.timer id in
self#read_chunk_data' kind;
try
self#read_chunk_data' kind
with Invalid_argument msg -> begin
close();
self#die kind msg
end;
close()

method read_chunks (new_api : hxb_reader_api) (chunks : cached_chunks) =
Expand Down
29 changes: 15 additions & 14 deletions src/compiler/hxb/hxbWriter.ml
Original file line number Diff line number Diff line change
Expand Up @@ -469,6 +469,7 @@ type hxb_writer = {
mutable local_type_parameters : (typed_type_param,unit) IdentityPool.t;
mutable field_stack : unit list;
mutable wrote_local_type_param : bool;
mutable needs_local_context : bool;
unbound_ttp : (typed_type_param,unit) IdentityPool.t;
t_instance_chunk : Chunk.t;
}
Expand Down Expand Up @@ -1006,12 +1007,11 @@ module HxbWriter = struct
write_pos writer v.v_pos

let rec write_anon writer (an : tanon) =
let needs_local_context = ref false in
let write_fields () =
let restore = start_temporary_chunk writer 256 in
let i = ref 0 in
PMap.iter (fun _ cf ->
write_anon_field_ref writer needs_local_context cf;
write_anon_field_ref writer cf;
incr i;
) an.a_fields;
let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
Expand All @@ -1035,8 +1035,7 @@ module HxbWriter = struct
assert false
| AbstractStatics _ ->
assert false
end;
!needs_local_context
end

and write_anon_ref writer (an : tanon) =
let pfm = Option.get (writer.anon_id#identify_anon ~strict:true an) in
Expand All @@ -1046,9 +1045,10 @@ module HxbWriter = struct
Chunk.write_uleb128 writer.chunk index
with Not_found ->
let restore = start_temporary_chunk writer 256 in
let needs_local_context = write_anon writer an in
writer.needs_local_context <- false;
write_anon writer an;
let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
if needs_local_context then begin
if writer.needs_local_context then begin
let index = Pool.add writer.anons pfm.pfm_path None in
Chunk.write_u8 writer.chunk 1;
Chunk.write_uleb128 writer.chunk index;
Expand All @@ -1059,31 +1059,31 @@ module HxbWriter = struct
Chunk.write_uleb128 writer.chunk index;
end

and write_anon_field_ref writer needs_local_context cf =
and write_anon_field_ref writer cf =
try
let index = HashedIdentityPool.get writer.anon_fields cf.cf_name cf in
Chunk.write_u8 writer.chunk 0;
Chunk.write_uleb128 writer.chunk index
with Not_found ->
let restore = start_temporary_chunk writer 256 in
let old = writer.wrote_local_type_param in
writer.wrote_local_type_param <- false;
ignore(write_class_field_and_overloads_data writer true cf);
let wrote_local_type_param = writer.wrote_local_type_param in
writer.wrote_local_type_param <- old;
let bytes = restore (fun new_chunk -> Chunk.get_bytes new_chunk) in
if wrote_local_type_param then begin
if writer.needs_local_context || writer.wrote_local_type_param then begin
(* If we access something from the method scope, we have to write the anon field immediately.
This should be fine because in such cases the field cannot be referenced elsewhere. *)
let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf None in
needs_local_context := true;
writer.needs_local_context <- true;
Chunk.write_u8 writer.chunk 1;
Chunk.write_uleb128 writer.chunk index;
Chunk.write_bytes writer.chunk bytes
end else begin
let index = HashedIdentityPool.add writer.anon_fields cf.cf_name cf (Some bytes) in
Chunk.write_u8 writer.chunk 0;
Chunk.write_uleb128 writer.chunk index;
end
end;
writer.wrote_local_type_param <- old

(* Type instances *)

Expand Down Expand Up @@ -1565,7 +1565,7 @@ module HxbWriter = struct
| TField(e1,FAnon cf) ->
Chunk.write_u8 writer.chunk 104;
loop e1;
write_anon_field_ref writer (ref false) cf;
write_anon_field_ref writer cf;
true;
| TField(e1,FClosure(Some(c,tl),cf)) ->
Chunk.write_u8 writer.chunk 105;
Expand All @@ -1577,7 +1577,7 @@ module HxbWriter = struct
| TField(e1,FClosure(None,cf)) ->
Chunk.write_u8 writer.chunk 106;
loop e1;
write_anon_field_ref writer (ref false) cf;
write_anon_field_ref writer cf;
true;
| TField(e1,FEnum(en,ef)) ->
Chunk.write_u8 writer.chunk 107;
Expand Down Expand Up @@ -2312,6 +2312,7 @@ let create config warn anon_id =
local_type_parameters = IdentityPool.create ();
field_stack = [];
wrote_local_type_param = false;
needs_local_context = false;
unbound_ttp = IdentityPool.create ();
t_instance_chunk = Chunk.create EOM cp 32;
}
Expand Down
27 changes: 27 additions & 0 deletions tests/server/src/cases/issues/Issue11589.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package cases.issues;

class Issue11589 extends TestCase {
function test(_) {
vfs.putContent("Main.hx", getTemplate("issues/Issue11589/Main.hx"));
var args = ["--main", "Main.hx", "--no-output"];
runHaxe(args);
runHaxe(args);
Assert.isFalse(lastResult.hasError);
}

function testNestedField(_) {
vfs.putContent("Main.hx", getTemplate("issues/Issue11589/Main1.hx"));
var args = ["--main", "Main.hx", "--no-output"];
runHaxe(args);
runHaxe(args);
Assert.isFalse(lastResult.hasError);
}

function testNestedFieldUsed(_) {
vfs.putContent("Main.hx", getTemplate("issues/Issue11589/Main2.hx"));
var args = ["--main", "Main.hx", "--no-output"];
runHaxe(args);
runHaxe(args);
Assert.isFalse(lastResult.hasError);
}
}
3 changes: 3 additions & 0 deletions tests/server/test/templates/issues/Issue11589/Main.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
function main() {}

typedef Foo<T> = {} & { foo:T }
8 changes: 8 additions & 0 deletions tests/server/test/templates/issues/Issue11589/Main1.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
function main() {}

typedef Foo<T> = { foo : { bar : T } }

typedef Bar<T> = {
function foo( elements : Array<{ value : T }> ) : Void;
function bar( foo : T, bar : { baz : Bool } ) : Void;
}
6 changes: 6 additions & 0 deletions tests/server/test/templates/issues/Issue11589/Main2.hx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
function main() {
foo("");
}

function foo<T>(v:T):Foo<T> return {foo:{bar:v}}
typedef Foo<T> = { foo : { bar : T } }

0 comments on commit ea964ad

Please sign in to comment.