Преглед на файлове

Merge branch 'development' into hlcode_absolute_jump_offsets

Simon Krajewski преди 2 години
родител
ревизия
aff110cb3d
променени са 35 файла, в които са добавени 414 реда и са изтрити 46 реда
  1. 1 0
      .gitignore
  2. 1 1
      opam
  3. 5 0
      src-json/define.json
  4. 1 0
      src/context/typecore.ml
  5. 1 0
      src/core/tType.ml
  6. 15 5
      src/generators/genjvm.ml
  7. 12 8
      src/generators/genlua.ml
  8. 16 2
      src/generators/genneko.ml
  9. 2 2
      src/generators/jvm/jvmAttribute.ml
  10. 11 5
      src/generators/jvm/jvmBuilder.ml
  11. 1 1
      src/macro/eval/evalStdLib.ml
  12. 35 1
      src/optimization/analyzerTexpr.ml
  13. 1 1
      src/typing/functionArguments.ml
  14. 2 1
      src/typing/generic.ml
  15. 2 1
      src/typing/typeload.ml
  16. 1 1
      src/typing/typeloadFields.ml
  17. 19 14
      src/typing/typer.ml
  18. 70 0
      tests/misc/neko/projects/Issue10937/Main.hx
  19. 1 0
      tests/misc/neko/projects/Issue10937/aaa-setup.hxml
  20. 4 0
      tests/misc/neko/projects/Issue10937/compile.hxml
  21. 1 0
      tests/misc/neko/projects/Issue10937/compile.hxml.stdout
  22. 0 0
      tests/misc/neko/projects/Issue10937/dummy_ndll/ndll/.exists
  23. 2 0
      tests/misc/neko/run.hxml
  24. 37 0
      tests/misc/projects/Issue10961/Main.hx
  25. 2 0
      tests/misc/projects/Issue10961/compile-fail.hxml
  26. 3 0
      tests/misc/projects/Issue10961/compile-fail.hxml.stderr
  27. 22 0
      tests/optimization/src/TestJs.hx
  28. 1 2
      tests/optimization/src/issues/Issue10765.hx
  29. 3 0
      tests/runci/targets/Neko.hx
  30. 2 1
      tests/unit/compile-each.hxml
  31. 24 0
      tests/unit/src/unit/issues/Issue10735.hx
  32. 35 0
      tests/unit/src/unit/issues/Issue10776.hx
  33. 19 0
      tests/unit/src/unit/issues/Issue10867.hx
  34. 12 0
      tests/unit/src/unit/issues/Issue10960.hx
  35. 50 0
      tests/unit/src/unit/issues/Issue11040.hx

+ 1 - 0
.gitignore

@@ -136,3 +136,4 @@ tests/server/test.js.map
 lib.sexp
 src/compiler/version.ml
 tests/party
+tests/misc/projects/Issue10863/error.log

+ 1 - 1
opam

@@ -32,4 +32,4 @@ depends: [
   "conf-zlib"
   "conf-neko"
   "luv"
-]
+]

+ 5 - 0
src-json/define.json

@@ -579,6 +579,11 @@
 		"doc": "GenCommon internal.",
 		"platforms": ["cs", "java"]
 	},
+	{
+		"name": "RetainUntypedMeta",
+		"define": "retain-untyped-meta",
+		"doc": "Prevents arbitrary expression metadata from being discarded upon typing."
+	},
 	{
 		"name": "Scriptable",
 		"define": "scriptable",

+ 1 - 0
src/context/typecore.ml

@@ -71,6 +71,7 @@ type typer_globals = {
 	mutable delayed : (typer_pass * (unit -> unit) list) list;
 	mutable debug_delayed : (typer_pass * ((unit -> unit) * string * typer) list) list;
 	doinline : bool;
+	retain_meta : bool;
 	mutable core_api : typer option;
 	mutable macros : ((unit -> unit) * typer) option;
 	mutable std : module_def;

+ 1 - 0
src/core/tType.ml

@@ -126,6 +126,7 @@ and tvar_kind =
 	| VInlined
 	| VInlinedConstructorVariable
 	| VExtractorVariable
+	| VAbstractThis
 
 and tvar = {
 	mutable v_id : int;

+ 15 - 5
src/generators/genjvm.ml

@@ -269,9 +269,15 @@ module AnnotationHandler = struct
 			| EField(e1,s,_) ->
 				let path = parse_path e1 in
 				AEnum(object_path_sig path,s)
+			| ECall(e1, el) -> 
+				let path = parse_path e1 in
+				let _,name = ExtString.String.replace (snd path) "." "$" in
+				let path = (fst path, name) in
+				let values = List.map parse_value_pair el in 
+				AAnnotation(TObject(path, []),values)	
+				
 			| _ -> Error.typing_error "Expected value expression" (pos e)
-		in
-		let parse_value_pair e = match fst e with
+		and parse_value_pair e = match fst e with
 			| EBinop(OpAssign,(EConst(Ident s),_),e1) ->
 				s,parse_value e1
 			| _ ->
@@ -1933,18 +1939,22 @@ class texpr_to_jvm
 				)
 		| TSwitch(e1,cases,def) ->
 			self#switch ret e1 cases def
-		| TWhile(e1,e2,flag) -> (* TODO: do-while *)
+		| TWhile(e1,e2,flag) ->
 			block_exits <- ExitLoop :: block_exits;
 			let is_true_loop = match (Texpr.skip e1).eexpr with TConst (TBool true) -> true | _ -> false in
 			let continue_label = jm#spawn_label "continue" in
 			let break_label = jm#spawn_label "break" in
 			let body_label = jm#spawn_label "body" in
+			let restore = jm#start_branch in
+			if flag = DoWhile then begin
+				body_label#goto;
+				restore();
+			end;
 			let old_continue = continue in
 			continue <- Some continue_label;
 			let old_break = break in
 			break <- Some break_label;
 			continue_label#here;
-			let restore = jm#start_branch in
 			if not is_true_loop then self#condition false e1 body_label break_label;
 			let pop_scope = jm#push_scope in
 			body_label#here;
@@ -3093,4 +3103,4 @@ let generate jvm_flag com =
 		"\n\n"
 	in
 	gctx.out#add_entry manifest_content "META-INF/MANIFEST.MF";
-	gctx.out#close;
+	gctx.out#close;

+ 12 - 8
src/generators/genlua.ml

@@ -566,20 +566,26 @@ and gen_cond ctx cond =
     gen_value ctx cond;
     ctx.iife_assign <- false
 
-and gen_loop ctx label cond e =
+and gen_loop ctx cond do_while e =
     let old_in_loop = ctx.in_loop in
     ctx.in_loop <- true;
     let old_handle_continue = ctx.handle_continue in
     let will_continue = has_continue e in
     ctx.handle_continue <- has_continue e;
     ctx.break_depth <- ctx.break_depth + 1;
-    if will_continue then begin
+    if will_continue then
         println ctx "local _hx_continue_%i = false;" ctx.break_depth;
-    end;
+    if do_while then
+        println ctx "local _hx_do_first_%i = true;" ctx.break_depth;
     let b = open_block ctx in
-    print ctx "%s " label;
+    print ctx "while ";
     gen_cond ctx cond;
+    if do_while then
+        print ctx " or _hx_do_first_%i" ctx.break_depth;
     print ctx " do ";
+    if do_while then
+        newline ctx;
+        println ctx "_hx_do_first_%i = false;" ctx.break_depth;
     if will_continue then print ctx "repeat ";
     gen_block_element ctx e;
     if will_continue then begin
@@ -955,11 +961,9 @@ and gen_expr ?(local=true) ctx e = begin
         gen_value ctx e;
         spr ctx (Ast.s_unop op)
     | TWhile (cond,e,Ast.NormalWhile) ->
-        gen_loop ctx "while" cond e
+        gen_loop ctx cond false e;
     | TWhile (cond,e,Ast.DoWhile) ->
-        gen_block_element ctx e;
-        newline ctx;
-        gen_loop ctx "while" cond e
+        gen_loop ctx cond true e;
     | TObjectDecl [] ->
         spr ctx "_hx_e()";
         ctx.separator <- true

+ 16 - 2
src/generators/genneko.ml

@@ -675,7 +675,14 @@ let generate_libs_init = function
 					else
 						"/usr/local/lib/haxe/lib/";
 			if( try $loader.loadprim("std@sys_file_type",1)(".haxelib") == "dir" catch e false ) @b = $loader.loadprim("std@file_full_path",1)(".haxelib") + "/";
-			if( $loader.loadprim("std@sys_is64",0)() ) @s = @s + 64;
+			if( $version() >= 240 )
+				@s = @s + switch $loader.loadprim("std@sys_cpu_arch",0)() {
+					"arm64" => "Arm64"
+					"arm" => "Arm"
+					"x86_64" => "64"
+					default => ""
+				};
+			else if( $loader.loadprim("std@sys_is64",0)() ) @s = @s + 64;
 			@b = @b + "/"
 		*)
 		let p = null_pos in
@@ -705,7 +712,14 @@ let generate_libs_init = function
 				),p);
 			],p);
 			(EIf ((ETry (op "==" (call p (loadp "sys_file_type" 1) [str p ".haxelib"]) (str p "dir"),"e",(EConst False,p)),p),op "=" (ident p "@b") (op "+" (call p (loadp "file_full_path" 1) [str p ".haxelib"]) (str p "/")), None),p);
-			(EIf (call p (loadp "sys_is64" 0) [],op "=" es (op "+" es (int p 64)),None),p);
+			(EIf (op ">=" (builtin p "version") (int p 240),
+				(op "=" es (op "+" es (ESwitch (call p (loadp "sys_cpu_arch" 0) [],[
+					(str p "arm64", str p "Arm64");
+					(str p "arm", str p "Arm");
+					(str p "x86_64", str p "64");
+				], Some (str p "")),p))),
+				Some (EIf (call p (loadp "sys_is64" 0) [],op "=" es (op "+" es (int p 64)),None),p)
+			),p);
 			op "=" es (op "+" es (str p "/"));
 		] in
 		let lpath = field p (builtin p "loader") "path" in

+ 2 - 2
src/generators/jvm/jvmAttribute.ml

@@ -167,7 +167,7 @@ let rec write_annotation ch ann =
 			| ValClass i ->
 				write_ui16 ch i
 			| ValAnnotation a ->
-				write_annotation ch ann
+				write_annotation ch a
 			| ValArray annl ->
 				write_array16 ch loop annl
 		in
@@ -250,4 +250,4 @@ let write_attribute pool jvma =
 	{
 		attr_index = pool#add (ConstUtf8 name);
 		attr_data = IO.close_out ch
-	}
+	}

+ 11 - 5
src/generators/jvm/jvmBuilder.ml

@@ -29,6 +29,7 @@ type annotation_kind =
 	| ABool of bool
 	| AEnum of jsignature * string
 	| AArray of annotation_kind list
+	| AAnnotation of jsignature * annotation 
 
 and annotation = (string * annotation_kind) list
 
@@ -37,7 +38,7 @@ type export_config = {
 }
 
 let convert_annotations pool annotations =
-	let a = Array.map (fun (jsig,l) ->
+	let rec process_annotation (jsig, l) = 		
 		let offset = pool#add_string (generate_signature false jsig) in
 		let l = List.map (fun (name,ak) ->
 			let offset = pool#add_string name in
@@ -55,14 +56,19 @@ let convert_annotations pool annotations =
 				| AArray l ->
 					let l = List.map (fun ak -> loop ak) l in
 					'[',ValArray(Array.of_list l)
+				| AAnnotation (jsig, a) -> 
+					let ann = process_annotation (jsig, a) in 
+					'@',ValAnnotation(ann)
+					
 			in
 			offset,loop ak
 		) l in
-		{
+		{ 
 			ann_type = offset;
 			ann_elements = Array.of_list l;
-		}
-	) annotations in
+		} 
+	in  
+	let a = Array.map process_annotation annotations in
 	a
 
 class base_builder = object(self)
@@ -89,4 +95,4 @@ class base_builder = object(self)
 
 	method export_attributes (pool : JvmConstantPool.constant_pool) =
 		DynArray.to_array (DynArray.map (write_attribute pool) attributes)
-end
+end

+ 1 - 1
src/macro/eval/evalStdLib.ml

@@ -1401,7 +1401,7 @@ module StdHost = struct
 
 	let resolve = vfun1 (fun name ->
 		let name = decode_string name in
-		let h = catch_unix_error Unix.gethostbyname name in
+		let h = try Unix.gethostbyname name with Not_found -> exc_string (Printf.sprintf "Could not resolve host %s" name) in
 		let addr = catch_unix_error Unix.string_of_inet_addr h.h_addr_list.(0) in
 		let a, b, c, d = Scanf.sscanf addr "%d.%d.%d.%d" (fun a b c d -> a,b,c,d) in
 		vint32 (Int32.logor (Int32.shift_left (Int32.of_int a) 24) (Int32.of_int (d lor (c lsl 8) lor (b lsl 16))))

+ 35 - 1
src/optimization/analyzerTexpr.ml

@@ -1032,22 +1032,56 @@ module Cleanup = struct
 			| TWhile(e1,e2,NormalWhile) ->
 				let e1 = loop e1 in
 				let e2 = loop e2 in
+				let rec has_continue e = match e.eexpr with
+					| TContinue ->
+						true
+					| _ ->
+						check_expr has_continue e
+				in
+				let has_continue = has_continue e2 in
 				begin match e2.eexpr with
 					| TBlock ({eexpr = TIf(e1,({eexpr = TBlock[{eexpr = TBreak}]} as eb),None)} :: el2) ->
 						let e1 = Texpr.skip e1 in
 						let e1 = match e1.eexpr with TUnop(_,_,e1) -> e1 | _ -> {e1 with eexpr = TUnop(Not,Prefix,e1)} in
 						{e with eexpr = TWhile(e1,{eb with eexpr = TBlock el2},NormalWhile)}
 					| TBlock el ->
+						let do_while = ref None in
+						let locals = ref IntMap.empty in
+						let rec collect_vars e = match e.eexpr with
+							| TVar(v,e1) ->
+								locals := IntMap.add v.v_id true !locals;
+								Option.may collect_vars e1
+							| _ ->
+								Type.iter collect_vars e
+						in
+						let rec references_local e = match e.eexpr with
+							| TLocal v when IntMap.mem v.v_id !locals -> true
+							| _ -> check_expr references_local e
+						in
+						let can_do = match com.platform with Hl -> false | _ -> true in
 						let rec loop2 el = match el with
+							| [{eexpr = TBreak}] when is_true_expr e1 && can_do && not has_continue ->
+								do_while := Some (Texpr.Builder.make_bool com.basic true e1.epos);
+								[]
+							| [{eexpr = TIf(econd,{eexpr = TBlock[{eexpr = TBreak}]},None)}] when is_true_expr e1 && not (references_local econd) && can_do && not has_continue ->
+								do_while := Some econd;
+								[]
 							| {eexpr = TBreak | TContinue | TReturn _ | TThrow _} as e :: el ->
 								[e]
 							| e :: el ->
+								collect_vars e;
 								e :: (loop2 el)
 							| [] ->
 								[]
 						in
 						let el = loop2 el in
-						{e with eexpr = TWhile(e1,{e2 with eexpr = TBlock el},NormalWhile)}
+						begin match !do_while with
+						| None ->
+							{e with eexpr = TWhile(e1,{e2 with eexpr = TBlock el},NormalWhile)}
+						| Some econd ->
+							let econd = {econd with eexpr = TUnop(Not,Prefix,econd)} in
+							{e with eexpr = TWhile(econd,{e2 with eexpr = TBlock el},DoWhile)}
+						end;
 					| _ ->
 						{e with eexpr = TWhile(e1,e2,NormalWhile)}
 				end

+ 1 - 1
src/typing/functionArguments.ml

@@ -46,7 +46,7 @@ class function_arguments
 	(syntax : (placed_name * bool * metadata * type_hint option * expr option) list)
 =
 	let with_default =
-		let l = List.mapi (fun i ((name,pn),opt,m,t,eo) ->
+		let l = List.mapi (fun i ((name,pn),opt,_,t,eo) ->
 			let t = type_arg i opt t pn in
 			let t,eo = type_function_arg ctx t eo opt pn in
 			(name,eo,t)

+ 2 - 1
src/typing/generic.ml

@@ -291,7 +291,7 @@ let rec build_generic_class ctx c p tl =
 				begin try (match cf_old.cf_expr with
 					| None ->
 						begin match cf_old.cf_kind with
-							| Method _ when not (has_class_flag c CInterface) && not (has_class_flag c CExtern) ->
+							| Method _ when not (has_class_flag c CInterface) && not (has_class_flag c CExtern) && not (has_class_field_flag cf_old CfAbstract) ->
 								display_error ctx.com (Printf.sprintf "Field %s has no expression (possible typing order issue)" cf_new.cf_name) cf_new.cf_pos;
 								display_error ctx.com (Printf.sprintf "While building %s" (s_type_path cg.cl_path)) p;
 							| _ ->
@@ -335,6 +335,7 @@ let rec build_generic_class ctx c p tl =
 		TypeloadFunction.add_constructor ctx cg false p;
 		cg.cl_kind <- KGenericInstance (c,tl);
 		if (has_class_flag c CInterface) then add_class_flag cg CInterface;
+		if (has_class_flag c CAbstract) then add_class_flag cg CAbstract;
 		cg.cl_constructor <- (match cg.cl_constructor, c.cl_constructor, c.cl_super with
 			| _, Some cf, _ -> Some (build_field cf)
 			| Some ctor, _, _ -> Some ctor

+ 2 - 1
src/typing/typeload.ml

@@ -524,8 +524,9 @@ and load_complex_type' ctx allow_display (t,p) =
 		let displayed_field = ref None in
 		let rec loop acc f =
 			let n = fst f.cff_name in
+			let pf = snd f.cff_name in
 			let p = f.cff_pos in
-			if PMap.mem n acc then typing_error ("Duplicate field declaration : " ^ n) p;
+			if PMap.mem n acc then typing_error ("Duplicate field declaration : " ^ n) pf;
 			let topt = function
 				| None -> typing_error ("Explicit type required for field " ^ n) p
 				| Some t -> load_complex_type ctx allow_display t

+ 1 - 1
src/typing/typeloadFields.ml

@@ -273,7 +273,7 @@ let transform_abstract_field com this_t a_t a f =
 	| FProp _ when not stat && not (Meta.has Meta.Enum f.cff_meta) ->
 		typing_error "Member property accessors must be get/set or never" p;
 	| FFun fu when fst f.cff_name = "new" && not stat ->
-		let init p = (EVars [mk_evar ~t:this_t ("this",null_pos)],p) in
+		let init p = (EVars [mk_evar ~t:this_t ~meta:([Meta.This,[],null_pos]) ("this",null_pos)],p) in
 		let cast e = (ECast(e,None)),pos e in
 		let ret p = (EReturn (Some (cast (EConst (Ident "this"),p))),p) in
 		let meta = (Meta.NoCompletion,[],null_pos) :: f.cff_meta in

+ 19 - 14
src/typing/typer.ml

@@ -704,7 +704,11 @@ and type_vars ctx vl p =
 					let e = AbstractCast.cast_or_unify ctx t e p in
 					Some e
 			) in
-			let v = add_local_with_origin ctx TVOLocalVariable n t pv in
+			let v = if Meta.has Meta.This ev.ev_meta then
+				add_local ctx VAbstractThis n t pv
+			else
+				add_local_with_origin ctx TVOLocalVariable n t pv
+			in
 			v.v_meta <- ev.ev_meta;
 			DisplayEmitter.check_display_metadata ctx v.v_meta;
 			if ev.ev_final then add_var_flag v VFinal;
@@ -862,16 +866,11 @@ and type_object_decl ctx fl with_type p =
 				when not (Meta.has Meta.CoreType a.a_meta)
 					&& not (List.exists (fun t' -> shallow_eq t t') seen) ->
 				let froms = get_abstract_froms ctx a pl in
-				begin match froms with
-				| [] ->
-					(* If the abstract has no casts in the first place, we can assume plain typing (issue #10730) *)
-					ODKPlain
-				| _ ->
-					let fold = fun acc t' -> match loop (t :: seen) t' with ODKPlain -> acc | t -> t :: acc in
-					begin match List.fold_left fold [] froms with
-						| [t] -> t
-						| _ -> ODKFailed
-					end
+				let fold = fun acc t' -> match loop (t :: seen) t' with ODKPlain -> acc | t -> t :: acc in
+				begin match List.fold_left fold [] froms with
+					| [] -> ODKPlain (* If the abstract has no casts in the first place, we can assume plain typing (issue #10730) *)
+					| [t] -> t
+					| _ -> ODKFailed
 				end
 			| TDynamic (Some t) ->
 				dynamic_parameter := Some t;
@@ -893,7 +892,7 @@ and type_object_decl ctx fl with_type p =
 		let extra_fields = ref [] in
 		let fl = List.map (fun ((n,pn,qs),e) ->
 			let is_valid = Lexer.is_valid_identifier n in
-			if PMap.mem n !fields then typing_error ("Duplicate field in object declaration : " ^ n) p;
+			if PMap.mem n !fields then typing_error ("Duplicate field in object declaration : " ^ n) pn;
 			let is_final = ref false in
 			let e = try
 				let t = match !dynamic_parameter with
@@ -936,7 +935,7 @@ and type_object_decl ctx fl with_type p =
 	let type_plain_fields () =
 		let rec loop (l,acc) ((f,pf,qs),e) =
 			let is_valid = Lexer.is_valid_identifier f in
-			if PMap.mem f acc then typing_error ("Duplicate field in object declaration : " ^ f) p;
+			if PMap.mem f acc then typing_error ("Duplicate field in object declaration : " ^ f) pf;
 			let e = type_expr ctx e (WithType.named_structure_field f) in
 			(match follow e.etype with TAbstract({a_path=[],"Void"},_) -> typing_error "Fields of type Void are not allowed in structures" e.epos | _ -> ());
 			let cf = mk_field f e.etype (punion pf e.epos) pf in
@@ -1685,7 +1684,12 @@ and type_meta ?(mode=MGet) ctx m e1 with_type p =
 		| (Meta.Dollar s,_,p) ->
 			display_error ctx.com (Printf.sprintf "Reification $%s is not allowed outside of `macro` expression" s) p;
 			e()
-		| _ -> e()
+		| _ ->
+			if ctx.g.retain_meta then
+				let e = e() in
+				{e with eexpr = TMeta(m,e)}
+			else
+				e()
 	in
 	ctx.meta <- old;
 	e
@@ -2056,6 +2060,7 @@ let rec create com =
 			delayed = [];
 			debug_delayed = [];
 			doinline = com.display.dms_inline && not (Common.defined com Define.NoInline);
+			retain_meta = Common.defined com Define.RetainUntypedMeta;
 			std = null_module;
 			global_using = [];
 			complete = false;

+ 70 - 0
tests/misc/neko/projects/Issue10937/Main.hx

@@ -0,0 +1,70 @@
+import sys.io.Process;
+
+using StringTools;
+
+enum abstract Arch(String) {
+	final Arm64;
+	final Arm;
+	final X86;
+	final X86_64;
+
+	public function getNdllSuffix():String {
+		return switch abstract {
+			case Arm64: "Arm64";
+			case Arm: "Arm";
+			case X86_64: "64";
+			case X86: "";
+		};
+	}
+}
+
+function getArchWindows() {
+	return switch Sys.getEnv("PROCESSOR_ARCHITECTURE") {
+		case "x86": X86;
+		case "AMD64": X86_64;
+		case "ARM64": Arm64;
+		case other: throw 'Unknown CPU architecture: $other';
+	};
+}
+
+function getArchUnix() {
+	final uname = new Process("uname", ["-m"]);
+
+	final arch = try {
+		uname.stdout.readLine();
+	} catch (e:haxe.io.Eof) {
+		"";
+	};
+
+	uname.kill();
+	uname.close();
+
+	return switch arch {
+		case "x86_64" | "amd64": X86_64;
+		case "i386" | "x86": X86;
+		case "arm64" | "aarch64": Arm64;
+		case "arm": Arm;
+		case other: throw 'Unknown CPU architecture: "$other"';
+	};
+}
+
+function getArch() {
+	return switch Sys.systemName() {
+		case "Windows":	getArchWindows();
+		default: getArchUnix();
+	};
+}
+
+function main() {
+	final arch = getArch();
+
+	final expectedNdllSubDir = Sys.systemName() + arch.getNdllSuffix() + "/";
+
+	final ndllPath = neko.vm.Loader.local().getPath()[0];
+
+	if (ndllPath.endsWith(expectedNdllSubDir)) {
+		Sys.println("Success");
+	} else {
+		Sys.println('Failure: Expected $ndllPath to end with $expectedNdllSubDir');
+	}
+}

+ 1 - 0
tests/misc/neko/projects/Issue10937/aaa-setup.hxml

@@ -0,0 +1 @@
+--cmd haxelib dev dummy_ndll dummy_ndll

+ 4 - 0
tests/misc/neko/projects/Issue10937/compile.hxml

@@ -0,0 +1,4 @@
+--main Main
+--neko bin/main.n
+-lib dummy_ndll
+--cmd neko bin/main.n

+ 1 - 0
tests/misc/neko/projects/Issue10937/compile.hxml.stdout

@@ -0,0 +1 @@
+Success

+ 0 - 0
tests/misc/neko/projects/Issue10937/dummy_ndll/ndll/.exists


+ 2 - 0
tests/misc/neko/run.hxml

@@ -0,0 +1,2 @@
+-cp ../src
+--run Main

+ 37 - 0
tests/misc/projects/Issue10961/Main.hx

@@ -0,0 +1,37 @@
+class Main {
+	static function main() {
+		final foo:Foo = {
+			a: 0,
+			b: 0,
+			c: 0,
+			a: 0,
+		}
+		final foo = {
+			a: 0,
+			b: 0,
+			c: 0,
+			a: 0,
+		}
+		final foo:CFoo = {
+			a: 0,
+			b: 0,
+			a: 0,
+		}
+	}
+}
+
+typedef Foo = {
+	a:Int,
+	b:Int,
+	c:Int,
+}
+
+typedef FooAdd = {
+	d:Int,
+}
+
+@:structInit
+class CFoo {
+	var a:Int;
+	var b:Int;
+}

+ 2 - 0
tests/misc/projects/Issue10961/compile-fail.hxml

@@ -0,0 +1,2 @@
+--main Main
+--interp

+ 3 - 0
tests/misc/projects/Issue10961/compile-fail.hxml.stderr

@@ -0,0 +1,3 @@
+Main.hx:7: characters 4-5 : Duplicate field in object declaration : a
+Main.hx:13: characters 4-5 : Duplicate field in object declaration : a
+Main.hx:18: characters 4-5 : Duplicate field in object declaration : a

+ 22 - 0
tests/optimization/src/TestJs.hx

@@ -26,6 +26,8 @@ private enum EnumFlagTest {
 
 @:analyzer(no_user_var_fusion)
 class TestJs {
+	static var notFalse = true;
+
 	//@:js('var x = 10;"" + x;var x1 = 10;"" + x1;var x2 = 10.0;"" + x2;var x3 = "10";x3;var x4 = true;"" + x4;')
 	//static function testStdString() {
 	//var x = 10;
@@ -720,6 +722,26 @@ class TestJs {
 	static function testIssue10740_forceInlineInSafeNav() {
 		inline Issue10740.inst?.f();
 	}
+
+	@:js('
+		var offset = 0;
+		do {
+			TestJs.use(offset);
+			if(offset >= 3) {
+				break;
+			}
+			offset = 3;
+		} while(TestJs.notFalse);
+	')
+	static function testDoWhile() {
+		var offset = 0;
+		do {
+			use(offset);
+			if (offset >= 3)
+				break;
+			offset = 3;
+		} while (notFalse);
+	}
 }
 
 class Issue9227 {

+ 1 - 2
tests/optimization/src/issues/Issue10765.hx

@@ -37,8 +37,7 @@ private class Complex {
 class Issue10765 {
 	@:js('
 		var buffer = new ArrayBuffer(80);
-		var this1 = new DataView(buffer,0,buffer.byteLength);
-		var array = this1;
+		var array = new DataView(buffer,0,buffer.byteLength);
 		var real = array.getFloat32(0);
 		var imag = array.getFloat32(4);
 		array.setFloat32(0,real + real);

+ 3 - 0
tests/runci/targets/Neko.hx

@@ -8,6 +8,9 @@ class Neko {
 		runCommand("haxe", ["compile-neko.hxml", "-D", "dump", "-D", "dump_ignore_var_ids"].concat(args));
 		runCommand("neko", ["bin/unit.n"]);
 
+		changeDirectory(getMiscSubDir('neko'));
+		runCommand("haxe", ["run.hxml"].concat(args));
+
 		changeDirectory(sysDir);
 		runCommand("haxe", ["compile-neko.hxml"].concat(args));
 		runSysTest("neko", ["bin/neko/sys.n"]);

+ 2 - 1
tests/unit/compile-each.hxml

@@ -9,4 +9,5 @@
 --dce full
 -lib utest
 -D analyzer-optimize
--D analyzer-user-var-fusion
+-D analyzer-user-var-fusion
+-D message-reporting=pretty

+ 24 - 0
tests/unit/src/unit/issues/Issue10735.hx

@@ -0,0 +1,24 @@
+package unit.issues;
+
+@:generic
+private abstract class A<T> {
+	var i:T;
+
+	public function new(i:T) {
+		this.i = i;
+	}
+
+	abstract function foo():T;
+}
+
+private class B extends A<Int> {
+	public function foo() {
+		return i;
+	}
+}
+
+class Issue10735 extends Test {
+	function test() {
+		eq(12, new B(12).foo());
+	}
+}

+ 35 - 0
tests/unit/src/unit/issues/Issue10776.hx

@@ -0,0 +1,35 @@
+package unit.issues;
+
+import utest.Assert;
+
+@:forward
+private abstract DialogConfig(DialogConfigData) from DialogConfigData {
+	@:from static function fromRenderResult(r:RenderResult):DialogConfig
+		return {priority: 0, ui: r};
+}
+
+private typedef DialogConfigData = {
+	final priority:Int;
+	final ui:DialogUi;
+}
+
+@:callable
+private abstract DialogUi((close:() -> Void)->RenderResult) from (close:() -> Void)->RenderResult {
+	inline function new(f)
+		this = f;
+
+	@:from static function fromRenderResult(r:RenderResult)
+		return new DialogUi(_ -> r);
+}
+
+private abstract RenderResult(String) to String from String {}
+
+class Issue10776 extends Test {
+	function test() {
+		var cfg:DialogConfig = {
+			priority: 0,
+			ui: (null : RenderResult),
+		};
+		Assert.pass();
+	}
+}

+ 19 - 0
tests/unit/src/unit/issues/Issue10867.hx

@@ -0,0 +1,19 @@
+package unit.issues;
+
+class Issue10867 extends Test {
+	function test() {
+		var r = ~/\/\*(((?!\*\/).)*)$/s;
+		var a = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
+
+		var test = "/*";
+		var res = new StringBuf();
+		for (i in 0...10) {
+			test += a;
+			res.add('iter $i: ${r.match(test)} ');
+		}
+
+		res.add("Finished");
+		eq("iter 0: true iter 1: true iter 2: true iter 3: true iter 4: true iter 5: true iter 6: true iter 7: true iter 8: true iter 9: true Finished",
+			res.toString());
+	}
+}

+ 12 - 0
tests/unit/src/unit/issues/Issue10960.hx

@@ -0,0 +1,12 @@
+package unit.issues;
+
+class Issue10960 extends Test {
+	function test() {
+		final obj:Dynamic = 0;
+		eq("", mm(obj));
+	}
+
+	static macro function mm(any:Any) {
+		return macro "";
+	}
+}

+ 50 - 0
tests/unit/src/unit/issues/Issue11040.hx

@@ -0,0 +1,50 @@
+package unit.issues;
+
+class Issue11040 extends Test {
+	function run() {
+		var tagName = "Array";
+		var text:String = "<Array<haxe.Json>>";
+		var startTag = '<$tagName';
+		var endTag = '</$tagName>';
+
+		var depth = 0;
+		var index = 0;
+		var buf = new StringBuf();
+		function append(s:String) {
+			buf.add(s);
+			buf.add("\n");
+		}
+		append("enter loop");
+		while (true) {
+			append("looping");
+			var indexStartTag = text.indexOf(startTag, index);
+			var indexEndTag = text.indexOf(endTag, index);
+			if ((indexStartTag == -1) && (indexEndTag == -1)) {
+				append(">>> should exit here >>>");
+				return buf.toString();
+			}
+			index++;
+			switch (text.charAt(index)) {
+				case " " | "/" | ">":
+				default:
+					append("default -> continue loop");
+					continue;
+			}
+			if (depth <= 0) {
+				break;
+			}
+		}
+		text = text.substr(0, index);
+		append("exit loop");
+		return buf.toString();
+	}
+
+	function test() {
+		eq("enter loop
+looping
+default -> continue loop
+looping
+>>> should exit here >>>
+", run());
+	}
+}