فهرست منبع

allow using Const type parameters as value (closes #3450)

Simon Krajewski 10 سال پیش
والد
کامیت
d764c9468f
3فایلهای تغییر یافته به همراه48 افزوده شده و 5 حذف شده
  1. 19 1
      codegen.ml
  2. 16 0
      tests/unit/src/unit/issues/Issue3450.hx
  3. 13 4
      typer.ml

+ 19 - 1
codegen.ml

@@ -292,6 +292,24 @@ let generic_substitute_expr gctx e =
 			let _, _, f = gctx.ctx.g.do_build_instance gctx.ctx (TClassDecl c) gctx.p in
 			let t = f (List.map (generic_substitute_type gctx) tl) in
 			build_expr {e with eexpr = TField(e1,quick_field t cf.cf_name)}
+		| 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 ->
+					begin match follow t1 with
+						| TInst(c2,_) when c == c2 -> t2
+						| _ -> 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
+				end
+			with Not_found ->
+				e
+			end
 		| _ ->
 			map_expr_type build_expr (generic_substitute_type gctx) build_var e
 	in
@@ -2022,4 +2040,4 @@ module ExtClass = struct
 		let ef1 = mk (TField(ethis,FStatic(c,cf))) cf.cf_type p in
 		let e_assign = mk (TBinop(OpAssign,ef1,e)) e.etype p in
 		add_cl_init c e_assign
-end
+end

+ 16 - 0
tests/unit/src/unit/issues/Issue3450.hx

@@ -0,0 +1,16 @@
+package unit.issues;
+
+@:generic class X<@:const T, @:const S> {
+	public function new() { }
+
+	public function getString() {
+		return T + " " + S;
+	}
+}
+
+class Issue3450 extends Test {
+	function test() {
+		var c = new X<'foo', 12>();
+		eq("foo 12", c.getString());
+	}
+}

+ 13 - 4
typer.ml

@@ -2493,11 +2493,20 @@ and type_ident ctx i p mode =
 				let t = mk_mono() in
 				AKExpr (mk (TLocal (add_local ctx i t)) t p)
 			end else begin
-				if List.exists (fun (i2,_) -> i2 = i) ctx.type_params then
-					display_error ctx ("Type parameter " ^ i ^ " is only available at compilation and is not a runtime value") p
-				else
+				let e = 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
+						display_error ctx ("Type parameter " ^ i ^ " is only available at compilation and is not a runtime value") p;
+						AKExpr (mk (TConst TNull) t_dynamic p)
+					end
+				with Not_found ->
 					display_error ctx (error_msg err) p;
-				AKExpr (mk (TConst TNull) t_dynamic p)
+					AKExpr (mk (TConst TNull) t_dynamic p)
+				in
+				e
 			end
 		end