瀏覽代碼

try to determine generic type parameters from constructor arguments (closes #2044)

Simon Krajewski 11 年之前
父節點
當前提交
13ab208948
共有 4 個文件被更改,包括 43 次插入14 次删除
  1. 1 1
      codegen.ml
  2. 2 0
      main.ml
  3. 14 0
      tests/unit/issues/Issue2044.hx
  4. 26 13
      typer.ml

+ 1 - 1
codegen.ml

@@ -298,7 +298,7 @@ let rec build_generic ctx c p tl =
 	if !recurse then begin
 		TInst (c,tl) (* build a normal instance *)
 	end else begin
-	let gctx = try make_generic ctx c.cl_types tl p with Generic_Exception (msg,p) -> error msg p in
+	let gctx = make_generic ctx c.cl_types tl p in
 	let name = (snd c.cl_path) ^ "_" ^ gctx.name in
 	try
 		Typeload.load_instance ctx { tpackage = pack; tname = name; tparams = []; tsub = None } p false

+ 2 - 0
main.ml

@@ -1499,6 +1499,8 @@ with
 		message ctx msg p;
 		List.iter (message ctx "Called from") l;
 		error ctx "Aborted" Ast.null_pos;
+	| Codegen.Generic_Exception(m,p) ->
+		error ctx m p
 	| Arg.Bad msg ->
 		error ctx ("Error: " ^ msg) Ast.null_pos
 	| Failure msg when not (is_debug_run()) ->

+ 14 - 0
tests/unit/issues/Issue2044.hx

@@ -0,0 +1,14 @@
+package unit.issues;
+
+@:generic
+private class Gen<T> {
+    public function new(t:T) { }
+}
+
+class Issue2044 extends Test {
+	function test() {
+		eq("unit.issues._Issue2044.Gen_String", Type.getClassName(Type.getClass(new Gen("foo"))));
+		eq("unit.issues._Issue2044.Gen_Int", Type.getClassName(Type.getClass(new Gen(12))));
+		eq("unit.issues._Issue2044.Gen_Bool", Type.getClassName(Type.getClass(new Gen(true))));
+	}
+}

+ 26 - 13
typer.ml

@@ -3119,15 +3119,37 @@ and type_expr ctx (e,p) (with_type:with_type) =
 	| ECall (e,el) ->
 		type_call ctx e el with_type p
 	| ENew (t,el) ->
-		let t = Typeload.load_instance ctx t p true in
-		let ct = (match follow t with
+		let unify_constructor_call c params f ct = match follow ct with
+			| TFun (args,r) ->
+				(try
+					fst (unify_call_params ctx (Some (TInst(c,params),f)) el args r p false)
+				with Error (e,p) ->
+					display_error ctx (error_msg e) p;
+					[])
+			| _ ->
+				error "Constructor is not a function" p
+		in
+		let t = try
+			follow (Typeload.load_instance ctx t p true)
+		with Codegen.Generic_Exception _ ->
+			(* Try to infer generic parameters from the argument list (issue #2044) *)
+			match Typeload.load_type_def ctx p t with
+			| TClassDecl ({cl_constructor = Some cf} as c) ->
+				let monos = List.map (fun _ -> mk_mono()) c.cl_types in
+				let ct, f = get_constructor ctx c monos p in
+				ignore (unify_constructor_call c monos f ct);
+				Codegen.build_generic ctx c p monos
+			| mt ->
+				error ((s_type_path (t_infos mt).mt_path) ^ " cannot be constructed") p
+		in
+		let ct = (match t with
 			| TAbstract (a,pl) ->
 				(match a.a_impl with
 				| None -> t
 				| Some c -> TInst (c,pl))
 			| _ -> t
 		) in
-		(match follow ct with
+		(match ct with
 		| TInst ({cl_kind = KTypeParameter tl} as c,params) ->
 			if not (Typeload.is_generic_parameter ctx c) then error "Only generic type parameters can be constructed" p;
 			let el = List.map (fun e -> type_expr ctx e Value) el in
@@ -3148,16 +3170,7 @@ and type_expr ctx (e,p) (with_type:with_type) =
 			(match f.cf_kind with
 			| Var { v_read = AccRequire (r,msg) } -> (match msg with Some msg -> error msg p | None -> error_require r p)
 			| _ -> ());
-			let el = (match follow ct with
-			| TFun (args,r) ->
-				(try
-					fst (unify_call_params ctx (Some (TInst(c,params),f)) el args r p false)
-				with Error (e,p) ->
-					display_error ctx (error_msg e) p;
-					[])
-			| _ ->
-				error "Constructor is not a function" p
-			) in
+			let el = unify_constructor_call c params f ct in
 			(match c.cl_kind with
 			| KAbstractImpl a when not (Meta.has Meta.MultiType a.a_meta) ->
 				let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in