Explorar el Código

[typer] cache @:generic @:const expression and use their type properly

closes #6979
Simon Krajewski hace 7 años
padre
commit
c5e343e4ae
Se han modificado 3 ficheros con 42 adiciones y 13 borrados
  1. 20 10
      src/typing/typeload.ml
  2. 4 3
      src/typing/typer.ml
  3. 18 0
      tests/unit/src/unit/issues/Issue6979.hx

+ 20 - 10
src/typing/typeload.ml

@@ -3767,18 +3767,27 @@ exception Generic_Exception of string * pos
 
 type generic_context = {
 	ctx : typer;
-	subst : (t * t) list;
+	subst : (t * (t * texpr option)) list;
 	name : string;
 	p : pos;
 	mutable mg : module_def option;
 }
 
+let generic_check_const_expr ctx t =
+	match follow t with
+	| TInst({cl_kind = KExpr e},_) ->
+		let e = type_expr ctx e Value in
+		e.etype,Some e
+	| _ -> t,None
+
 let make_generic ctx ps pt p =
 	let rec loop l1 l2 =
 		match l1, l2 with
 		| [] , [] -> []
 		| (x,TLazy f) :: l1, _ -> loop ((x,lazy_type f) :: l1) l2
-		| (_,t1) :: l1 , t2 :: l2 -> (t1,t2) :: loop l1 l2
+		| (_,t1) :: l1 , t2 :: l2 ->
+			let t,eo = generic_check_const_expr ctx t2 in
+			(t1,(t,eo)) :: loop l1 l2
 		| _ -> assert false
 	in
 	let name =
@@ -3820,7 +3829,8 @@ let rec generic_substitute_type gctx t =
 		t
 	| _ ->
 		try
-			generic_substitute_type gctx (List.assq t gctx.subst)
+			let t,_ = List.assq t gctx.subst in
+			generic_substitute_type gctx t
 		with Not_found ->
 			Type.map (generic_substitute_type gctx) t
 
@@ -3848,18 +3858,18 @@ let generic_substitute_expr gctx e =
 			build_expr {e with eexpr = TField(e1,fa)}
 		| TTypeExpr (TClassDecl ({cl_kind = KTypeParameter _;} as c)) when Meta.has Meta.Const c.cl_meta ->
 			let rec loop subst = match subst with
-				| (t1,t2) :: subst ->
+				| (t1,(_,eo)) :: subst ->
 					begin match follow t1 with
-						| TInst(c2,_) when c == c2 -> t2
+						| TInst(c2,_) when c == c2 -> eo
 						| _ -> loop subst
 					end
 				| [] -> raise Not_found
 			in
 			begin try
-				let t = loop gctx.subst in
-				begin match follow t with
-					| TInst({cl_kind = KExpr e},_) -> type_expr gctx.ctx e Value
-					| _ -> error "Only Const type parameters can be used as value" e.epos
+				let eo = loop gctx.subst in
+				begin match eo with
+					| Some e -> e
+					| None -> error "Only Const type parameters can be used as value" e.epos
 				end
 			with Not_found ->
 				e
@@ -3951,7 +3961,7 @@ let rec build_generic ctx c p tl =
 			let param_subst,params = List.fold_left (fun (subst,params) (s,t) -> match follow t with
 				| TInst(c,tl) as t ->
 					let t2 = TInst({c with cl_module = mg;},tl) in
-					(t,t2) :: subst,(s,t2) :: params
+					(t,(t2,None)) :: subst,(s,t2) :: params
 				| _ -> assert false
 			) ([],[]) cf_old.cf_params in
 			let gctx = {gctx with subst = param_subst @ gctx.subst} in

+ 4 - 3
src/typing/typer.ml

@@ -1142,9 +1142,10 @@ and type_ident ctx i p mode =
 			begin try
 				let t = List.find (fun (i2,_) -> i2 = i) ctx.type_params in
 				let c = match follow (snd t) with TInst(c,_) -> c | _ -> assert false in
-				if Typeload.is_generic_parameter ctx c && Meta.has Meta.Const c.cl_meta then
-					AKExpr (type_module_type ctx (TClassDecl c) None p)
-				else begin
+                if Typeload.is_generic_parameter ctx c && Meta.has Meta.Const c.cl_meta then begin
+                    let e = type_module_type ctx (TClassDecl c) None p in
+                    AKExpr {e with etype = (snd t)}
+				end else begin
 					display_error ctx ("Only @:const type parameters on @:generic classes can be used as value") p;
 					AKExpr (mk (TConst TNull) t_dynamic p)
 				end

+ 18 - 0
tests/unit/src/unit/issues/Issue6979.hx

@@ -0,0 +1,18 @@
+package unit.issues;
+
+@:generic class MyGeneric<@:const T> {
+    public function new() {}
+
+    public function foo() {
+        return T;
+    }
+}
+
+
+class Issue6979 extends unit.Test {
+	function test() {
+        var a:MyGeneric<1> = new MyGeneric();
+        unit.HelperMacros.typedAs(a.foo(), 1);
+        eq(3, a.foo() + 2);
+	}
+}