Browse Source

Fix call stack positions (#11065)

* Error reporting: keep stack data available until the very end

* fix stack depth

* Fix 'for function argument' very important messages

Well, except for have/want errors

* Fix error position recovery

* [tests] Add simple test for #11055

* Don't process eval exceptions twice

* [tests] update

* Reduce diff

* Whitespace

* Make childErrors private
Rudy Ges 2 years ago
parent
commit
c212924e80

+ 3 - 3
src/codegen/gencommon/gencommon.ml

@@ -730,9 +730,9 @@ let run_filters_from gen t filters =
 		()
 
 let run_filters gen =
-	let last_error = gen.gcon.error in
+	let last_error = gen.gcon.located_error in
 	let has_errors = ref false in
-	gen.gcon.error <- (fun ?(depth=0) msg pos -> has_errors := true; last_error ~depth msg pos);
+	gen.gcon.located_error <- (fun ?(depth=0) msg -> has_errors := true; last_error ~depth msg);
 	(* first of all, we have to make sure that the filters won't trigger a major Gc collection *)
 	let t = Timer.timer ["gencommon_filters"] in
 	(if Common.defined gen.gcon Define.GencommonDebug then debug_mode := true else debug_mode := false);
@@ -820,7 +820,7 @@ let run_filters gen =
 
 	reorder_modules gen;
 	t();
-	if !has_errors then raise (Abort("Compilation aborted with errors",null_pos))
+	if !has_errors then abort "Compilation aborted with errors" null_pos
 
 (* ******************************************* *)
 (* basic generation module that source code compilation implementations can use *)

+ 2 - 2
src/codegen/java.ml

@@ -35,9 +35,9 @@ type java_lib_ctx = {
 	is_std : bool;
 }
 
-exception ConversionError of string * pos
+exception ConversionError of located
 
-let error s p = raise (ConversionError (s, p))
+let error s p = raise (ConversionError (located s p))
 
 let is_haxe_keyword = function
 	| "cast" | "extern" | "function" | "in" | "typedef" | "using" | "var" | "untyped" | "inline" -> true

+ 5 - 3
src/compiler/compilationContext.ml

@@ -68,6 +68,8 @@ let error ctx ?(depth=0) msg p =
 	message ctx (make_compiler_message msg p depth DKCompilerMessage Error);
 	ctx.has_error <- true
 
-let located_error ctx ?(depth=0) msg =
-	message ctx (make_compiler_message (extract_located_msg msg) (extract_located_pos msg) depth DKCompilerMessage Error);
-	ctx.has_error <- true
+let located_error ctx ?(depth=0) msg = match (extract_located msg) with
+	| [] -> ()
+	| (msg,p) :: tl ->
+		error ~depth ctx msg p;
+		List.iter (fun (msg,p) -> error ~depth:(depth+1) ctx msg p) tl

+ 3 - 2
src/compiler/compiler.ml

@@ -226,6 +226,7 @@ module Setup = struct
 				()
 		);
 		com.error <- error ctx;
+		com.located_error <- located_error ctx;
 		let filter_messages = (fun keep_errors predicate -> (List.filter (fun cm ->
 			(match cm.cm_severity with
 			| MessageSeverity.Error -> keep_errors;
@@ -336,8 +337,8 @@ with
 		()
 	| Error.Fatal_error (m,depth) ->
 		located_error ~depth ctx m
-	| Common.Abort (m,p) ->
-		error ctx m p
+	| Common.Abort msg ->
+		located_error ctx msg
 	| Lexer.Error (m,p) ->
 		error ctx (Lexer.error_msg m) p
 	| Parser.Error (m,p) ->

+ 3 - 3
src/compiler/displayOutput.ml

@@ -350,8 +350,8 @@ let handle_type_path_exception ctx p c is_import pos =
 			| Some (c,cur_package) ->
 				let ctx = Typer.create com in
 				DisplayPath.TypePathHandler.complete_type_path_inner ctx p c cur_package is_import
-		end with Common.Abort(msg,p) ->
-			error ctx msg p;
+		end with Common.Abort msg ->
+			located_error ctx msg;
 			None
 	in
 	begin match ctx.com.json_out,fields with
@@ -381,4 +381,4 @@ let emit_diagnostics com =
 let emit_statistics tctx =
 	let stats = Statistics.collect_statistics tctx [SFFile (DisplayPosition.display_position#get).pfile] true in
 	let s = Statistics.Printer.print_statistics stats in
-	raise (Completion s)
+	raise (Completion s)

+ 16 - 6
src/context/common.ml

@@ -363,6 +363,7 @@ type context = {
 	(* communication *)
 	mutable print : string -> unit;
 	mutable error : ?depth:int -> string -> pos -> unit;
+	mutable located_error : ?depth:int -> located -> unit;
 	mutable info : ?depth:int -> string -> pos -> unit;
 	mutable warning : ?depth:int -> warning -> Warning.warning_option list list -> string -> pos -> unit;
 	mutable warning_options : Warning.warning_option list list;
@@ -414,7 +415,7 @@ type context = {
 	memory_marker : float array;
 }
 
-exception Abort of string * pos
+exception Abort of located
 
 let ignore_error com =
 	let b = com.display.dms_error_policy = EPIgnore in
@@ -835,6 +836,7 @@ let create compilation_step cs version args =
 		warning = (fun ?depth _ _ _ -> die "" __LOC__);
 		warning_options = [];
 		error = (fun ?depth _ _ -> die "" __LOC__);
+		located_error = (fun ?depth _ -> die "" __LOC__);
 		get_messages = (fun() -> []);
 		filter_messages = (fun _ -> ());
 		pass_debug_messages = DynArray.create();
@@ -1022,7 +1024,8 @@ let allow_package ctx s =
 	with Not_found ->
 		()
 
-let abort ?depth msg p = raise (Abort (msg,p))
+let abort_located ?depth msg = raise (Abort msg)
+let abort ?depth msg p = abort_located ~depth (located msg p)
 
 let platform ctx p = ctx.platform = p
 
@@ -1227,17 +1230,24 @@ let utf16_to_utf8 str =
 	Buffer.contents b
 
 let add_diagnostics_message com msg kind sev =
-	let p = Globals.extract_located_pos msg in
-	let s = Globals.extract_located_msg msg in
 	if sev = MessageSeverity.Error then com.has_error <- true;
 	let di = com.shared.shared_display_information in
-	di.diagnostics_messages <- (s,p,kind,sev) :: di.diagnostics_messages
+	match (extract_located msg) with
+	| [] -> ()
+	| (s,p) :: [] ->
+		di.diagnostics_messages <- (s,p,kind,sev) :: di.diagnostics_messages
+	| (s,p) :: stack ->
+		(* TODO send full stack data as diagnostics attribute for better handling by editors *)
+		let s = List.fold_left (fun acc (s,p) ->
+			Printf.sprintf "%s%s\n" acc (Lexer.get_error_pos (Printf.sprintf "%s:%d: ") p)
+		) (s ^ "\n") stack in
+		di.diagnostics_messages <- (s,p,kind,sev) :: di.diagnostics_messages
 
 let located_display_error com ?(depth = 0) msg =
 	if is_diagnostics com then
 		add_diagnostics_message com msg MessageKind.DKCompilerMessage MessageSeverity.Error
 	else
-		com.error (Globals.extract_located_msg msg) (Globals.extract_located_pos msg) ~depth
+		com.located_error msg ~depth
 
 let display_error com ?(depth = 0) msg p =
 	located_display_error com ~depth (Globals.located msg p)

+ 9 - 5
src/core/error.ml

@@ -105,6 +105,7 @@ module BetterErrors = struct
 		mutable acc_expected : TType.t;
 		mutable acc_actual : TType.t;
 		mutable acc_messages : unify_error list;
+		mutable acc_extra : unify_error list;
 		mutable acc_next : access option;
 	}
 
@@ -121,6 +122,7 @@ module BetterErrors = struct
 			acc_expected = expected;
 			acc_actual = actual;
 			acc_messages = [];
+			acc_extra = [];
 			acc_next = None;
 		} in
 		let root_acc = make_acc Root t_dynamic t_dynamic in
@@ -128,6 +130,9 @@ module BetterErrors = struct
 		let add_message msg =
 			!current_acc.acc_messages <- msg :: !current_acc.acc_messages
 		in
+		let add_extra msg =
+			!current_acc.acc_extra <- msg :: !current_acc.acc_extra
+		in
 		let add_access kind =
 			let acc = make_acc kind t_dynamic t_dynamic in
 			!current_acc.acc_next <- Some acc;
@@ -146,6 +151,8 @@ module BetterErrors = struct
 				add_access FunctionReturn;
 			| Invariant_parameter i ->
 				add_access (TypeParameter i);
+			| Unify_custom _ ->
+				add_extra err
 			| _ ->
 				add_message err
 		) l;
@@ -267,7 +274,7 @@ module BetterErrors = struct
 		in
 		match access.acc_next with
 		| None ->
-			String.concat "\n" (List.rev_map (unify_error_msg ctx) access.acc_messages)
+			String.concat "\n" (List.rev_map (unify_error_msg ctx) (access.acc_extra @ access.acc_messages))
 		| Some access_next ->
 			let slhs,srhs = loop access_next access  in
 			Printf.sprintf "error: %s\nhave: %s\nwant: %s" (Buffer.contents message_buffer) slhs srhs
@@ -297,13 +304,10 @@ let typing_error ?(depth=0) msg p = raise (Error (Custom msg,p,depth))
 let located_typing_error ?(depth=0) msg =
 	let err = match msg with
 		| Message (msg,p) -> Custom msg
-		| Stack stack -> Stack (List.map (fun msg -> (Custom (extract_located_msg msg),(extract_located_pos msg))) stack)
+		| Stack _ -> Stack (List.map (fun (msg,p) -> (Custom msg,p)) (extract_located msg))
 	in
 	raise (Error (err,(extract_located_pos msg),depth))
 
-let call_stack_error ?(depth=0) msg stack p =
-	raise (Error (Stack (((Custom ("Uncaught exception " ^ msg)),p) :: (List.map (fun p -> ((Custom "Called from here"),p)) stack)),p,depth))
-
 let raise_typing_error ?(depth=0) err p = raise (Error(err,p,depth))
 
 let error_require r p =

+ 11 - 6
src/core/globals.ml

@@ -38,14 +38,19 @@ let null_pos = { pfile = "?"; pmin = -1; pmax = -1 }
 let located msg p = Message (msg,p)
 let located_stack stack = Stack stack
 
-let rec extract_located_msg = function
-	 | Message (msg,p) -> msg
-	 | Stack stack -> String.concat "\n" (List.map extract_located_msg stack)
+let rec extract_located = function
+	| Message (msg,p) -> [(msg, p)]
+	| Stack stack -> List.fold_left (fun acc s -> acc @ (extract_located s)) [] stack
+
+let rec relocate msg p = match msg with
+	| Message (msg,_) -> Message (msg,p)
+	| Stack [] -> Stack []
+	| Stack (hd :: tl) -> Stack ((relocate hd p) :: tl)
 
 let rec extract_located_pos = function
-	 | Message (_,p) -> p
-	 | Stack [] -> null_pos
-	 | Stack (hd :: _) -> extract_located_pos hd
+	| Message (_,p) -> p
+	| Stack [] -> null_pos
+	| Stack (hd :: _) -> extract_located_pos hd
 
 let macro_platform = ref Neko
 

+ 3 - 3
src/generators/genpy.ml

@@ -1492,9 +1492,9 @@ module Printer = struct
 				let interpolate () =
 					Codegen.interpolate_code pctx.pc_com code tl (Buffer.add_string buf) (fun e -> Buffer.add_string buf (print_expr pctx e)) ecode.epos
 				in
-				let old = pctx.pc_com.error in
-				pctx.pc_com.error <- abort;
-				Std.finally (fun() -> pctx.pc_com.error <- old) interpolate ();
+				let old = pctx.pc_com.located_error in
+				pctx.pc_com.located_error <- abort_located;
+				Std.finally (fun() -> pctx.pc_com.located_error <- old) interpolate ();
 				Buffer.contents buf
 			| ("python_Syntax._pythonCode"), [e] ->
 				print_expr pctx e

+ 27 - 4
src/macro/eval/evalExceptions.ml

@@ -119,13 +119,29 @@ let catch_exceptions ctx ?(final=(fun() -> ())) f p =
 		final();
 		Some v
 	with
-	| RunTimeException(v,stack,p') ->
+	| RunTimeException(v,eval_stack,p') ->
 		eval.caught_exception <- vnull;
 		Option.may (build_exception_stack ctx) env;
 		eval.env <- env;
 		if is v key_haxe_macro_Error then begin
 			let v1 = field v key_exception_message in
 			let v2 = field v key_pos in
+			let v3 = field v key_child_errors in
+			let stack = match v3 with
+				| VArray sub ->
+						List.map (fun v ->
+							if is v key_haxe_macro_Error then begin
+								let v1 = field v key_exception_message in
+								let v2 = match (field v key_pos) with
+									| VInstance {ikind=IPos p} -> p
+									| _ -> null_pos
+								in
+								(Error.Custom (value_string v1), v2)
+							end else
+								Error.typing_error "Something went wrong" null_pos
+						) (EvalArray.to_list sub)
+				| _ -> []
+			in
 			reset_ctx();
 			final();
 			match v1 with
@@ -146,12 +162,15 @@ let catch_exceptions ctx ?(final=(fun() -> ())) f p =
 							)
 						| _ -> null_pos
 					in
-					raise (Error.Error (Error.Custom s.sstring,p,0))
+					(match stack with
+						| [] -> raise (Error.Error (Error.Custom s.sstring,p,0))
+						| _ -> raise (Error.Error (Stack ((Error.Custom (s.sstring),p) :: stack),p,0))
+					);
 				| _ ->
 					Error.typing_error "Something went wrong" null_pos
 		end else begin
 			(* Careful: We have to get the message before resetting the context because toString() might access it. *)
-			let stack = match stack with
+			let stack = match eval_stack with
 				| [] -> []
 				| l when p' = null_pos -> l (* If the exception position is null_pos, we're "probably" in a built-in function. *)
 				| _ :: l -> l (* Otherwise, ignore topmost frame position. *)
@@ -159,7 +178,11 @@ let catch_exceptions ctx ?(final=(fun() -> ())) f p =
 			let stack = get_exc_error_stack ctx stack in
 			reset_ctx();
 			final();
-			Error.call_stack_error (value_string v) stack (if p' = null_pos then p else p')
+			let p = if p' = null_pos then p else p' in
+			raise (Error.Error (Stack (
+				(Error.Custom ("Uncaught exception " ^ (value_string v)),p)
+				:: (List.map (fun p -> ((Error.Custom "Called from here"),p)) stack)
+			),p,0))
 		end
 	| MacroApi.Abort ->
 		final();

+ 1 - 0
src/macro/eval/evalHash.ml

@@ -203,6 +203,7 @@ let key_fspare = hash "fspare"
 let key_kind = hash "kind"
 let key_end = hash "end"
 let key_events = hash "events"
+let key_child_errors = hash "childErrors"
 let key_isInternal = hash "isInternal"
 let key_physical = hash "physical"
 let key_address = hash "address"

+ 10 - 1
src/macro/eval/evalLuv.ml

@@ -550,7 +550,16 @@ let uv_error_fields = [
 					(* Eval interpreter rethrows runtime exceptions as `Custom "Exception message\nException stack"` *)
 					(try fst (ExtString.String.split msg "\n")
 					with _ -> msg)
-				| HaxeError.Error (err,p,_) -> extract_located_msg (HaxeError.error_msg p err)
+				| HaxeError.Error (err,p,_) ->
+						(* TODO hook global error reporting *)
+						(match (extract_located (HaxeError.error_msg p err)) with
+						| [] -> ""
+						| (s,_) :: [] -> s
+						| (s,_) :: stack ->
+							List.fold_left (fun acc (s,p) ->
+								Printf.sprintf "%s%s\n" acc (Lexer.get_error_pos (Printf.sprintf "%s:%d: ") p)
+							) (s ^ "\n") stack
+						);
 				| _ -> Printexc.to_string ex
 			in
 			let e = create_haxe_exception ~stack:(get_ctx()).exception_stack msg in

+ 40 - 15
src/macro/eval/evalMain.ml

@@ -151,7 +151,16 @@ let create com api is_macro =
 		| _ ->
 			let msg =
 				match ex with
-				| Error.Error (err,p,_) -> extract_located_msg (Error.error_msg p err)
+				| Error.Error (err,p,_) ->
+						(* TODO hook global error reporting *)
+						(match (extract_located (Error.error_msg p err)) with
+						| [] -> ""
+						| (s,_) :: [] -> s
+						| (s,_) :: stack ->
+							List.fold_left (fun acc (s,p) ->
+								Printf.sprintf "%s%s\n" acc (Lexer.get_error_pos (Printf.sprintf "%s:%d: ") p)
+							) (s ^ "\n") stack
+						);
 				| _ -> Printexc.to_string ex
 			in
 			Printf.eprintf "%s\n" msg;
@@ -401,27 +410,43 @@ let set_error ctx b =
 let add_types ctx types ready =
 	if not ctx.had_error then ignore(catch_exceptions ctx (fun () -> ignore(add_types ctx types ready)) null_pos)
 
-let compiler_error msg =
-	let pos = extract_located_pos msg in
-	let msg = extract_located_msg msg in
+let make_runtime_error msg pos =
 	let vi = encode_instance key_haxe_macro_Error in
 	match vi with
 	| VInstance i ->
-		let msg = EvalString.create_unknown msg in
-		set_instance_field i key_exception_message msg;
+		let s = EvalString.create_unknown msg in
+		set_instance_field i key_exception_message s;
 		set_instance_field i key_pos (encode_pos pos);
-		set_instance_field i key_native_exception msg;
-		let ctx = get_ctx() in
-		let eval = get_eval ctx in
-		(match eval.env with
-		| Some _ ->
-			let stack = EvalStackTrace.make_stack_value (call_stack eval) in
-			set_instance_field i key_native_stack stack;
-		| None -> ());
-		exc vi
+		set_instance_field i key_native_exception s;
+		vi
 	| _ ->
 		die "" __LOC__
 
+let compiler_error msg =
+	let pos = extract_located_pos msg in
+	let items = extract_located msg in
+		let vi = make_runtime_error (fst (List.hd items)) pos in
+		match vi with
+		| VInstance i ->
+			(match items with
+			| [] | _ :: [] ->
+				let ctx = get_ctx() in
+				let eval = get_eval ctx in
+				(match eval.env with
+				| Some _ ->
+					let stack = EvalStackTrace.make_stack_value (call_stack eval) in
+					set_instance_field i key_native_stack stack;
+				| None -> ());
+
+			| (hd :: stack) ->
+				let stack = List.map (fun (s,p) -> make_runtime_error s p) stack in
+				set_instance_field i key_child_errors (encode_array stack);
+			);
+
+			exc vi
+		| _ ->
+			die "" __LOC__
+
 let rec value_to_expr v p =
 	let path i =
 		let mt = IntMap.find i (get_ctx()).type_cache in

+ 15 - 8
src/typing/callUnification.ml

@@ -18,7 +18,13 @@ let rec unify_call_args ctx el args r callp inline force_inline in_overload =
 		raise (Error (Call_error err,p,0))
 	in
 	let arg_error ul name opt p =
-		let err = Stack [(ul,p); (Custom ("For " ^ (if opt then "optional " else "") ^ "function argument '" ^ name ^ "'"), p)] in
+		let msg = ("For " ^ (if opt then "optional " else "") ^ "function argument '" ^ name ^ "'") in
+		let err = match ul with
+			| Stack s -> Stack (s @ [(Custom msg,p)])
+			| Unify l -> Unify (l @ [(Unify_custom msg)])
+			| Custom parent -> Custom (parent ^ "\n" ^ msg)
+			| _ -> Stack [(ul,p); (Custom (compl_msg msg), p)]
+		in
 		call_error (Could_not_unify err) p
 	in
 	let mk_pos_infos t =
@@ -470,26 +476,27 @@ object(self)
 		in
 		ctx.macro_depth <- ctx.macro_depth - 1;
 		ctx.with_type_stack <- List.tl ctx.with_type_stack;
-		let old = ctx.com.error in
-		ctx.com.error <- (fun ?(depth=0) msg ep ->
+		let old = ctx.com.located_error in
+		ctx.com.located_error <- (fun ?(depth=0) msg ->
+			let ep = extract_located_pos msg in
 			(* display additional info in the case the error is not part of our original call *)
 			if ep.pfile <> p.pfile || ep.pmax < p.pmin || ep.pmin > p.pmax then begin
 				locate_macro_error := false;
-				old msg (if ep = null_pos then p else ep);
+				old (if ep = null_pos then (relocate msg p) else msg);
 				locate_macro_error := true;
-				if ep <> null_pos then old ~depth:(depth+1) (compl_msg "Called from macro here") p;
+				if ep <> null_pos then old ~depth:(depth+1) (located (compl_msg "Called from macro here") p);
 			end else
-				old msg ep;
+				old msg;
 		);
 		let e = try
 			f()
 		with exc ->
-			ctx.com.error <- old;
+			ctx.com.located_error <- old;
 			!ethis_f();
 			raise exc
 		in
 		let e = Diagnostics.secure_generated_code ctx e in
-		ctx.com.error <- old;
+		ctx.com.located_error <- old;
 		!ethis_f();
 		e
 

+ 15 - 7
src/typing/macroContext.ml

@@ -83,20 +83,28 @@ let macro_timer ctx l =
 
 let typing_timer ctx need_type f =
 	let t = Timer.timer ["typing"] in
-	let old = ctx.com.error and oldp = ctx.pass and oldlocals = ctx.locals in
+	let old = ctx.com.located_error and oldp = ctx.pass and oldlocals = ctx.locals in
 	let restore_report_mode = disable_report_mode ctx.com in
 	(*
 		disable resumable errors... unless we are in display mode (we want to reach point of completion)
 	*)
-	(*if ctx.com.display = DMNone then ctx.com.error <- (fun e p -> raise (Error(Custom e,p)));*) (* TODO: review this... *)
-	ctx.com.error <- (fun ?(depth=0) e p -> raise (Error(Custom e,p,depth)));
+	(*if ctx.com.display = DMNone then ctx.com.located_error <- (fun e p -> raise (Error(Custom e,p)));*) (* TODO: review this... *)
+	let rec located_to_error = function
+		| Message (e,p) -> (Custom e,p)
+		| Stack stack -> (Stack (List.map located_to_error stack),null_pos)
+	in
+
+	ctx.com.located_error <- (fun ?(depth=0) msg ->
+		let (e,p) = located_to_error msg in
+		raise (Error (e,p,depth)));
+
 	if need_type && ctx.pass < PTypeField then begin
 		ctx.pass <- PTypeField;
 		flush_pass ctx PBuildClass "typing_timer";
 	end;
 	let exit() =
 		t();
-		ctx.com.error <- old;
+		ctx.com.located_error <- old;
 		ctx.pass <- oldp;
 		ctx.locals <- oldlocals;
 		restore_report_mode ();
@@ -528,11 +536,11 @@ let create_macro_interp ctx mctx =
 			Interp.do_reuse mint (make_macro_api ctx null_pos);
 			mint, (fun() -> ())
 	) in
-	let on_error = com2.error in
-	com2.error <- (fun ?depth e p ->
+	let on_error = com2.located_error in
+	com2.located_error <- (fun ?depth msg ->
 		Interp.set_error (Interp.get_ctx()) true;
 		macro_interp_cache := None;
-		on_error e p
+		on_error msg
 	);
 	let macro = ((fun() -> Interp.select mint), mctx) in
 	ctx.g.macros <- Some macro;

+ 3 - 3
src/typing/matcher.ml

@@ -269,14 +269,14 @@ module Pattern = struct
 			if pctx.is_postfix_match then DKMarked else DKPattern toplevel
 		in
 		let catch_errors () =
-			let old = ctx.com.error in
+			let old = ctx.com.located_error in
 			let restore_report_mode = disable_report_mode ctx.com in
-			ctx.com.error <- (fun ?depth _ _ ->
+			ctx.com.located_error <- (fun ?depth _ ->
 				raise Exit
 			);
 			(fun () ->
 				restore_report_mode();
-				ctx.com.error <- old
+				ctx.com.located_error <- old
 			)
 		in
 		let try_typing e =

+ 5 - 0
std/haxe/macro/Expr.hx

@@ -1011,6 +1011,11 @@ class Error extends Exception {
 	**/
 	public var pos:Position;
 
+	/**
+		Child error messages, if any.
+	**/
+	private var childErrors:Array<Error>;
+
 	/**
 		Instantiates an error with given message and position.
 	**/

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

@@ -3,4 +3,3 @@ Main.hx:6: characters 9-10 : Warning : { foo : Null<Unknown<0>>, ?b : Null<Int>,
 Main.hx:7: characters 10-11 : error: Int should be String
 Main.hx:7: characters 10-11 : ... have: { b: Int }
 Main.hx:7: characters 10-11 : ... want: { b: String }
-Main.hx:7: characters 10-11 : ... For function argument 'v'

+ 14 - 0
tests/misc/projects/Issue11055/Main.hx

@@ -0,0 +1,14 @@
+macro function test() {
+	foo();
+	return macro null;
+}
+
+#if macro
+function foo() {
+	throw "up";
+}
+#end
+
+function main() {
+	test();
+}

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

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

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

@@ -0,0 +1,3 @@
+Main.hx:8: characters 2-7 : Uncaught exception up
+Main.hx:2: characters 2-7 : Called from here
+Main.hx:13: characters 2-8 : Called from here

+ 3 - 0
tests/misc/projects/Issue11055/compile-pretty-fail.hxml

@@ -0,0 +1,3 @@
+compile-fail.hxml
+-D message-reporting=pretty
+-D no-color

+ 14 - 0
tests/misc/projects/Issue11055/compile-pretty-fail.hxml.stderr

@@ -0,0 +1,14 @@
+[ERROR] Main.hx:8: characters 2-7
+
+ 8 |  throw "up";
+   |  ^^^^^
+   | Uncaught exception up
+
+     2 |  foo();
+       |  ^^^^^
+       | Called from here
+
+    13 |  test();
+       |  ^^^^^^
+       | Called from here
+

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

@@ -1,8 +1,6 @@
 Fail.hx:7: characters 8-12 : error: Void should be haxe.NotVoid
 Fail.hx:7: characters 8-12 : ... have: (...) -> Void
 Fail.hx:7: characters 8-12 : ... want: (...) -> haxe.NotVoid
-Fail.hx:7: characters 8-12 : ... For function argument 'f'
 Fail.hx:8: characters 8-16 : error: FakeVoid should be haxe.NotVoid
 Fail.hx:8: characters 8-16 : ... have: (...) -> FakeVoid
 Fail.hx:8: characters 8-16 : ... want: (...) -> haxe.NotVoid
-Fail.hx:8: characters 8-16 : ... For function argument 'f'

+ 0 - 2
tests/misc/projects/Issue6810/indent-fail.hxml.stderr

@@ -1,8 +1,6 @@
 Fail.hx:7: characters 8-12 : error: Void should be haxe.NotVoid
   Fail.hx:7: characters 8-12 : have: (...) -> Void
   Fail.hx:7: characters 8-12 : want: (...) -> haxe.NotVoid
-  Fail.hx:7: characters 8-12 : For function argument 'f'
 Fail.hx:8: characters 8-16 : error: FakeVoid should be haxe.NotVoid
   Fail.hx:8: characters 8-16 : have: (...) -> FakeVoid
   Fail.hx:8: characters 8-16 : want: (...) -> haxe.NotVoid
-  Fail.hx:8: characters 8-16 : For function argument 'f'

+ 0 - 2
tests/misc/projects/Issue6810/pretty-fail.hxml.stderr

@@ -5,7 +5,6 @@
    | error: Void should be haxe.NotVoid
    | have: (...) -> Void
    | want: (...) -> haxe.NotVoid
-   | For function argument 'f'
 
 [ERROR] Fail.hx:8: characters 8-16
 
@@ -14,5 +13,4 @@
    | error: FakeVoid should be haxe.NotVoid
    | have: (...) -> FakeVoid
    | want: (...) -> haxe.NotVoid
-   | For function argument 'f'
 

+ 6 - 1
tests/unit/src/unit/HelperMacros.hx

@@ -48,11 +48,16 @@ class HelperMacros {
 		return { pos: currentPos(), expr: haxe.macro.Expr.ExprDef.EConst(haxe.macro.Expr.Constant.CIdent(result)) };
 	}
 
+	@:access(haxe.macro.Error.childErrors)
 	static public macro function typeErrorText(e:haxe.macro.Expr) {
 		var result = try {
 			typeof(e);
 			null;
-		} catch (e:haxe.macro.Expr.Error) e.message;
+		} catch (e:haxe.macro.Expr.Error) {
+			var msg = e.message;
+			if (e.childErrors != null) for (c in e.childErrors) msg += "\n" + c.message;
+			msg;
+		}
 		return {
 			pos: currentPos(),
 			expr: if (result == null)