2
0
Эх сурвалжийг харах

Merge branch 'development' into out_of_curiosity_(don't_freak_out)

Simon Krajewski 1 жил өмнө
parent
commit
a176c668c7
44 өөрчлөгдсөн 463 нэмэгдсэн , 132 устгасан
  1. 17 13
      src/compiler/compiler.ml
  2. 1 1
      src/compiler/messageReporting.ml
  3. 6 3
      src/context/resolution.ml
  4. 3 3
      src/core/ast.ml
  5. 49 16
      src/generators/jvm/jvmFunctions.ml
  6. 2 2
      src/optimization/analyzerTexprTransformer.ml
  7. 50 23
      src/optimization/inlineConstructors.ml
  8. 1 1
      src/syntax/grammar.mly
  9. 14 2
      src/syntax/parser.ml
  10. 45 45
      src/syntax/parserEntry.ml
  11. 1 1
      src/typing/matcher/texprConverter.ml
  12. 3 5
      src/typing/operators.ml
  13. 21 8
      src/typing/typeloadFields.ml
  14. 3 1
      std/haxe/macro/Context.hx
  15. 1 1
      std/neko/Boot.hx
  16. 2 0
      tests/misc/projects/Issue10287/Main.hx
  17. 1 0
      tests/misc/projects/Issue10287/compile-fail.hxml
  18. 2 0
      tests/misc/projects/Issue10287/compile-fail.hxml.stderr
  19. 9 0
      tests/misc/projects/Issue11208/Main.hx
  20. 1 0
      tests/misc/projects/Issue11208/compile-fail.hxml
  21. 1 0
      tests/misc/projects/Issue11208/compile-fail.hxml.stderr
  22. 15 0
      tests/misc/projects/Issue11354/compile.hxml
  23. 3 0
      tests/misc/projects/Issue11354/compile.hxml.stdout
  24. 3 0
      tests/misc/projects/Issue11354/proj/Main.hx
  25. 3 0
      tests/misc/projects/Issue11354/proj/a/Main.hx
  26. 3 0
      tests/misc/projects/Issue11354/proj/b/Main.hx
  27. 14 0
      tests/misc/projects/Issue11354/proj/compile.hxml
  28. 3 0
      tests/misc/projects/Issue11354/proj/compile.hxml.stdout
  29. 6 0
      tests/misc/projects/Issue11366/Main.hx
  30. 1 0
      tests/misc/projects/Issue11366/compile-fail.hxml
  31. 1 0
      tests/misc/projects/Issue11366/compile-fail.hxml.stderr
  32. 8 0
      tests/misc/projects/Issue11368/Main.hx
  33. 1 0
      tests/misc/projects/Issue11368/compile-fail.hxml
  34. 1 0
      tests/misc/projects/Issue11368/compile-fail.hxml.stderr
  35. 18 0
      tests/misc/projects/Issue11373/Main.hx
  36. 2 0
      tests/misc/projects/Issue11373/compile.hxml
  37. 1 0
      tests/misc/projects/Issue11373/compile.hxml.stdout
  38. 21 0
      tests/misc/projects/Issue11373/pack/BuildMacro.hx
  39. 1 1
      tests/misc/projects/Issue2538/compile-fail.hxml.stderr
  40. 2 1
      tests/misc/projects/Issue8634/compile-fail.hxml.stderr
  41. 15 0
      tests/optimization/src/TestInlineConstructors.hx
  42. 11 5
      tests/server/src/TestCase.hx
  43. 64 0
      tests/unit/src/unit/issues/Issue11054.hx
  44. 33 0
      tests/unit/src/unit/issues/Issue11274.hx

+ 17 - 13
src/compiler/compiler.ml

@@ -534,14 +534,13 @@ module HighLevel = struct
 			lines
 
 	(* Returns a list of contexts, but doesn't do anything yet *)
-	let process_params server_api create each_params has_display is_server pl =
-		let curdir = Unix.getcwd () in
+	let process_params server_api create each_args has_display is_server args =
+		(* We want the loop below to actually see all the --each params, so let's prepend them *)
+		let args = !each_args @ args in
 		let added_libs = Hashtbl.create 0 in
 		let server_mode = ref SMNone in
 		let create_context args =
 			let ctx = create (server_api.on_context_create()) args in
-			(* --cwd triggers immediately, so let's reset *)
-			Unix.chdir curdir;
 			ctx
 		in
 		let rec find_subsequent_libs acc args = match args with
@@ -552,16 +551,16 @@ module HighLevel = struct
 		in
 		let rec loop acc = function
 			| [] ->
-				[],Some (create_context (!each_params @ (List.rev acc)))
+				[],Some (create_context (List.rev acc))
 			| "--next" :: l when acc = [] -> (* skip empty --next *)
 				loop [] l
 			| "--next" :: l ->
-				let ctx = create_context (!each_params @ (List.rev acc)) in
+				let ctx = create_context (List.rev acc) in
 				ctx.has_next <- true;
 				l,Some ctx
 			| "--each" :: l ->
-				each_params := List.rev acc;
-				loop [] l
+				each_args := List.rev acc;
+				loop acc l
 			| "--cwd" :: dir :: l | "-C" :: dir :: l ->
 				(* we need to change it immediately since it will affect hxml loading *)
 				(try Unix.chdir dir with _ -> raise (Arg.Bad ("Invalid directory: " ^ dir)));
@@ -584,14 +583,14 @@ module HighLevel = struct
 				loop acc l
 			| "--run" :: cl :: args ->
 				let acc = cl :: "-x" :: acc in
-				let ctx = create_context (!each_params @ (List.rev acc)) in
+				let ctx = create_context (List.rev acc) in
 				ctx.com.sys_args <- args;
 				[],Some ctx
 			| ("-L" | "--library" | "-lib") :: name :: args ->
 				let libs,args = find_subsequent_libs [name] args in
 				let libs = List.filter (fun l -> not (Hashtbl.mem added_libs l)) libs in
 				List.iter (fun l -> Hashtbl.add added_libs l ()) libs;
-				let lines = add_libs libs pl server_api.cache has_display in
+				let lines = add_libs libs args server_api.cache has_display in
 				loop acc (lines @ args)
 			| ("--jvm" | "--java" | "-java" as arg) :: dir :: args ->
 				loop_lib arg dir "hxjava" acc args
@@ -607,7 +606,7 @@ module HighLevel = struct
 		and loop_lib arg dir lib acc args =
 			loop (dir :: arg :: acc) ("-lib" :: lib :: args)
 		in
-		let args,ctx = loop [] pl in
+		let args,ctx = loop [] args in
 		args,!server_mode,ctx
 
 	let execute_ctx server_api ctx server_mode =
@@ -635,6 +634,7 @@ module HighLevel = struct
 	let entry server_api comm args =
 		let create = create_context comm server_api.cache in
 		let each_args = ref [] in
+		let curdir = Unix.getcwd () in
 		let has_display = ref false in
 		(* put --display in front if it was last parameter *)
 		let args = match List.rev args with
@@ -654,14 +654,18 @@ module HighLevel = struct
 			in
 			let code = match ctx with
 				| Some ctx ->
+					(* Need chdir here because --cwd is eagerly applied in process_params *)
+					Unix.chdir curdir;
 					execute_ctx server_api ctx server_mode
 				| None ->
 					(* caused by --connect *)
 					0
 			in
-			if code = 0 && args <> [] && not !has_display then
+			if code = 0 && args <> [] && not !has_display then begin
+				(* We have to chdir here again because any --cwd also takes effect in execute_ctx *)
+				Unix.chdir curdir;
 				loop args
-			else
+			end else
 				code
 		in
 		let code = loop args in

+ 1 - 1
src/compiler/messageReporting.ml

@@ -99,7 +99,7 @@ let compiler_pretty_message_string com ectx cm =
 				let lines = resolve_source f l1 p1 l2 p2 in
 				let epos = Lexer.get_error_pos error_printer cm.cm_pos in
 				(l1, p1, l2, p2, epos, lines)
-			end with Not_found ->
+			end with Not_found | Sys_error _ ->
 				(1, 1, 1, 1, cm.cm_pos.pfile, [])
 			in
 

+ 6 - 3
src/context/resolution.ml

@@ -2,7 +2,7 @@ open Globals
 open Type
 
 type resolution_kind =
-	| RTypeImport of string* module_type
+	| RTypeImport of string * module_type
 	| RClassFieldImport of string * tclass * tclass_field
 	| RAbstractFieldImport of string * tabstract * tclass * tclass_field
 	| REnumConstructorImport of string * tenum * tenum_field
@@ -107,8 +107,7 @@ class resolution_list (id : string list) = object(self)
 			l <- loop [] l;
 		end
 
-	method resolve (i : string) : resolution =
-		self#resolve_lazies;
+	method resolve' (i : string) : resolution =
 		let rec loop l = match l with
 			| [] ->
 				raise Not_found
@@ -148,6 +147,10 @@ class resolution_list (id : string list) = object(self)
 		in
 		loop l
 
+	method resolve (i : string) : resolution =
+		self#resolve_lazies;
+		self#resolve' i
+
 	method expand_enum_constructors (mt : module_type) = match mt with
 		| TAbstractDecl ({a_impl = Some c} as a) when a.a_enum ->
 			Some (class_statics_resolution c null_pos)

+ 3 - 3
src/core/ast.ml

@@ -1008,10 +1008,10 @@ let get_value_meta meta =
 
 (* Type path related functions *)
 
-let rec string_list_of_expr_path_raise (e,p) =
+let rec string_list_of_expr_path_raise ?root_cb (e,p) =
 	match e with
-	| EConst (Ident i) -> [i]
-	| EField (e,f,_) -> f :: string_list_of_expr_path_raise e
+	| EConst (Ident i) -> (match root_cb with None -> [i] | Some f -> f i)
+	| EField (e,f,_) -> f :: string_list_of_expr_path_raise ?root_cb e
 	| _ -> raise Exit
 
 let rec string_pos_list_of_expr_path_raise (e,p) =

+ 49 - 16
src/generators/jvm/jvmFunctions.ml

@@ -294,6 +294,14 @@ module JavaFunctionalInterfaces = struct
 		jparams : string list;
 	}
 
+	let string_of_functional_interface jfi = TPrinting.Printer.s_record_fields "" [
+		"jargs",String.concat ", " (List.map (generate_signature true) jfi.jargs);
+		"jret",Option.map_default (generate_signature true) "None" jfi.jret;
+		"jpath",Globals.s_type_path jfi.jpath;
+		"jname",jfi.jname;
+		"jparams",String.concat ", " jfi.jparams;
+	]
+
 	let java_functional_interfaces = DynArray.create ()
 
 	let add args ret path name params =
@@ -307,30 +315,55 @@ module JavaFunctionalInterfaces = struct
 		DynArray.add java_functional_interfaces jfi
 
 	let unify jfi args ret =
-		let rec loop params want have = match want,have with
+		let params = ref [] in
+		let rec unify jsig1 jsig2 = match jsig1,jsig2 with
+			| TObject(path1,params1),TObject(path2,params2) ->
+				path1 = path2 &&
+				unify_params params1 params2
+			| TTypeParameter n,jsig
+			| jsig,TTypeParameter n ->
+				List.mem_assoc n !params || begin
+					params := (n,jsig) :: !params;
+					true
+				end
+			| _ ->
+				jsig1 = jsig2
+		and unify_params params1 params2 = match params1,params2 with
+			| [],_
+			| _,[] ->
+				(* Assume raw type, I guess? *)
+				true
+			| param1 :: params1,param2 :: params2 ->
+				match param1,param2 with
+				| TAny,_
+				| _,TAny ->
+					(* Is this correct in both directions? *)
+					unify_params params1 params2
+				| TType(_,jsig1),TType(_,jsig2) ->
+					(* TODO: wildcard? *)
+					unify jsig1 jsig2 && unify_params params1 params2
+		in
+		let rec loop want have = match want,have with
 			| [],[] ->
-				Some (jfi,List.map (fun s -> TType(WNone,List.assoc s params)) jfi.jparams)
+				let params = List.map (fun s ->
+					try
+						TType(WNone,List.assoc s !params)
+					with Not_found ->
+						TAny
+				) jfi.jparams in
+				Some (jfi,params)
 			| want1 :: want,have1 :: have ->
-				begin match want1 with
-				| TTypeParameter n ->
-					let have1 = get_boxed_type have1 in
-					loop ((n,have1) :: params) want have
-				| _ ->
-					if have1 <> want1 then None
-					else loop params want have
-				end
+				if unify have1 want1 then loop want have
+				else None
 			| _ ->
 				None
 		in
 		match jfi.jret,ret with
 		| None,None ->
-			loop [] jfi.jargs args
-		| Some (TTypeParameter n),Some jsig ->
-			let jsig = get_boxed_type jsig in
-			loop [n,jsig] jfi.jargs args
+			loop jfi.jargs args
 		| Some jsig1,Some jsig2 ->
-			if jsig1 <> jsig2 then None
-			else loop [] jfi.jargs args
+			if unify jsig1 jsig2 then loop jfi.jargs args
+			else None
 		| _ ->
 			None
 

+ 2 - 2
src/optimization/analyzerTexprTransformer.ml

@@ -102,7 +102,7 @@ let rec func ctx bb tf t p =
 			block_element bb e,e1
 		| TBlock [e1] ->
 			value bb e1
-		| TBlock _ | TIf _ | TSwitch _ | TTry _ ->
+		| TBlock _ | TIf(_,_,Some _) | TSwitch _ | TTry _ ->
 			bind_to_temp bb e
 		| TCall({eexpr = TIdent s},el) when is_really_unbound s ->
 			check_unbound_call s el;
@@ -178,7 +178,7 @@ let rec func ctx bb tf t p =
 		| TThrow _ | TReturn _ | TBreak | TContinue ->
 			let bb = block_element bb e in
 			bb,mk (TConst TNull) t_dynamic e.epos
-		| TVar _ | TFor _ | TWhile _ ->
+		| TVar _ | TFor _ | TWhile _ | TIf _ ->
 			Error.raise_typing_error "Cannot use this expression as value" e.epos
 	and value bb e =
 		let bb,e = value' bb e in

+ 50 - 23
src/optimization/inlineConstructors.ml

@@ -107,6 +107,15 @@ and inline_object_field =
 	| IOFInlineVar of inline_var
 	| IOFNone
 
+(*
+	inline_expression_handled
+	Defines what will happen to the expression being analized by analyze_aliases
+*)
+and inline_expression_handled = 
+	| IEHCaptured (* The expression will be assigned to a variable *)
+	| IEHIgnored (* The result of the expression will not be used *)
+	| IEHNotHandled (* Cases that are not handled (usually leads to cancelling inlining *)
+
 let inline_constructors ctx original_e =
 	let inline_objs = ref IntMap.empty in
 	let vars = ref IntMap.empty in
@@ -259,7 +268,7 @@ let inline_constructors ctx original_e =
 
 		e: The expression to analyze
 	*)
-	let rec analyze_aliases (seen_ctors:tclass_field list) (captured:bool) (is_lvalue:bool) (e:texpr) : inline_var option =
+	let rec analyze_aliases (seen_ctors:tclass_field list) (captured:inline_expression_handled) (is_lvalue:bool) (e:texpr) : inline_var option =
 		let mk_io ?(has_untyped=false) (iok : inline_object_kind) (id:int) (expr:texpr) : inline_object =
 			let io = {
 				io_kind = iok;
@@ -297,8 +306,8 @@ let inline_constructors ctx original_e =
 			| _ -> None
 			end
 		in
-		let handle_field_case ?(captured=false) ?(is_lvalue=false) efield ethis fname validate_io : inline_object_field =
-			begin match analyze_aliases true ethis with
+		let handle_field_case ?(captured=IEHNotHandled) ?(is_lvalue=false) efield ethis fname validate_io : inline_object_field =
+			begin match analyze_aliases IEHCaptured ethis with
 			| Some({iv_state = IVSAliasing io} as iv) when validate_io io ->
 				begin match get_io_inline_method io fname with
 				| Some(c, tl, cf, tf)->
@@ -321,7 +330,7 @@ let inline_constructors ctx original_e =
 							warning ctx WConstructorInliningCancelled ("Constructor inlining cancelled because of use of uninitialized member field " ^ fname) ethis.epos;
 							raise Not_found
 						);
-						if not captured then cancel_iv fiv efield.epos;
+						if captured == IEHNotHandled then cancel_iv fiv efield.epos;
 						IOFInlineVar(fiv)
 					with Not_found ->
 						cancel_iv iv efield.epos;
@@ -343,7 +352,7 @@ let inline_constructors ctx original_e =
 		let handle_default_case e =
 			let old = !scoped_ivs in
 			scoped_ivs := [];
-			let f e = ignore(analyze_aliases false e) in
+			let f e = ignore(analyze_aliases IEHNotHandled e) in
 			Type.iter f e;
 			List.iter (fun iv -> iv.iv_closed <- true) !scoped_ivs;
 			scoped_ivs := old;
@@ -357,7 +366,7 @@ let inline_constructors ctx original_e =
 					| _ ->
 						let v = alloc_var VGenerated "arg" e.etype e.epos in
 						let decle = mk (TVar(v, Some e)) ctx.t.tvoid e.epos in
-						ignore(analyze_aliases true decle);
+						ignore(analyze_aliases IEHIgnored decle);
 						let mde = (Meta.InlineConstructorArgument (v.v_id, 0)), [], e.epos in
 						let e = mk (TMeta(mde, e)) e.etype e.epos in
 						loop (v::vs, e::es) el
@@ -369,7 +378,7 @@ let inline_constructors ctx original_e =
 		let handle_inline_object_case (io_id:int) (force_inline:bool) (e:texpr) =
 			match e.eexpr, e.etype with
 			| TNew({ cl_constructor = Some ({cf_expr = Some ({eexpr = TFunction tf})} as cf)} as c,tl,pl),_
-				when captured && not (List.memq cf seen_ctors) ->
+				when captured!=IEHNotHandled && not (List.memq cf seen_ctors) ->
 				begin
 					let argvs, pl = analyze_call_args pl in
 					let _, cname = c.cl_path in
@@ -395,12 +404,12 @@ let inline_constructors ctx original_e =
 					in loop c tl;
 					let iv = add v IVKLocal in
 					set_iv_alias iv io;
-					ignore(analyze_aliases_in_ctor cf true io.io_expr);
+					ignore(analyze_aliases_in_ctor cf IEHIgnored io.io_expr);
 					Some iv
 				end
 			| TNew({ cl_constructor = Some ({cf_kind = Method MethInline; cf_expr = Some _} as cf)} as c,_,pl),_ when is_extern_ctor c cf ->
 				raise_typing_error "Extern constructor could not be inlined" e.epos;
-			| TObjectDecl fl, _ when captured && fl <> [] && List.for_all (fun((s,_,_),_) -> Lexer.is_valid_identifier s) fl ->
+			| TObjectDecl fl, _ when captured!=IEHNotHandled && fl <> [] && List.for_all (fun((s,_,_),_) -> Lexer.is_valid_identifier s) fl ->
 				let v = alloc_var VGenerated "inlobj" e.etype e.epos in
 				let ev = mk (TLocal v) v.v_type e.epos in
 				let el = List.map (fun ((s,_,_),e) ->
@@ -413,9 +422,9 @@ let inline_constructors ctx original_e =
 				List.iter (fun ((s,_,_),e) -> ignore(alloc_io_field io s e.etype v.v_pos)) fl;
 				let iv = add v IVKLocal in
 				set_iv_alias iv io;
-				List.iter (fun e -> ignore(analyze_aliases true e)) el;
+				List.iter (fun e -> ignore(analyze_aliases IEHIgnored e)) el;
 				Some iv
-			| TArrayDecl el, TInst(_, [elemtype]) when captured ->
+			| TArrayDecl el, TInst(_, [elemtype]) when captured!=IEHNotHandled ->
 				let len = List.length el in
 				let v = alloc_var VGenerated "inlarr" e.etype e.epos in
 				let ev = mk (TLocal v) v.v_type e.epos in
@@ -429,7 +438,7 @@ let inline_constructors ctx original_e =
 				for i = 0 to len-1 do ignore(alloc_io_field io (int_field_name i) elemtype v.v_pos) done;
 				let iv = add v IVKLocal in
 				set_iv_alias iv io;
-				List.iter (fun e -> ignore(analyze_aliases true e)) el;
+				List.iter (fun e -> ignore(analyze_aliases IEHIgnored e)) el;
 				Some iv
 			| _ ->
 				handle_default_case e
@@ -443,7 +452,7 @@ let inline_constructors ctx original_e =
 			handle_inline_object_case io_id false e
 		| TVar(v,None) -> ignore(add v IVKLocal); None
 		| TVar(v,Some rve) ->
-			begin match analyze_aliases true rve with
+			begin match analyze_aliases IEHCaptured rve with
 			| Some({iv_state = IVSAliasing(io)}) ->
 				let iv = add v IVKLocal in
 				set_iv_alias iv io;
@@ -453,15 +462,15 @@ let inline_constructors ctx original_e =
 		| TBinop(OpAssign, lve, rve) ->
 			begin match analyze_aliases_in_lvalue lve with
 			| Some({iv_state = IVSUnassigned} as iv) ->
-				begin match analyze_aliases true rve with
+				begin match analyze_aliases IEHCaptured rve with
 				| Some({iv_state = IVSAliasing(io)}) ->
 					scoped_ivs := iv :: !scoped_ivs;
 					set_iv_alias iv io
 				| _ -> cancel_iv iv lve.epos
 				end;
 				Some iv
-			| Some(iv) -> cancel_iv iv e.epos; ignore(analyze_aliases false rve); None
-			| _ -> ignore(analyze_aliases false rve); None
+			| Some(iv) -> cancel_iv iv e.epos; ignore(analyze_aliases IEHNotHandled rve); None
+			| _ -> ignore(analyze_aliases IEHNotHandled rve); None
 			end
 		| TField(ethis, fa) ->
 			handle_field_case_no_methods e ethis (field_name fa) (fun _ -> true)
@@ -471,19 +480,19 @@ let inline_constructors ctx original_e =
 			handle_field_case_no_methods e ethis (int_field_name i) validate_io
 		| TLocal(v) when v.v_id < 0 ->
 			let iv = get_iv v.v_id in
-			if iv.iv_closed || not captured then cancel_iv iv e.epos;
+			if iv.iv_closed || captured==IEHNotHandled then cancel_iv iv e.epos;
 			Some iv
 		| TBlock(el) ->
 			let rec loop = function
 				| [e] -> analyze_aliases captured e
-				| e::el -> ignore(analyze_aliases true e); loop (el)
+				| e::el -> ignore(analyze_aliases IEHIgnored e); loop (el)
 				| [] -> None
 			in loop el
 		| TMeta((Meta.InlineConstructorArgument (vid,_),_,_),_) ->
 			(* The contents have already been analyzed, so we must skip the wrapped expression *)
 			(try
 				let iv = get_iv vid in
-				if iv.iv_closed || not captured then cancel_iv iv e.epos;
+				if iv.iv_closed || captured==IEHNotHandled then cancel_iv iv e.epos;
 				Some(get_iv vid)
 			with Not_found -> None)
 		| TParenthesis e | TMeta(_,e) | TCast(e,None) ->
@@ -517,14 +526,32 @@ let inline_constructors ctx original_e =
 				end
 			| IOFInlineVar(iv) ->
 				cancel_iv iv e.epos;
-				List.iter (fun ca -> ignore(analyze_aliases false ca)) call_args;
+				List.iter (fun ca -> ignore(analyze_aliases IEHNotHandled ca)) call_args;
 				None
 			| IOFNone ->
-				List.iter (fun ca -> ignore(analyze_aliases false ca)) call_args;
+				List.iter (fun ca -> ignore(analyze_aliases IEHNotHandled ca)) call_args;
 				None
 			end
 		| TFunction tf ->
-			analyze_aliases true tf.tf_expr
+			let old = !scoped_ivs in
+			scoped_ivs := [];
+			ignore(analyze_aliases IEHIgnored tf.tf_expr);
+			List.iter (fun iv -> iv.iv_closed <- true) !scoped_ivs;
+			scoped_ivs := old;
+			None
+		| TWhile(condition, body, _)  ->
+			ignore(analyze_aliases IEHNotHandled condition);
+			ignore(analyze_aliases IEHIgnored body);
+			None
+		| TIf (e,e1,e2) when captured=IEHIgnored ->
+			ignore(analyze_aliases IEHNotHandled e);
+			ignore(analyze_aliases IEHIgnored e1);
+			(match e2 with None -> () | Some e -> ignore(analyze_aliases IEHIgnored e));
+			None
+		| TTry (e,catches) when captured==IEHIgnored ->
+			ignore(analyze_aliases IEHIgnored e);
+			List.iter (fun (_,e) -> ignore(analyze_aliases IEHIgnored e)) catches;
+			None
 		| _ ->
 			handle_default_case e
 	in
@@ -690,7 +717,7 @@ let inline_constructors ctx original_e =
 	in
 	if not (check_for_ctors original_e) then original_e else
 	let e = mark_ctors original_e in
-	ignore(analyze_aliases [] false false e);
+	ignore(analyze_aliases [] IEHNotHandled false e);
 	if IntMap.for_all (fun _ io -> io.io_cancelled) !inline_objs then begin
 		IntMap.iter (fun _ iv -> let v = iv.iv_var in if v.v_id < 0 then v.v_id <- -v.v_id ) !vars;
 		original_e

+ 1 - 1
src/syntax/grammar.mly

@@ -121,7 +121,7 @@ let check_redundant_var p1 = parser
 
 let parsing_macro_cond = ref false
 
-let rec	parse_file s =
+let rec parse_file s =
 	last_doc := None;
 	match s with parser
 	| [< '(Kwd Package,_); pack = parse_package; s >] ->

+ 14 - 2
src/syntax/parser.ml

@@ -22,11 +22,17 @@ open Globals
 open DisplayTypes.DisplayMode
 open DisplayPosition
 
+type preprocessor_error =
+	| InvalidEnd
+	| InvalidElse
+	| InvalidElseif
+	| UnclosedConditional
+
 type error_msg =
 	| Unexpected of token
 	| Duplicate_default
 	| Missing_semicolon
-	| Unclosed_conditional
+	| Preprocessor_error of preprocessor_error
 	| Unimplemented
 	| Missing_type
 	| Expected of string list
@@ -70,7 +76,13 @@ let error_msg = function
 	| Unexpected t -> "Unexpected "^(s_token t)
 	| Duplicate_default -> "Duplicate default"
 	| Missing_semicolon -> "Missing ;"
-	| Unclosed_conditional -> "Unclosed conditional compilation block"
+	| Preprocessor_error ppe ->
+		begin match ppe with
+			| UnclosedConditional -> "Unclosed conditional compilation block"
+			| InvalidEnd -> "Invalid #end"
+			| InvalidElse -> "Invalid #else"
+			| InvalidElseif -> "Invalid #elseif"
+		end
 	| Unimplemented -> "Not implemented for current platform"
 	| Missing_type -> "Missing type declaration"
 	| Expected sl -> "Expected " ^ (String.concat " or " sl)

+ 45 - 45
src/syntax/parserEntry.ml

@@ -143,40 +143,45 @@ class condition_handler = object(self)
 
 	method private cond_if' (e : expr) =
 		conditional_expressions <- e :: conditional_expressions;
-		conditional_stack <- e :: conditional_stack
+		conditional_stack <- (e,false) :: conditional_stack
 
 	method cond_if (e : expr) =
 		self#cond_if' e;
 		depths <- 1 :: depths
 
-	method cond_else = match conditional_stack with
-		| e :: el ->
-			conditional_stack <- (self#negate e) :: el
+	method cond_else (p : pos) =
+		match conditional_stack with
+		| (_,true) :: _ ->
+			error (Preprocessor_error InvalidElse) p
+		| (e,false) :: el ->
+			conditional_stack <- (self#negate e,true) :: el
 		| [] ->
-			die "" __LOC__
+			error (Preprocessor_error InvalidElse) p
 
-	method cond_elseif (e : expr) =
-		self#cond_else;
+	method cond_elseif (e : expr) (p : pos) =
+		self#cond_else p;
 		self#cond_if' e;
 		match depths with
-		| [] -> die "" __LOC__
+		| [] ->
+			error (Preprocessor_error InvalidElseif) p
 		| depth :: depths' ->
 			depths <- (depth + 1) :: depths'
 
-	method cond_end =
+	method cond_end (p : pos) =
 		let rec loop d el =
 			if d = 0 then el
 			else loop (d - 1) (List.tl el)
 		in
 		match depths with
-			| [] -> die "" __LOC__
+			| [] ->
+				error (Preprocessor_error InvalidEnd) p
 			| depth :: depths' ->
 				conditional_stack <- loop depth conditional_stack;
 				depths <- depths'
 
 	method get_current_condition = match conditional_stack with
-		| e :: el ->
-			List.fold_left self#conjoin e el
+		| (e,_) :: el ->
+			List.fold_left self#conjoin e (List.map fst el)
 		| [] ->
 			(EConst (Ident "true"),null_pos)
 
@@ -224,7 +229,6 @@ let parse entry ctx code file =
 			code_ref := old_code;
 		)
 	in
-	let mstack = ref [] in
 	last_doc := None;
 	in_macro := Define.defined ctx Define.Macro;
 	Lexer.skip_header code;
@@ -237,6 +241,9 @@ let parse entry ctx code file =
 	let conds = new condition_handler in
 	let dbc = new dead_block_collector conds in
 	let sraw = Stream.from (fun _ -> Some (Lexer.sharp_token code)) in
+	let preprocessor_error ppe pos tk =
+		syntax_error (Preprocessor_error ppe) ~pos:(Some pos) sraw tk
+	in
 	let rec next_token() = process_token (Lexer.token code)
 
 	and process_token tk =
@@ -257,31 +264,19 @@ let parse entry ctx code file =
 			end;
 			next_token()
 		| Sharp "end" ->
-			(match !mstack with
-			| [] -> tk
-			| _ :: l ->
-				conds#cond_end;
-				mstack := l;
-				next_token())
+			conds#cond_end (snd tk);
+			next_token()
 		| Sharp "elseif" ->
-			(match !mstack with
-			| [] -> tk
-			| _ :: l ->
-				let _,(e,pe) = parse_macro_cond sraw in
-				conds#cond_elseif (e,pe);
-				dbc#open_dead_block pe;
-				mstack := l;
-				let tk = skip_tokens (pos tk) false in
-				process_token tk)
+			let _,(e,pe) = parse_macro_cond sraw in
+			conds#cond_elseif (e,pe) (snd tk);
+			dbc#open_dead_block pe;
+			let tk = skip_tokens (pos tk) false in
+			process_token tk
 		| Sharp "else" ->
-			(match !mstack with
-			| [] -> tk
-			| _ :: l ->
-				conds#cond_else;
-				dbc#open_dead_block (pos tk);
-				mstack := l;
-				let tk = skip_tokens (pos tk) false in
-				process_token tk)
+			conds#cond_else (snd tk);
+			dbc#open_dead_block (pos tk);
+			let tk = skip_tokens (pos tk) false in
+			process_token tk
 		| Sharp "if" ->
 			process_token (enter_macro true (snd tk))
 		| Sharp "error" ->
@@ -302,10 +297,9 @@ let parse entry ctx code file =
 
 	and enter_macro is_if p =
 		let tk, e = parse_macro_cond sraw in
-		(if is_if then conds#cond_if else conds#cond_elseif) e;
+		(if is_if then conds#cond_if e else conds#cond_elseif e p);
 		let tk = (match tk with None -> Lexer.token code | Some tk -> tk) in
 		if is_true (eval ctx e) then begin
-			mstack := p :: !mstack;
 			tk
 		end else begin
 			dbc#open_dead_block (pos e);
@@ -315,24 +309,23 @@ let parse entry ctx code file =
 	and skip_tokens_loop p test tk =
 		match fst tk with
 		| Sharp "end" ->
-			conds#cond_end;
+			conds#cond_end (snd tk);
 			dbc#close_dead_block (pos tk);
 			Lexer.token code
 		| Sharp "elseif" when not test ->
 			dbc#close_dead_block (pos tk);
 			let _,(e,pe) = parse_macro_cond sraw in
-			conds#cond_elseif (e,pe);
+			conds#cond_elseif (e,pe) (snd tk);
 			dbc#open_dead_block pe;
 			skip_tokens p test
 		| Sharp "else" when not test ->
-			conds#cond_else;
+			conds#cond_else (snd tk);
 			dbc#close_dead_block (pos tk);
 			dbc#open_dead_block (pos tk);
 			skip_tokens p test
 		| Sharp "else" ->
-			conds#cond_else;
+			conds#cond_else (snd tk);
 			dbc#close_dead_block (pos tk);
-			mstack := snd tk :: !mstack;
 			Lexer.token code
 		| Sharp "elseif" ->
 			dbc#close_dead_block (pos tk);
@@ -348,7 +341,7 @@ let parse entry ctx code file =
 		| Sharp s ->
 			sharp_error s (pos tk)
 		| Eof ->
-			syntax_error Unclosed_conditional ~pos:(Some p) sraw tk
+			preprocessor_error UnclosedConditional p tk
 		| _ ->
 			skip_tokens p test
 
@@ -362,7 +355,14 @@ let parse entry ctx code file =
 	) in
 	try
 		let l = entry s in
-		(match !mstack with p :: _ -> syntax_error Unclosed_conditional ~pos:(Some p) sraw () | _ -> ());
+		begin match Stream.peek s with
+			| None ->
+				() (* Eof could already have been consumed *)
+			| Some (Eof,_) ->
+				() (* This is what we want *)
+			| Some (tok,p) ->
+				error (Unexpected tok) p (* This isn't *)
+		end;
 		let was_display_file = !in_display_file in
 		restore();
 		Lexer.restore old;

+ 1 - 1
src/typing/matcher/texprConverter.ml

@@ -359,7 +359,7 @@ let to_texpr ctx t_switch with_type dt =
 						let e_else = loop dt_rec params dt2 in
 						begin match e_else with
 						| None ->
-							if toplevel then
+							if toplevel && with_type = NoValue then
 								Some (mk (TIf(e_cond,e_then,None)) t_switch e_then.epos)
 							else
 								report_not_exhaustive !v_lookup e []

+ 3 - 5
src/typing/operators.ml

@@ -13,7 +13,7 @@ let check_error ctx err = match err.err_message with
 	| Module_not_found ([],name) when Diagnostics.error_in_diagnostics_run ctx.com err.err_pos ->
 		DisplayToplevel.handle_unresolved_identifier ctx name err.err_pos true
 	| _ ->
-		Common.display_error_ext ctx.com err
+		raise_or_display_error ctx err
 
 module BinopResult = struct
 
@@ -239,14 +239,12 @@ let make_binop ctx op e1 e2 is_assign_op with_type p =
 			if unify_int ctx e1 KUnk then tint else tfloat
 		| KUnk , KFloat
 		| KUnk , KString  ->
-			unify ctx e1.etype e2.etype e1.epos;
-			e1.etype
+			e2.etype
 		| KInt , KUnk ->
 			if unify_int ctx e2 KUnk then tint else tfloat
 		| KFloat , KUnk
 		| KString , KUnk ->
-			unify ctx e2.etype e1.etype e2.epos;
-			e2.etype
+			e1.etype
 		| _ , KString
 		| KString , _ ->
 			tstring

+ 21 - 8
src/typing/typeloadFields.ml

@@ -457,12 +457,18 @@ let build_enum_abstract ctx c a fields p =
 	) fields;
 	EVars [mk_evar ~t:(CTAnonymous fields,p) ("",null_pos)],p
 
-let apply_macro ctx mode path el p =
-	let cpath, meth = (match List.rev (ExtString.String.nsplit path ".") with
-		| meth :: name :: pack -> (List.rev pack,name), meth
-		| _ -> raise_typing_error "Invalid macro path" p
-	) in
-	ctx.g.do_macro ctx mode cpath meth el p
+let resolve_type_import ctx p i =
+	try
+		let res = ctx.m.import_resolution#resolve' i in
+		begin match res.r_kind with
+		| RTypeImport(_,mt) ->
+			let path = t_path mt in
+			snd path :: (List.rev (fst path))
+		| _ ->
+			raise_typing_error "Type path expected" p
+		end
+	with Not_found ->
+		[i]
 
 let build_module_def ctx mt meta fvars fbuild =
 	let is_typedef = match mt with TTypeDecl _ -> true | _ -> false in
@@ -472,11 +478,18 @@ let build_module_def ctx mt meta fvars fbuild =
 					| [ECall (epath,el),p] -> epath, el
 					| _ -> raise_typing_error "Invalid build parameters" p
 				) in
-				let s = try String.concat "." (List.rev (string_list_of_expr_path epath)) with Error { err_pos = p } -> raise_typing_error "Build call parameter must be a class path" p in
+				let cpath, meth =
+					let sl = try string_list_of_expr_path_raise ~root_cb:(resolve_type_import ctx p) epath with Exit -> raise_typing_error "Build call parameter must be a class path" p in
+					match sl with
+					| meth :: name :: pack ->
+						(List.rev pack,name), meth
+					| _ ->
+						raise_typing_error "Invalid macro path" p
+				in
 				if ctx.com.is_macro_context then raise_typing_error "You cannot use @:build inside a macro : make sure that your type is not used in macro" p;
 				let old = ctx.get_build_infos in
 				ctx.get_build_infos <- (fun() -> Some (mt, extract_param_types (t_infos mt).mt_params, fvars()));
-				let r = try apply_macro ctx MBuild s el p with e -> ctx.get_build_infos <- old; raise e in
+				let r = try ctx.g.do_macro ctx MBuild cpath meth el p with e -> ctx.get_build_infos <- old; raise e in
 				ctx.get_build_infos <- old;
 				(match r with
 				| None -> raise_typing_error "Build failure" p

+ 3 - 1
std/haxe/macro/Context.hx

@@ -112,6 +112,8 @@ class Context {
 
 		If a class path was declared relative, this method returns the relative
 		file path. Otherwise it returns the absolute file path.
+
+		If no type can be found, an exception of type `String` is thrown.
 	**/
 	public static function resolvePath(file:String):String {
 		return load("resolve_path", 1)(file);
@@ -292,7 +294,7 @@ class Context {
 
 		@see https://haxe.org/manual/lf-condition-compilation.html
 	**/
-	public static function definedValue(key:String):String {
+	public static function definedValue(key:String):Null<String> {
 		return load("defined_value", 1)(key);
 	}
 

+ 1 - 1
std/neko/Boot.hx

@@ -48,7 +48,7 @@ class Boot {
 			i += 1;
 		}
 		e.__string = old;
-		return s + untyped ")".__s;
+		return NativeString.ofString(s + untyped ")".__s);
 	}
 
 	private static function __interfLoop(cc:Dynamic, cl:Dynamic) {

+ 2 - 0
tests/misc/projects/Issue10287/Main.hx

@@ -0,0 +1,2 @@
+function foo() return 1;
+function main() trace('${foo()blah}');

+ 1 - 0
tests/misc/projects/Issue10287/compile-fail.hxml

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

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

@@ -0,0 +1,2 @@
+Main.hx:2: characters 31-35 : Unexpected blah
+Main.hx:2: characters 31-35 : ... For function argument 'v'

+ 9 - 0
tests/misc/projects/Issue11208/Main.hx

@@ -0,0 +1,9 @@
+function main() {
+	#if false
+	trace("?");
+	#else
+	trace("!");
+	#else
+	trace("...");
+	#end
+}

+ 1 - 0
tests/misc/projects/Issue11208/compile-fail.hxml

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

+ 1 - 0
tests/misc/projects/Issue11208/compile-fail.hxml.stderr

@@ -0,0 +1 @@
+Main.hx:6: characters 2-7 : Invalid #else

+ 15 - 0
tests/misc/projects/Issue11354/compile.hxml

@@ -0,0 +1,15 @@
+--cwd proj
+--main Main
+
+--each
+
+--cwd a
+--interp
+
+--next
+
+--cwd b
+--interp
+
+--next
+--interp

+ 3 - 0
tests/misc/projects/Issue11354/compile.hxml.stdout

@@ -0,0 +1,3 @@
+Main.hx:2: Hello from folder a
+Main.hx:2: Hello from folder b
+Main.hx:2: Hello from folder proj

+ 3 - 0
tests/misc/projects/Issue11354/proj/Main.hx

@@ -0,0 +1,3 @@
+function main() {
+	trace("Hello from folder proj");
+}

+ 3 - 0
tests/misc/projects/Issue11354/proj/a/Main.hx

@@ -0,0 +1,3 @@
+function main() {
+	trace("Hello from folder a");
+}

+ 3 - 0
tests/misc/projects/Issue11354/proj/b/Main.hx

@@ -0,0 +1,3 @@
+function main() {
+	trace("Hello from folder b");
+}

+ 14 - 0
tests/misc/projects/Issue11354/proj/compile.hxml

@@ -0,0 +1,14 @@
+--main Main
+
+--each
+
+--cwd a
+--interp
+
+--next
+
+--cwd b
+--interp
+
+--next
+--interp

+ 3 - 0
tests/misc/projects/Issue11354/proj/compile.hxml.stdout

@@ -0,0 +1,3 @@
+Main.hx:2: Hello from folder a
+Main.hx:2: Hello from folder b
+Main.hx:2: Hello from folder proj

+ 6 - 0
tests/misc/projects/Issue11366/Main.hx

@@ -0,0 +1,6 @@
+function main() {
+	var x = switch [][0] {
+		case null:
+			'x';
+	}
+}

+ 1 - 0
tests/misc/projects/Issue11366/compile-fail.hxml

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

+ 1 - 0
tests/misc/projects/Issue11366/compile-fail.hxml.stderr

@@ -0,0 +1 @@
+Main.hx:2: characters 17-22 : Unmatched patterns: _

+ 8 - 0
tests/misc/projects/Issue11368/Main.hx

@@ -0,0 +1,8 @@
+macro function test() {
+	haxe.macro.Context.parseInlineSring("p:true,v:0", haxe.macro.Context.currentPos())
+	return macro null;
+}
+
+function main() {
+	test();
+}

+ 1 - 0
tests/misc/projects/Issue11368/compile-fail.hxml

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

+ 1 - 0
tests/misc/projects/Issue11368/compile-fail.hxml.stderr

@@ -0,0 +1 @@
+Main.hx:3: characters 2-8 : Missing ;

+ 18 - 0
tests/misc/projects/Issue11373/Main.hx

@@ -0,0 +1,18 @@
+import pack.BuildMacro;
+import pack.BuildMacro as BM;
+
+@:build(BuildMacro.build())
+class ClassImport {}
+
+@:build(BuildMacro.BuildMacro.build())
+class SubClassImport {}
+
+@:build(BM.build())
+class ClassImportAlias {}
+
+@:build(BM.BuildMacro.build())
+class SubClassImportAlias {}
+
+function main() {
+	trace(BuildMacro.report());
+}

+ 2 - 0
tests/misc/projects/Issue11373/compile.hxml

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

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

@@ -0,0 +1 @@
+Main.hx:17: ClassImport, ClassImportAlias, SubClassImport, SubClassImportAlias

+ 21 - 0
tests/misc/projects/Issue11373/pack/BuildMacro.hx

@@ -0,0 +1,21 @@
+package pack;
+
+import haxe.macro.Context;
+
+class BuildMacro {
+	#if macro
+	static var builtTypes = [];
+	#end
+
+	static public function build():Array<haxe.macro.Expr.Field> {
+		#if macro
+		builtTypes.push("" + Context.getLocalClass());
+		#end
+		return null;
+	}
+
+	macro static public function report() {
+		builtTypes.sort(Reflect.compare);
+		return macro $v{builtTypes.join(", ")};
+	}
+}

+ 1 - 1
tests/misc/projects/Issue2538/compile-fail.hxml.stderr

@@ -1 +1 @@
-Main.hx:7: characters 13-25 : Cannot use Void as value
+Main.hx:7: characters 13-25 : Cannot use this expression as value

+ 2 - 1
tests/misc/projects/Issue8634/compile-fail.hxml.stderr

@@ -1 +1,2 @@
-Main.hx:4: characters 13-17 : Cannot use null as ternary condition
+Main.hx:4: characters 13-17 : Cannot use null as ternary condition
+Main.hx:4: characters 13-17 : ... For function argument 'v'

+ 15 - 0
tests/optimization/src/TestInlineConstructors.hx

@@ -19,6 +19,12 @@ class InlineClass {
 	}
 }
 
+class ExternInlineClass {
+	public var a = 1;
+	public extern inline function new() {
+	}
+}
+
 class InlineIterator {
 	public var i = 0;
 	public inline function new() {};
@@ -130,4 +136,13 @@ class TestInlineConstructors extends TestBase {
 		}
 		return acc;
 	}
+
+	static var condition = false;
+	static function testIgnoredValuesNotCancelling() {
+		var a = new ExternInlineClass();
+		if ( condition ) a else a;
+		while ( condition ) a;
+		try { a; } catch(_) { a; };
+		return a.a;
+	}
 }

+ 11 - 5
tests/server/src/TestCase.hx

@@ -37,19 +37,25 @@ class TestCase implements ITest {
 	public function new() {}
 
 	function debugMessages(?pos:PosInfos) {
-		for (m in messages) haxe.Log.trace(m, pos);
+		for (m in messages)
+			haxe.Log.trace(m, pos);
 	}
 
 	function debugErrorMessages(?pos:PosInfos) {
-		for (m in errorMessages) haxe.Log.trace(m, pos);
+		for (m in errorMessages)
+			haxe.Log.trace(m, pos);
 	}
 
 	function messagesWith(s:String, ?pos:PosInfos) {
-		for (m in messages) if (m.contains(s)) haxe.Log.trace(m, pos);
+		for (m in messages)
+			if (m.contains(s))
+				haxe.Log.trace(m, pos);
 	}
 
 	function errorMessagesWith(s:String, ?pos:PosInfos) {
-		for (m in errorMessages) if (m.contains(s)) haxe.Log.trace(m, pos);
+		for (m in errorMessages)
+			if (m.contains(s))
+				haxe.Log.trace(m, pos);
 	}
 
 	static public function printSkipReason(ddr:SkipReason) {
@@ -211,7 +217,7 @@ class TestCase implements ITest {
 	}
 
 	function assertSkipping(module:String, reason:SkipReason, ?p:haxe.PosInfos) {
-		var msg = 'skipping $module (${printSkipReason(reason))})';
+		var msg = 'skipping $module (${printSkipReason(reason)})';
 		return Assert.isTrue(hasMessage(msg), null, p);
 	}
 

+ 64 - 0
tests/unit/src/unit/issues/Issue11054.hx

@@ -0,0 +1,64 @@
+package unit.issues;
+
+private abstract class Robot<T> {
+	public function new() {}
+
+	public function performTask(listener:T) {}
+
+	public function toString() {
+		return "Robot";
+	}
+}
+
+private interface IGreetRobot {
+	function greet<T>(robot:Robot<T>):Void;
+}
+
+private interface IMathOperation {
+	function operate(a:Int, b:Int):Int;
+}
+
+private class MathRobot extends Robot<IMathOperation> {
+	override function performTask(listener:IMathOperation) {
+		super.performTask(listener);
+		var result = listener.operate(3, 4);
+	}
+}
+
+private class GreetRobot extends Robot<IGreetRobot> {
+	var target:Robot<Dynamic>;
+
+	public function new(target:Robot<Dynamic>) {
+		super();
+		this.target = target;
+	}
+
+	override function performTask(listener:IGreetRobot) {
+		super.performTask(listener);
+		listener.greet(target);
+	}
+}
+
+class Issue11054 extends Test {
+	#if jvm
+	function test() {
+		var robot1 = new MathRobot();
+		var robot2 = new GreetRobot(robot1);
+
+		robot1.performTask(add);
+		robot1.performTask(function(a:Int, b:Int):Int {
+			return a - b;
+		});
+
+		var called = false;
+		robot2.performTask(function(target) {
+			called = true;
+		});
+		t(called);
+	}
+	#end
+
+	static function add(a:Int, b:Int):Int {
+		return a + b;
+	}
+}

+ 33 - 0
tests/unit/src/unit/issues/Issue11274.hx

@@ -0,0 +1,33 @@
+package unit.issues;
+
+using unit.issues.Issue11274.SpriteTools;
+
+private class Sprite {
+	public function new() {}
+}
+
+private class SpriteTools {
+	public static function setName(sprite:Sprite, name:String):Void {}
+}
+
+class Issue11274 extends unit.Test {
+	static var mark = false;
+
+	function test() {
+		sprite(foo -> {
+			foo.setName("foo");
+			add(foo); // err
+		});
+		t(mark);
+	}
+
+	extern inline overload static function sprite(callback:(sprite:Sprite) -> Void) {
+		callback(new Sprite());
+	}
+
+	extern inline overload static function sprite(name:String, callback:(sprite:Sprite) -> Void) {}
+
+	static function add(sprite:Sprite):Void {
+		mark = true;
+	}
+}