Browse Source

allow Rest type parameter for @:genericBuild classes (closes #3089)

Simon Krajewski 11 years ago
parent
commit
20509385d1
3 changed files with 62 additions and 17 deletions
  1. 14 0
      tests/unit/issues/Issue3089.hx
  2. 15 0
      tests/unit/issues/misc/Issue3089Macro.hx
  3. 33 17
      typeload.ml

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

@@ -0,0 +1,14 @@
+package unit.issues;
+
+import unit.issues.misc.Issue3089Macro;
+
+@:genericBuild(unit.issues.misc.Issue3089Macro.build())
+private class GenericBuild<Rest> { }
+
+class Issue3089 extends Test {
+	function test() {
+		unit.TestType.typedAs((null:GenericBuild), (null:GenericBuildResult<"">));
+		unit.TestType.typedAs((null:GenericBuild<String>), (null:GenericBuildResult<"String">));
+		unit.TestType.typedAs((null:GenericBuild<String, Int, Float>), (null:GenericBuildResult<"String_Int_Float">));
+	}
+}

+ 15 - 0
tests/unit/issues/misc/Issue3089Macro.hx

@@ -0,0 +1,15 @@
+package unit.issues.misc;
+import haxe.macro.Expr;
+
+class GenericBuildResult<Const> { }
+
+class Issue3089Macro {
+	macro static public function build():ComplexType {
+		var s = switch (haxe.macro.Context.getLocalType()) {
+			case TInst(_, self): self.map(function(t) return haxe.macro.TypeTools.toString(t)).join("_");
+			default: throw "Something went wrong.";
+		}
+		var ct = TPath({name: "Issue3089Macro", pack: ["unit", "issues", "misc"], sub: "GenericBuildResult", params: [TPExpr(macro $v{s})]});
+		return macro : $ct;
+	}
+}

+ 33 - 17
typeload.ml

@@ -365,7 +365,7 @@ let rec load_instance ctx t p allow_no_params =
 			| [TPType t] -> TDynamic (load_complex_type ctx p t)
 			| [TPType t] -> TDynamic (load_complex_type ctx p t)
 			| _ -> error "Too many parameters for Dynamic" p
 			| _ -> error "Too many parameters for Dynamic" p
 		else begin
 		else begin
-			if List.length types <> List.length t.tparams then error ("Invalid number of type parameters for " ^ s_type_path path) p;
+			(* if List.length types <> List.length t.tparams then error ("Invalid number of type parameters for " ^ s_type_path path) p; *)
 			let tparams = List.map (fun t ->
 			let tparams = List.map (fun t ->
 				match t with
 				match t with
 				| TPExpr e ->
 				| TPExpr e ->
@@ -380,22 +380,38 @@ let rec load_instance ctx t p allow_no_params =
 					TInst (c,[])
 					TInst (c,[])
 				| TPType t -> load_complex_type ctx p t
 				| TPType t -> load_complex_type ctx p t
 			) t.tparams in
 			) t.tparams in
-			let params = List.map2 (fun t (name,t2) ->
-				let isconst = (match t with TInst ({ cl_kind = KExpr _ },_) -> true | _ -> false) in
-				if isconst <> (name = "Const") && t != t_dynamic then error (if isconst then "Constant value unexpected here" else "Constant value excepted as type parameter") p;
-				match follow t2 with
-				| TInst ({ cl_kind = KTypeParameter [] }, []) when not is_generic ->
-					t
-				| TInst (c,[]) ->
-					let r = exc_protect ctx (fun r ->
-						r := (fun() -> t);
-						delay ctx PCheckConstraint (fun() -> check_param_constraints ctx types t tparams c p);
-						t
-					) "constraint" in
-					delay ctx PForce (fun () -> ignore(!r()));
-					TLazy r
-				| _ -> assert false
-			) tparams types in
+			let rec loop tl1 tl2 is_rest = match tl1,tl2 with
+				| t :: tl1,(name,t2) :: tl2 ->
+					let isconst = (match t with TInst ({ cl_kind = KExpr _ },_) -> true | _ -> false) in
+					if isconst <> (name = "Const") && t != t_dynamic then error (if isconst then "Constant value unexpected here" else "Constant value excepted as type parameter") p;
+					let is_rest = is_rest || name = "Rest" in
+					let t = match follow t2 with
+						| TInst ({ cl_kind = KTypeParameter [] }, []) when not is_generic ->
+							t
+						| TInst (c,[]) ->
+							let r = exc_protect ctx (fun r ->
+								r := (fun() -> t);
+								delay ctx PCheckConstraint (fun() -> check_param_constraints ctx types t tparams c p);
+								t
+							) "constraint" in
+							delay ctx PForce (fun () -> ignore(!r()));
+							TLazy r
+						| _ -> assert false
+					in
+					t :: loop tl1 tl2 is_rest
+				| [],[] ->
+					[]
+				| [],["Rest",_] ->
+					[]
+				| [],_ ->
+					error ("Not enough type parameters for " ^ s_type_path path) p
+				| t :: tl,[] ->
+					if is_rest then
+						t :: loop tl [] true
+					else
+						error ("Too many parameters for " ^ s_type_path path) p
+			in
+			let params = loop tparams types false in
 			f params
 			f params
 		end
 		end
 (*
 (*