diff --git a/src/compiler/hxb/hxbReader.ml b/src/compiler/hxb/hxbReader.ml index 0f5e8074d61..aa20a40a449 100644 --- a/src/compiler/hxb/hxbReader.ml +++ b/src/compiler/hxb/hxbReader.ml @@ -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) = diff --git a/src/compiler/hxb/hxbWriter.ml b/src/compiler/hxb/hxbWriter.ml index 23ea698e153..d426221c52b 100644 --- a/src/compiler/hxb/hxbWriter.ml +++ b/src/compiler/hxb/hxbWriter.ml @@ -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; } @@ -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 @@ -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 @@ -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; @@ -1059,7 +1059,7 @@ 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; @@ -1067,15 +1067,14 @@ module HxbWriter = struct 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 @@ -1083,7 +1082,8 @@ module HxbWriter = struct 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 *) @@ -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; @@ -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; @@ -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; } diff --git a/tests/server/src/cases/issues/Issue11589.hx b/tests/server/src/cases/issues/Issue11589.hx new file mode 100644 index 00000000000..2f75aaa89ca --- /dev/null +++ b/tests/server/src/cases/issues/Issue11589.hx @@ -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); + } +} diff --git a/tests/server/test/templates/issues/Issue11589/Main.hx b/tests/server/test/templates/issues/Issue11589/Main.hx new file mode 100644 index 00000000000..8ca9cd6ae2f --- /dev/null +++ b/tests/server/test/templates/issues/Issue11589/Main.hx @@ -0,0 +1,3 @@ +function main() {} + +typedef Foo = {} & { foo:T } diff --git a/tests/server/test/templates/issues/Issue11589/Main1.hx b/tests/server/test/templates/issues/Issue11589/Main1.hx new file mode 100644 index 00000000000..b219dc81c53 --- /dev/null +++ b/tests/server/test/templates/issues/Issue11589/Main1.hx @@ -0,0 +1,8 @@ +function main() {} + +typedef Foo = { foo : { bar : T } } + +typedef Bar = { + function foo( elements : Array<{ value : T }> ) : Void; + function bar( foo : T, bar : { baz : Bool } ) : Void; +} diff --git a/tests/server/test/templates/issues/Issue11589/Main2.hx b/tests/server/test/templates/issues/Issue11589/Main2.hx new file mode 100644 index 00000000000..ab3ad3a2a41 --- /dev/null +++ b/tests/server/test/templates/issues/Issue11589/Main2.hx @@ -0,0 +1,6 @@ +function main() { + foo(""); +} + +function foo(v:T):Foo return {foo:{bar:v}} +typedef Foo = { foo : { bar : T } }