浏览代码

Merge branch 'development' of https://github.com/haxefoundation/haxe into development

Mark Knol 6 年之前
父节点
当前提交
5286223994

+ 1 - 1
appveyor.yml

@@ -42,7 +42,7 @@ install:
       )
     - 7z x "opam.tar.xz" -so | 7z x -aoa -si -ttar
     - '%CYG_ROOT%/bin/bash -lc "cd \"$OLDPWD\" && bash opam${ARCH}/install.sh"'
-    - '%CYG_ROOT%/bin/bash -lc "opam init mingw \"https://github.com/fdopen/opam-repository-mingw.git\" --comp 4.02.3+mingw${ARCH}c --switch 4.02.3+mingw${ARCH}c --auto-setup --yes"'
+    - '%CYG_ROOT%/bin/bash -lc "opam init mingw \"https://github.com/fdopen/opam-repository-mingw.git\" --comp 4.07.0+mingw${ARCH}c --switch 4.07.0+mingw${ARCH}c --auto-setup --yes"'
     - '%CYG_ROOT%/bin/bash -lc "opam update --yes"'
     - '%CYG_ROOT%/bin/bash -lc "opam pin add haxe \"$APPVEYOR_BUILD_FOLDER\" --no-action --yes"'
     - '%CYG_ROOT%/bin/bash -lc "opam install haxe --deps-only --yes"'

+ 26 - 6
src/codegen/codegen.ml

@@ -387,11 +387,34 @@ module Dump = struct
 			close();
 		) com.types
 
+	let dump_position com =
+		List.iter (fun mt ->
+			match mt with
+				| TClassDecl c ->
+					let buf,close = create_dumpfile_from_path com (t_path mt) in
+					Printf.bprintf buf "%s\n" (s_type_path c.cl_path);
+					let field cf =
+						Printf.bprintf buf "\t%s\n" cf.cf_name;
+						begin match cf.cf_expr with
+						| None -> ()
+						| Some e ->
+							Printf.bprintf buf "%s\n" (Texpr.dump_with_pos "\t" e);
+						end
+					in
+					Option.may field c.cl_constructor;
+					List.iter field c.cl_ordered_statics;
+					List.iter field c.cl_ordered_fields;
+					close();
+				| _ ->
+					()
+		) com.types
+
 	let dump_types com =
 		match Common.defined_value_safe com Define.Dump with
 			| "pretty" -> dump_types com (Type.s_expr_pretty false "\t" true)
 			| "legacy" -> dump_types com Type.s_expr
 			| "record" -> dump_record com
+			| "position" -> dump_position com
 			| _ -> dump_types com (Type.s_expr_ast (not (Common.defined com Define.DumpIgnoreVarIds)) "\t")
 
 	let dump_dependencies ?(target_override=None) com =
@@ -453,7 +476,7 @@ let default_cast ?(vtmp="$t") com e texpr t p =
 	mk (TBlock [var;check;vexpr]) t p
 
 module UnificationCallback = struct
-	let tf_stack = ref []
+	let tf_stack = new_rec_stack()
 
 	let check_call_params f el tl =
 		let rec loop acc el tl = match el,tl with
@@ -521,7 +544,7 @@ module UnificationCallback = struct
 					| _ -> e
 				end
 			| TReturn (Some e1) ->
-				begin match !tf_stack with
+				begin match tf_stack.rec_stack with
 					| tf :: _ -> { e with eexpr = TReturn (Some (f e1 tf.tf_type))}
 					| _ -> e
 				end
@@ -530,10 +553,7 @@ module UnificationCallback = struct
 		in
 		match e.eexpr with
 			| TFunction tf ->
-				tf_stack := tf :: !tf_stack;
-				let etf = {e with eexpr = TFunction({tf with tf_expr = run f tf.tf_expr})} in
-				tf_stack := List.tl !tf_stack;
-				etf
+				rec_stack_loop tf_stack tf (fun() -> {e with eexpr = TFunction({tf with tf_expr = run f tf.tf_expr})}) ()
 			| _ ->
 				check (Type.map_expr (run ff) e)
 end;;

+ 15 - 7
src/compiler/main.ml

@@ -406,7 +406,7 @@ let rec process_params create pl =
 			ctx.flush()
 		| arg :: l ->
 			match List.rev (ExtString.String.nsplit arg ".") with
-			| "hxml" :: _ when (match acc with "-cmd" :: _ -> false | _ -> true) ->
+			| "hxml" :: _ when (match acc with "-cmd" :: _ | "--cmd" :: _ -> false | _ -> true) ->
 				let acc, l =
 					(try
 						let parsed = parse_hxml arg in
@@ -444,13 +444,13 @@ and process_args arg_spec =
 		(List.map (fun (arg) -> (arg, dep_spec arg spec, doc)) dep)
 	) arg_spec)
 
-and usage_string arg_spec usage =
+and usage_string ?(print_cat=true) arg_spec usage =
 	let make_label = fun names hint -> Printf.sprintf "%s %s" (String.concat ", " names) hint in
 	let args = (List.filter (fun (cat, ok, dep, spec, hint, doc) -> (List.length ok) > 0) arg_spec) in
 	let cat_order = ["Target";"Compilation";"Optimization";"Debug";"Batch";"Services";"Compilation Server";"Target-specific";"Miscellaneous"] in
 	let cats = List.filter (fun x -> List.mem x (List.map (fun (cat, _, _, _, _, _) -> cat) args)) cat_order in
 	let max_length = List.fold_left max 0 (List.map String.length (List.map (fun (_, ok, _, _, hint, _) -> make_label ok hint) args)) in
-	usage ^ (String.concat "\n" (List.flatten (List.map (fun cat -> ["\n"^cat^":"] @ (List.map (fun (cat, ok, dep, spec, hint, doc) ->
+	usage ^ (String.concat "\n" (List.flatten (List.map (fun cat -> (if print_cat then ["\n"^cat^":"] else []) @ (List.map (fun (cat, ok, dep, spec, hint, doc) ->
 		let label = make_label ok hint in
 		Printf.sprintf "  %s%s  %s" label (String.make (max_length - (String.length label)) ' ') doc
 	) (List.filter (fun (cat', _, _, _, _, _) -> (if List.mem cat' cat_order then cat' else "Miscellaneous") = cat) args))) cats)))
@@ -768,14 +768,22 @@ try
 			raise (HelpMessage (usage_string all_args usage))
 		| Arg.Bad msg ->
 			let first_line = List.nth (Str.split (Str.regexp "\n") msg) 0 in
-			let new_msg = (Printf.sprintf "%s\n\n%s" first_line (usage_string all_args usage)) in
-			let r = Str.regexp "unknown option `\\([-A-Za-z]+\\)'" in
+			let new_msg = (Printf.sprintf "%s" first_line) in
+			let r = Str.regexp "unknown option [`']?\\([-A-Za-z]+\\)[`']?" in
 			try
 				ignore(Str.search_forward r msg 0);
 				let s = Str.matched_group 1 msg in
 				let sl = List.map (fun (s,_,_) -> s) all_args_spec in
-				let msg = StringError.string_error_raise s sl (Printf.sprintf "Invalid command: %s" s) in
-				raise (Arg.Bad msg)
+				let sl = StringError.get_similar s sl in
+				begin match sl with
+				| [] -> raise Not_found
+				| _ ->
+					let spec = List.filter (fun (_,sl',sl'',_,_,_) ->
+						List.exists (fun s -> List.mem s sl) (sl' @ sl'')
+					) all_args in
+					let new_msg = (Printf.sprintf "%s\nDid you mean:\n%s" first_line (usage_string ~print_cat:false spec "")) in
+					raise (Arg.Bad new_msg)
+				end;
 			with Not_found ->
 				raise (Arg.Bad new_msg));
 		arg_delays := []

+ 3 - 6
src/context/abstractCast.ml

@@ -5,7 +5,7 @@ open Type
 open Typecore
 open Error
 
-let cast_stack = ref []
+let cast_stack = new_rec_stack()
 
 let make_static_call ctx c cf a pl args t p =
 	if cf.cf_kind = Method MethMacro then begin
@@ -26,11 +26,8 @@ let make_static_call ctx c cf a pl args t p =
 
 let do_check_cast ctx tleft eright p =
 	let recurse cf f =
-		if cf == ctx.curfield || List.mem cf !cast_stack then error "Recursive implicit cast" p;
-		cast_stack := cf :: !cast_stack;
-		let r = f() in
-		cast_stack := List.tl !cast_stack;
-		r
+		if cf == ctx.curfield || rec_stack_memq cf cast_stack then error "Recursive implicit cast" p;
+		rec_stack_loop cast_stack cf f ()
 	in
 	let find a tl f =
 		let tcf,cf = f() in

+ 20 - 4
src/context/display/displayFields.ml

@@ -114,6 +114,10 @@ let collect ctx e_ast e dk with_type p =
 			(not stat || not (Meta.has Meta.Impl cf.cf_meta)) &&
 			can_access ctx c cf stat
 	in
+	let make_class_field origin cf =
+		let ct = DisplayEmitter.completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) cf.cf_type in
+		make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct)
+	in
 	let rec loop items t =
 		let is_new_item items name = not (PMap.mem name items) in
 		match follow t with
@@ -127,12 +131,25 @@ let collect ctx e_ast e dk with_type p =
 			PMap.foldi (fun k (c,cf) acc ->
 				if should_access c cf false && is_new_item acc cf.cf_name then begin
 					let origin = if c == c0 then Self(TClassDecl c) else Parent(TClassDecl c) in
-					let ct = DisplayEmitter.completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) cf.cf_type in
-				 	let item = make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct) in
+					let item = make_class_field origin cf in
 					PMap.add k item acc
 				end else
 					acc
 			) fields items
+		| TEnum _ ->
+			let t = ctx.g.do_load_type_def ctx p {tpackage=[];tname="EnumValue";tsub=None;tparams=[]} in
+			begin match t with
+			| TAbstractDecl ({a_impl = Some c} as a) ->
+				begin try
+					let cf = PMap.find "match" c.cl_statics in
+					let item = make_class_field (Self(TAbstractDecl a)) cf in
+					PMap.add "match" item items
+				with Not_found ->
+					items
+				end
+			| _ ->
+				items
+			end;
 		| TAbstract({a_impl = Some c} as a,tl) ->
 			merge_core_doc ctx (TAbstractDecl a);
 			(* Abstracts should show all their @:impl fields minus the constructor. *)
@@ -141,8 +158,7 @@ let collect ctx e_ast e dk with_type p =
 					let origin = Self(TAbstractDecl a) in
 					let cf = prepare_using_field cf in
 					let cf = if tl = [] then cf else {cf with cf_type = apply_params a.a_params tl cf.cf_type} in
-					let ct = DisplayEmitter.completion_type_of_type ctx ~values:(get_value_meta cf.cf_meta) cf.cf_type in
-					let item = make_ci_class_field (CompletionClassField.make cf CFSMember origin true) (cf.cf_type,ct) in
+					let item = make_class_field origin cf in
 					PMap.add cf.cf_name item acc
 				end else
 					acc

+ 4 - 8
src/core/abstract.ml

@@ -47,11 +47,10 @@ let find_from ab pl a b =
 	else
 		find_field_from ab pl a b
 
-let underlying_type_stack = ref []
+let underlying_type_stack = new_rec_stack()
 
 let rec get_underlying_type a pl =
 	let maybe_recurse t =
-		underlying_type_stack := (TAbstract(a,pl)) :: !underlying_type_stack;
 		let rec loop t = match t with
 			| TMono r ->
 				(match !r with
@@ -64,19 +63,16 @@ let rec get_underlying_type a pl =
 			| TType (t,tl) ->
 				loop (apply_params t.t_params tl t.t_type)
 			| TAbstract(a,tl) when not (Meta.has Meta.CoreType a.a_meta) ->
-				if List.exists (fast_eq t) !underlying_type_stack then begin
+				if rec_stack_exists (fast_eq t) underlying_type_stack then begin
 					let pctx = print_context() in
-					let s = String.concat " -> " (List.map (fun t -> s_type pctx t) (List.rev (t :: !underlying_type_stack))) in
-					underlying_type_stack := [];
+					let s = String.concat " -> " (List.map (fun t -> s_type pctx t) (List.rev (t :: underlying_type_stack.rec_stack))) in
 					error ("Abstract chain detected: " ^ s) a.a_pos
 				end;
 				get_underlying_type a tl
 			| _ ->
 				t
 		in
-		let t = loop t in
-		underlying_type_stack := List.tl !underlying_type_stack;
-		t
+		rec_stack_loop underlying_type_stack (TAbstract(a,pl)) loop t
 	in
 	try
 		if not (Meta.has Meta.MultiType a.a_meta) then raise Not_found;

+ 112 - 1
src/core/texpr.ml

@@ -388,4 +388,115 @@ let build_metadata api t =
 		let meta_obj = (if fields = [] then meta_obj else (("fields",null_pos,NoQuotes),make_meta fields) :: meta_obj) in
 		let meta_obj = (if statics = [] then meta_obj else (("statics",null_pos,NoQuotes),make_meta statics) :: meta_obj) in
 		let meta_obj = (try (("obj",null_pos,NoQuotes), make_meta_field (List.assoc "" meta)) :: meta_obj with Not_found -> meta_obj) in
-		Some (mk (TObjectDecl meta_obj) t_dynamic p)
+		Some (mk (TObjectDecl meta_obj) t_dynamic p)
+
+let dump_with_pos tabs e =
+	let buf = Buffer.create 0 in
+	let add = Buffer.add_string buf in
+	let rec loop' tabs e =
+		let p = e.epos in
+		let add s = add (Printf.sprintf "%4i-%4i %s%s\n" p.pmin p.pmax tabs s) in
+		let loop e = loop' (tabs ^ "  ") e in
+		match e.eexpr with
+		| TConst ct -> add (s_const ct)
+		| TLocal v -> add ("TLocal " ^ v.v_name)
+		| TTypeExpr mt -> add ("TTypeExpr " ^ (s_type_path (t_infos mt).mt_path))
+		| TIdent s -> add ("TIdent " ^ s)
+		| TEnumParameter(e1,ef,_) ->
+			add ("TEnumParameter " ^ ef.ef_name);
+			loop e1
+		| TEnumIndex e1 ->
+			add "TEnumIndex";
+			loop e1
+		| TArray(e1,e2) ->
+			add "TArray";
+			loop e1;
+			loop e2;
+		| TBinop(op,e1,e2) ->
+			add ("TBinop " ^ (s_binop op));
+			loop e1;
+			loop e2;
+		| TField(e1,s) ->
+			add ("TField " ^ (field_name s));
+			loop e1
+		| TParenthesis e1 ->
+			add "TParenthesis";
+			loop e1
+		| TObjectDecl fl ->
+			add "TObjectDecl";
+			List.iter (fun ((n,p,_),e1) ->
+				Buffer.add_string buf (Printf.sprintf "%4i-%4i %s%s\n" p.pmin p.pmax tabs n);
+				loop e1
+			) fl;
+		| TArrayDecl el ->
+			add "TArrayDecl";
+			List.iter loop el
+		| TCall(e1,el) ->
+			add "TCall";
+			loop e1;
+			List.iter loop el
+		| TNew(c,_,el) ->
+			add ("TNew " ^ s_type_path c.cl_path);
+			List.iter loop el
+		| TUnop(op,_,e1) ->
+			add ("TUnop " ^ (s_unop op));
+			loop e1
+		| TVar(v,eo) ->
+			add ("TVar " ^ v.v_name);
+			begin match eo with
+				| None -> ()
+				| Some e ->
+					loop' (Printf.sprintf "%s  " tabs) e
+			end
+		| TFunction tf ->
+			add "TFunction";
+			loop tf.tf_expr;
+		| TBlock el ->
+			add "TBlock";
+			List.iter loop el
+		| TFor(v,e1,e2) ->
+			add ("TFor " ^ v.v_name);
+			loop e1;
+			loop e2;
+		| TIf(e1,e2,eo) ->
+			add "TIf";
+			loop e1;
+			loop e2;
+			Option.may loop eo;
+		| TWhile(e1,e2,_) ->
+			add "TWhile";
+			loop e1;
+			loop e2;
+		| TSwitch(e1,cases,def) ->
+			add "TSwitch";
+			loop e1;
+			List.iter (fun (el,e) ->
+				List.iter (loop' (tabs ^ "    ")) el;
+				loop' (tabs ^ "      ") e;
+			) cases;
+			Option.may (loop' (tabs ^ "      ")) def
+		| TTry(e1,catches) ->
+			add "TTry";
+			loop e1;
+			List.iter (fun (v,e) ->
+				loop' (tabs ^ "    ") e
+			) catches
+		| TReturn eo ->
+			add "TReturn";
+			Option.may loop eo;
+		| TBreak ->
+			add "TBreak";
+		| TContinue ->
+			add "TContinue"
+		| TThrow e1 ->
+			add "EThrow";
+			loop e1
+		| TCast(e1,_) ->
+			add "TCast";
+			loop e1;
+		| TMeta((m,_,_),e1) ->
+			add ("TMeta " ^ fst (Meta.get_info m));
+			loop e1
+	in
+	loop' tabs e;
+	Buffer.contents buf

+ 45 - 38
src/core/type.ml

@@ -1750,50 +1750,57 @@ let unify_kind k1 k2 =
 			| MethDynamic, MethNormal -> true
 			| _ -> false
 
-let eq_stack = ref []
+type 'a rec_stack = {
+	mutable rec_stack : 'a list;
+}
+
+let new_rec_stack() = { rec_stack = [] }
+let rec_stack_exists f s = List.exists f s.rec_stack
+let rec_stack_memq v s = List.memq v s.rec_stack
+let rec_stack_loop stack value f arg =
+	stack.rec_stack <- value :: stack.rec_stack;
+	try
+		let r = f arg in
+		stack.rec_stack <- List.tl stack.rec_stack;
+		r
+	with e ->
+		stack.rec_stack <- List.tl stack.rec_stack;
+		raise e
+
+let eq_stack = new_rec_stack()
 
 let rec_stack stack value fcheck frun ferror =
-	if not (List.exists fcheck !stack) then begin
+	if not (rec_stack_exists fcheck stack) then begin
 		try
-			stack := value :: !stack;
+			stack.rec_stack <- value :: stack.rec_stack;
 			let v = frun() in
-			stack := List.tl !stack;
+			stack.rec_stack <- List.tl stack.rec_stack;
 			v
 		with
 			Unify_error l ->
-				stack := List.tl !stack;
+				stack.rec_stack <- List.tl stack.rec_stack;
 				ferror l
 			| e ->
-				stack := List.tl !stack;
+				stack.rec_stack <- List.tl stack.rec_stack;
 				raise e
 	end
 
 let rec_stack_default stack value fcheck frun def =
-	if not (List.exists fcheck !stack) then begin
-		try
-			stack := value :: !stack;
-			let v = frun() in
-			stack := List.tl !stack;
-			v
-		with
-			| e ->
-				stack := List.tl !stack;
-				raise e
-	end	else def
+	if not (rec_stack_exists fcheck stack) then rec_stack_loop stack value frun () else def
 
 let rec_stack_bool stack value fcheck frun =
-	if (List.exists fcheck !stack) then false else begin
+	if (rec_stack_exists fcheck stack) then false else begin
 		try
-			stack := value :: !stack;
+			stack.rec_stack <- value :: stack.rec_stack;
 			frun();
-			stack := List.tl !stack;
+			stack.rec_stack <- List.tl stack.rec_stack;
 			true
 		with
 			Unify_error l ->
-				stack := List.tl !stack;
+				stack.rec_stack <- List.tl stack.rec_stack;
 				false
 			| e ->
-				stack := List.tl !stack;
+				stack.rec_stack <- List.tl stack.rec_stack;
 				raise e
 	end
 
@@ -1926,19 +1933,19 @@ let type_iseq_strict a b =
 	with Unify_error _ ->
 		false
 
-let unify_stack = ref []
-let abstract_cast_stack = ref []
-let unify_new_monos = ref []
+let unify_stack = new_rec_stack()
+let abstract_cast_stack = new_rec_stack()
+let unify_new_monos = new_rec_stack()
 
 let print_stacks() =
 	let ctx = print_context() in
 	let st = s_type ctx in
 	print_endline "unify_stack";
-	List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) !unify_stack;
+	List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) unify_stack.rec_stack;
 	print_endline "monos";
-	List.iter (fun m -> print_endline ("\t" ^ st m)) !unify_new_monos;
+	List.iter (fun m -> print_endline ("\t" ^ st m)) unify_new_monos.rec_stack;
 	print_endline "abstract_cast_stack";
-	List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) !abstract_cast_stack
+	List.iter (fun (a,b) -> Printf.printf "\t%s , %s\n" (st a) (st b)) abstract_cast_stack.rec_stack
 
 let rec unify a b =
 	if a == b then
@@ -2055,22 +2062,22 @@ let rec unify a b =
 				(match f2.cf_kind with
 				| Var { v_read = AccNo } | Var { v_read = AccNever } ->
 					(* we will do a recursive unification, so let's check for possible recursion *)
-					let old_monos = !unify_new_monos in
-					unify_new_monos := !monos @ !unify_new_monos;
+					let old_monos = unify_new_monos.rec_stack in
+					unify_new_monos.rec_stack <- !monos @ unify_new_monos.rec_stack;
 					rec_stack unify_stack (ft,f2.cf_type)
-						(fun (a2,b2) -> fast_eq b2 f2.cf_type && fast_eq_mono !unify_new_monos ft a2)
-						(fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos := old_monos; raise e)
+						(fun (a2,b2) -> fast_eq b2 f2.cf_type && fast_eq_mono unify_new_monos.rec_stack ft a2)
+						(fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e)
 						(fun l -> error (invalid_field n :: l));
-					unify_new_monos := old_monos;
+					unify_new_monos.rec_stack <- old_monos;
 				| Method MethNormal | Method MethInline | Var { v_write = AccNo } | Var { v_write = AccNever } ->
 					(* same as before, but unification is reversed (read-only var) *)
-					let old_monos = !unify_new_monos in
-					unify_new_monos := !monos @ !unify_new_monos;
+					let old_monos = unify_new_monos.rec_stack in
+					unify_new_monos.rec_stack <- !monos @ unify_new_monos.rec_stack;
 					rec_stack unify_stack (f2.cf_type,ft)
-						(fun(a2,b2) -> fast_eq_mono !unify_new_monos b2 ft && fast_eq f2.cf_type a2)
-						(fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos := old_monos; raise e)
+						(fun(a2,b2) -> fast_eq_mono unify_new_monos.rec_stack b2 ft && fast_eq f2.cf_type a2)
+						(fun() -> try unify_with_access f1 ft f2 with e -> unify_new_monos.rec_stack <- old_monos; raise e)
 						(fun l -> error (invalid_field n :: l));
-					unify_new_monos := old_monos;
+					unify_new_monos.rec_stack <- old_monos;
 				| _ ->
 					(* will use fast_eq, which have its own stack *)
 					try

+ 1 - 3
src/filters/filtersCommon.ml

@@ -50,9 +50,7 @@ let run_expression_filters ctx filters t =
 			ctx.curfield <- f;
 			(match f.cf_expr with
 			| Some e when not (is_removable_field ctx f) ->
-				AbstractCast.cast_stack := f :: !AbstractCast.cast_stack;
-				f.cf_expr <- Some (run e);
-				AbstractCast.cast_stack := List.tl !AbstractCast.cast_stack;
+				f.cf_expr <- Some (rec_stack_loop AbstractCast.cast_stack f run e);
 			| _ -> ());
 			List.iter process_field f.cf_overloads
 		in

+ 1 - 1
src/generators/gencpp.ml

@@ -4393,7 +4393,7 @@ let gen_field ctx class_def class_name ptr_name dot_name is_static is_interface
                        | TCppStar (t,const) ->
                           output ("(cpp::" ^ (if const then "Const" else "") ^"Pointer<" ^ (tcpp_to_string t)^" >) ")
                        | TCppInst(t) when has_meta_key t.cl_meta Meta.StructAccess ->
-                          output ("(cpp::Struct< " ^ (tcpp_to_string return_type) ^ " >) ");
+                          output ("(cpp::Struct< " ^ (tcpp_to_string arg) ^ " >) ");
                        | _ -> () );
                      output ("a" ^ (string_of_int i));
                   )  tcpp_args;

+ 20 - 5
src/generators/genhl.ml

@@ -2850,12 +2850,27 @@ and eval_expr ctx e =
 	| TCast (ev,Some _) ->
 		let t = to_type ctx e.etype in
 		let re = eval_expr ctx ev in
-		let r = alloc_tmp ctx t in
+		let rt = alloc_tmp ctx t in
 		if safe_cast (rtype ctx re) t then
-			op ctx (OMov (r,re))
-		else
-			op ctx (OSafeCast (r,re));
-		r
+			op ctx (OMov (rt,re))
+		else (match Abstract.follow_with_abstracts e.etype with
+		| TInst({ cl_interface = true } as c,_) ->
+			hold ctx re;
+			let c = eval_to ctx { eexpr = TTypeExpr(TClassDecl c); epos = e.epos; etype = t_dynamic } (class_type ctx ctx.base_type [] false) in
+			hold ctx c;
+			let rb = alloc_tmp ctx HBool in
+			op ctx (OCall2 (rb, alloc_fun_path ctx (["hl"],"BaseType") "check",c,re));
+			let jnext = jump ctx (fun n -> OJTrue (rb,n)) in
+			let jnext2 = jump ctx (fun n -> OJNull (re,n)) in
+			op ctx (OThrow (make_string ctx "Cast error" e.epos));
+			jnext();
+			jnext2();
+			op ctx (OMov (rt, unsafe_cast_to ~debugchk:false ctx re (to_type ctx e.etype) e.epos));
+			free ctx c;
+			free ctx re;
+		| _ ->
+			op ctx (OSafeCast (rt,re)));
+		rt
 	| TIdent s ->
 		abort ("Unbound identifier " ^ s) e.epos
 

+ 2 - 0
src/generators/genjs.ml

@@ -1526,6 +1526,8 @@ let generate com =
 		match e.eexpr with
 		| TField (_,FClosure _) ->
 			add_feature ctx "use.$bind"
+		| TCall ({ eexpr = TField (_,f) } as ef, []) when field_name f = "iterator" && is_dynamic_iterator ctx ef ->
+			add_feature ctx "use.$getIterator";
 		| _ ->
 			Type.iter chk_features e
 	in

+ 14 - 7
src/generators/genphp7.ml

@@ -544,20 +544,27 @@ let create_dir_recursive (path:string list) =
 (**
 	@return String representation of specified type path. E.g. returns "\example\Test" for (["example"], "Test")
 *)
-let get_full_type_name ?escape ?omit_first_slash (type_path:path) =
+let get_full_type_name ?(escape=false) ?(omit_first_slash=false) (type_path:path) =
 	let name =
 		match type_path with
+			| ([], type_name) ->
+				if omit_first_slash then
+					type_name
+				else
+					"\\" ^ type_name
 			| (module_path, type_name) ->
 				let parts =
-					match omit_first_slash with
-						| Some true -> get_real_path module_path
-						| _ -> "" :: get_real_path module_path
+					if omit_first_slash then
+						get_real_path module_path
+					else
+						"" :: get_real_path module_path
 				in
 				(String.concat "\\" parts) ^ "\\" ^ type_name
 	in
-	match escape with
-		| Some true -> String.escaped name
-		| _ -> name
+	if escape then
+		String.escaped name
+	else
+		name
 
 (**
 	Check if `target` is or implements native PHP `Throwable` interface

+ 2 - 4
src/generators/genpy.ml

@@ -2463,13 +2463,11 @@ module Generator = struct
 			| Some e ->
 				newline ctx;
 				newline ctx;
-				spr ctx "if __name__ == '__main__':";
-				newline ctx;
 				match e.eexpr with
 				| TBlock el ->
-					List.iter (fun e -> gen_expr ctx e "" "    "; newline ctx) el;
+					List.iter (fun e -> gen_expr ctx e "" ""; newline ctx) el
 				| _ ->
-					gen_expr ctx e "" "    "; newline ctx
+					gen_expr ctx e "" ""; newline ctx
 
 	(* Entry point *)
 

+ 3 - 2
src/optimization/inline.ml

@@ -394,7 +394,8 @@ class inline_state ctx ethis params cf f p = object(self)
 					_had_side_effect <- true;
 					l.i_force_temp <- true;
 				end;
-				if l.i_abstract_this then l.i_subst.v_extra <- Some ([],Some e);
+				(* We use a null expression because we only care about the type (for abstract casts). *)
+				if l.i_abstract_this then l.i_subst.v_extra <- Some ([],Some {e with eexpr = TConst TNull});
 				loop ((l,e) :: acc) pl al false
 			| [], (v,opt) :: al ->
 				let l = self#declare v in
@@ -510,7 +511,7 @@ class inline_state ctx ethis params cf f p = object(self)
 				if not (self#read v).i_outside then begin
 					v.v_type <- map_type v.v_type;
 					match v.v_extra with
-					| Some(tl,Some e) when ctx.com.platform <> Cs ->
+					| Some(tl,Some e) ->
 						v.v_extra <- Some(tl,Some (map_expr_type e));
 					| _ ->
 						()

+ 2 - 2
src/optimization/optimizer.ml

@@ -255,7 +255,7 @@ let reduce_control_flow ctx e = match e.eexpr with
 	| _ ->
 		e
 
-let inline_stack = ref []
+let inline_stack = new_rec_stack()
 
 let rec reduce_loop ctx e =
 	let e = Type.map_expr (reduce_loop ctx) e in
@@ -270,7 +270,7 @@ let rec reduce_loop ctx e =
 				(match inl with
 				| None -> reduce_expr ctx e
 				| Some e -> reduce_loop ctx e)
-			| {eexpr = TField(ef,(FStatic(_,cf) | FInstance(_,_,cf)))} when cf.cf_kind = Method MethInline && not (List.memq cf !inline_stack) ->
+			| {eexpr = TField(ef,(FStatic(_,cf) | FInstance(_,_,cf)))} when cf.cf_kind = Method MethInline && not (rec_stack_memq cf inline_stack) ->
 				begin match cf.cf_expr with
 				| Some {eexpr = TFunction tf} ->
 					let rt = (match follow e1.etype with TFun (_,rt) -> rt | _ -> assert false) in

+ 1 - 1
src/typing/forLoop.ml

@@ -195,7 +195,7 @@ module IterationKind = struct
 			let el = ExtList.List.init length (fun i ->
 				let ei = make_int ctx.t (if ascending then i + offset else offset - i) p in
 				let rec loop e = match e.eexpr with
-					| TLocal v' when v == v' -> ei
+					| TLocal v' when v == v' -> {ei with epos = e.epos}
 					| _ -> map_expr loop e
 				in
 				let e2 = loop e2 in

+ 5 - 2
src/typing/typeloadFunction.ml

@@ -111,9 +111,11 @@ let type_function ctx args ret fmode f do_display p =
 				error "Function body required" p
 		| Some e -> e
 	in
-	let e = if not do_display then
+	let is_position_debug = Meta.has (Meta.Custom ":debug.position") ctx.curfield.cf_meta in
+	let e = if not do_display then begin
+		if is_position_debug then print_endline ("syntax:\n" ^ (Expr.dump_with_pos e));
 		type_expr ctx e NoValue
-	else begin
+	end else begin
 		let is_display_debug = Meta.has (Meta.Custom ":debug.display") ctx.curfield.cf_meta in
 		if is_display_debug then print_endline ("before processing:\n" ^ (Expr.dump_with_pos e));
 		let e = if !Parser.had_resume then e else Display.ExprPreprocessing.process_expr ctx.com e in
@@ -198,6 +200,7 @@ let type_function ctx args ret fmode f do_display p =
 		| _ -> e
 	in
 	List.iter (fun r -> r := Closed) ctx.opened;
+	if is_position_debug then print_endline ("typing:\n" ^ (Texpr.dump_with_pos "" e));
 	e , fargs
 
 let type_function ctx args ret fmode f do_display p =

+ 10 - 1
std/cpp/StdString.hx

@@ -6,7 +6,8 @@ using cpp.NativeString;
 @:include("hx/StdString.h")
 @:stackOnly
 @:structAccess
-extern class StdString extends StdStringRef
+@:unrelfective
+extern class StdString
 {
    @:native("std::string::npos")
    public static var npos(default,null):Int;
@@ -18,5 +19,13 @@ extern class StdString extends StdStringRef
    //public function toString():String;
    //public function find(s:String):Int;
    //public function substr(pos:Int, len:Int):StdString;
+
+   public function c_str() : ConstPointer<Char>;
+   public function size() : Int;
+   public function find(s:String):Int;
+   public function substr(pos:Int, len:Int):StdString;
+   public function toString():String;
+   public function toStdString():StdString;
+
 }
 

+ 1 - 1
std/cpp/vm/Thread.hx

@@ -62,7 +62,7 @@ class Thread {
 		return untyped __global__.__hxcpp_thread_read_message(block);
 	}
 
-	@:keep function __compare(t) : Int {
+	@:keep function __compare(t:Thread) : Int {
 		return handle == t.handle ? 0 : 1;
 	}
 

+ 3 - 3
std/hl/Profile.hx

@@ -78,9 +78,9 @@ class Profile {
 	}
 
 	/**
-		Start tracking. Enabled by default.
+		Init tracking. Already set by default.
 	**/
-	@:hlNative("std","track_init") public static function start() {
+	@:hlNative("std","track_init") public static function init() {
 	}
 
 	/**
@@ -111,6 +111,6 @@ class Profile {
 	static function track_enable(b:Bool) : Void {}
 	static function track_lock(b:Bool) : Void {}
 	static function track_enabled() : Bool { return false; }
-	static function __init__() { start(); track_enable(true); }
+	static function __init__() { init(); if( Sys.getEnv("HL_TRACK_ENABLE") == "1" ) track_enable(true); }
 
 }

+ 3 - 2
std/hl/_std/sys/db/Mysql.hx

@@ -180,7 +180,7 @@ private class MysqlConnection implements Connection {
 	static function request_wrap( h :  ConnectionHandler, rq : hl.Bytes, rqLen : Int ) : ResultHandler { return null; }
 	@:hlNative("mysql","escape")
 	static function escape_wrap( h : ConnectionHandler, str : hl.Bytes, len : Int ) : hl.Bytes { return null; }
-	static function setConvFuns( fstring : Dynamic, fbytes : Dynamic, fdate : Dynamic ) { };
+	static function setConvFuns( fstring : Dynamic, fbytes : Dynamic, fdate : Dynamic, fjson : Dynamic ) { };
 
 }
 
@@ -201,7 +201,8 @@ class Mysql {
 			MysqlConnection.setConvFuns(
 				function(v:hl.Bytes) return @:privateAccess String.fromUTF8(v),
 				function(v:hl.Bytes,len:Int) return new haxe.io.Bytes(v,len),
-				function(t) return Date.fromTime(t)
+				function(t) return Date.fromTime(t),
+				function(v:hl.Bytes) return haxe.Json.parse(@:privateAccess String.fromUTF8(v))
 			);
 		}
 		var p = new MysqlParams();

+ 2 - 1
std/lua/_std/Reflect.hx

@@ -22,6 +22,7 @@
 import lua.Lua;
 import lua.TableTools;
 import lua.Boot;
+
 @:coreApi class Reflect {
 
 	public inline static function hasField( o : Dynamic, field : String ) : Bool {
@@ -33,7 +34,7 @@ import lua.Boot;
 	public static function field( o : Dynamic, field : String ) : Dynamic untyped {
 		if (Lua.type(o) == "string"){
 			if (field == "length"){
-				return lua.lib.luautf8.Utf8.len(o);
+				return cast (o : String).length;
 			} else return untyped String.prototype[field];
 		} else {
 		   	return try o[field] catch( e : Dynamic ) null;

+ 4 - 0
std/python/Lib.hx

@@ -33,6 +33,10 @@ typedef PySys = python.lib.Sys;
 	and vice-versa.
 **/
 class Lib {
+
+	static public var __name__(get, never):String;
+	static inline function get___name__():String return python.Syntax.code('__name__');
+
 	/**
 		Print the specified value on the default output.
 	**/

+ 19 - 0
tests/display/src/cases/Issue7627.hx

@@ -0,0 +1,19 @@
+package cases;
+
+class Issue7627 extends DisplayTestCase {
+	/**
+
+	import haxe.ds.Option;
+
+	class Main {
+		public static function main() {
+			var option = Some(1);
+			option.match(None);
+			option.{-1-}
+		}
+	}
+	**/
+	function test() {
+		eq(true, hasField(fields(pos(1)), "match", "(this : EnumValue, pattern : Dynamic) -> Bool"));
+	}
+}

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

@@ -61,9 +61,6 @@ class Cpp {
 					runCommand("haxe", ["compile-cppia.hxml"]);
 					runCpp("bin/cppia/Host-debug", ["bin/unit.cppia"]);
 					runCpp("bin/cppia/Host-debug", ["bin/unit.cppia", "-jit"]);
-					runCommand("haxe", ["compile-cppia.hxml", "-D", "nocppiaast"]);
-					runCpp("bin/cppia/Host-debug", ["bin/unit.cppia"]);
-					runCpp("bin/cppia/Host-debug", ["bin/unit.cppia", "-jit"]);
 				}
 		}
 

+ 10 - 6
tests/sys/src/TestCommandBase.hx

@@ -80,14 +80,18 @@ class TestCommandBase extends utest.Test {
 				if (exitCode != random)
 					trace(name);
 				Assert.equals(random, exitCode);
-
-				// Try to avoid unlink(): Resource temporarily unavailable error
-				#if php
-				php.Global.gc_collect_cycles();
-				#end
-				FileSystem.deleteFile(path);
 			}
 		}
+
+		// Try to avoid unlink(): Resource temporarily unavailable error
+		Sys.sleep(0.1);
+		#if php
+		php.Global.gc_collect_cycles();
+		#end
+		for (file in FileSystem.readDirectory("temp")) {
+			if (file == ".gitignore") continue;
+			FileSystem.deleteFile(Path.join(["temp", file]));
+		}
 	}
 
 	function testExitCode() {

+ 2 - 2
tests/sys/src/TestSys.hx

@@ -6,13 +6,13 @@ class TestSys extends TestCommandBase {
 	}
 
 	function testEnv() {
-		#if !(java || lua)
+		#if !(java)
 		Sys.putEnv("foo", "value");
 		Assert.equals("value", Sys.getEnv("foo"));
 		#end
 		Assert.equals(null, Sys.getEnv("doesn't exist"));
 
-		#if !(java || lua)
+		#if !(java)
 		var env = Sys.environment();
 		Assert.equals("value", env.get("foo"));
 		#end

+ 36 - 0
tests/unit/src/unit/issues/Issue6833.hx

@@ -0,0 +1,36 @@
+package unit.issues;
+
+class Issue6833 extends unit.Test {
+	function test() {
+		for(p in new KeyValueIterator([1 => 'hello'])) {}
+	}
+}
+
+private class KeyValueIterator<K,V> {
+	var map:Map<K,V>;
+	var keys:Iterator<K>;
+
+	public inline function new(map:Map<K,V>) {
+		this.map = map;
+		this.keys = map.keys();
+	}
+
+	public inline function hasNext():Bool {
+		return keys.hasNext();
+	}
+
+	public inline function next():KeyValuePair<K,V> {
+		var key = keys.next();
+		return new KeyValuePair<K,V>(key, map.get(key));
+	}
+}
+
+private class KeyValuePair<K,V> {
+	public var key (default,null):K;
+	public var value (default,null):Null<V>;
+
+	public inline function new(key:K, value:Null<V>) {
+		this.key = key;
+		this.value = value;
+	}
+}