浏览代码

Collect and reset monomorphs on failed overload resolution (#9696)

* [typer] keep track of more monos

* can't have properly typed code while there's std/neko

* [typer] add Monomorph.on_bind to track bindings

* [typer] drop the callback, just iterate the list
Simon Krajewski 5 年之前
父节点
当前提交
d5a5ab1edf
共有 4 个文件被更改,包括 50 次插入21 次删除
  1. 1 1
      src/context/typecore.ml
  2. 25 15
      src/typing/calls.ml
  3. 1 4
      src/typing/typeload.ml
  4. 23 1
      tests/unit/src/unit/TestConstrainedMonomorphs.hx

+ 1 - 1
src/context/typecore.ml

@@ -178,7 +178,7 @@ let unify_min_for_type_source ctx el src = (!unify_min_for_type_source_ref) ctx
 
 let spawn_monomorph' ctx p =
 	let mono = Monomorph.create () in
-	(* ctx.monomorphs.perfunction <- (mono,p) :: ctx.monomorphs.perfunction; *)
+	ctx.monomorphs.perfunction <- (mono,p) :: ctx.monomorphs.perfunction;
 	mono
 
 let spawn_monomorph ctx p =

+ 25 - 15
src/typing/calls.ml

@@ -284,21 +284,31 @@ let unify_field_call ctx fa el args ret p inline =
 		in
 		match cerr with Could_not_unify err -> loop err | _ -> ()
 	in
-	let rec loop candidates = match candidates with
-		| [] -> [],[]
-		| (t,cf) :: candidates ->
-			begin try
-				let candidate = attempt_call t cf in
-				if ctx.com.config.pf_overload && is_overload then begin
+	let attempt_calls candidates =
+		let rec loop candidates = match candidates with
+			| [] -> [],[]
+			| (t,cf) :: candidates ->
+				let known_monos = List.map (fun (m,_) ->
+					m,m.tm_type,m.tm_constraints
+				) ctx.monomorphs.perfunction in
+				begin try
+					let candidate = attempt_call t cf in
+					if ctx.com.config.pf_overload && is_overload then begin
+						let candidates,failures = loop candidates in
+						candidate :: candidates,failures
+					end else
+						[candidate],[]
+				with Error ((Call_error cerr as err),p) ->
+					List.iter (fun (m,t,constr) ->
+						m.tm_type <- t;
+						m.tm_constraints <- constr;
+					) known_monos;
+					maybe_raise_unknown_ident cerr p;
 					let candidates,failures = loop candidates in
-					candidate :: candidates,failures
-				end else
-					[candidate],[]
-			with Error ((Call_error cerr as err),p) ->
-				maybe_raise_unknown_ident cerr p;
-				let candidates,failures = loop candidates in
-				candidates,(cf,err,p) :: failures
-			end
+					candidates,(cf,err,p) :: failures
+				end
+		in
+		loop candidates
 	in
 	let fail_fun () =
 		let tf = TFun(args,ret) in
@@ -315,7 +325,7 @@ let unify_field_call ctx fa el args ret p inline =
 			fail_fun();
 		end
 	| _ ->
-		let candidates,failures = loop candidates in
+		let candidates,failures = attempt_calls candidates in
 		let fail () =
 			let failures = List.map (fun (cf,err,p) -> cf,error_msg err,p) failures in
 			let failures = remove_duplicates (fun (_,msg1,_) (_,msg2,_) -> msg1 <> msg2) failures in

+ 1 - 4
src/typing/typeload.ml

@@ -733,10 +733,7 @@ let t_iterator ctx =
 *)
 let load_type_hint ?(opt=false) ctx pcur t =
 	let t = match t with
-		| None ->
-			let mono = Monomorph.create () in
-			ctx.monomorphs.perfunction <- (mono,pcur) :: ctx.monomorphs.perfunction;
-			TMono mono
+		| None -> spawn_monomorph ctx pcur
 		| Some (t,p) ->	load_complex_type ctx true (t,p)
 	in
 	if opt then ctx.t.tnull t else t

+ 23 - 1
tests/unit/src/unit/TestConstrainedMonomorphs.hx

@@ -64,11 +64,33 @@ class TestConstrainedMonomorphs extends Test {
 		eq("fooFOO", infer(new MyNotString("foo")));
 	}
 
-	#if todo
+	#if java
 	function testDetectiveHaxe() {
 		var a = null;
 		eq("nullfoo", DetectiveHaxeExtern.itWasYou(a, "foo"));
 	}
+
+	function testDetectiveHaxe2() {
+		var a = [];
+		eq("nullfoo", DetectiveHaxeExtern.itWasYou(a[0], "foo"));
+	}
+
+	#if maybe_todo
+	function testDetectiveHaxe3() {
+		/* This doesn't work because the monomorphs of the inner function are not in-context while
+		   the call is being made. */
+		var a = () -> null;
+		eq("nullfoo", DetectiveHaxeExtern.itWasYou(a(), "foo"));
+	}
+
+	static var a = null;
+	function testDetectiveHaxe4() {
+		/* Similar problem: The monomorph of `static var a` is not in-context,  so it's not reset after the
+		   call failed. */
+		eq("nullfoo", DetectiveHaxeExtern.itWasYou(a, "foo"));
+	}
+	#end
+
 	#end
 
 	static function merge<A:{}, B:{}, C:A & B>(a:A, b:B):C {