Explorar o código

keep generic classes if they were used recursively, but make sure to error if their type parameters were used at the same time

Simon Krajewski %!s(int64=13) %!d(string=hai) anos
pai
achega
37a09bbd73
Modificáronse 3 ficheiros con 17 adicións e 2 borrados
  1. 11 2
      codegen.ml
  2. 1 0
      type.ml
  3. 5 0
      typer.ml

+ 11 - 2
codegen.ml

@@ -201,6 +201,10 @@ let extend_remoting ctx c t p async prot =
 (* -------------------------------------------------------------------------- *)
 (* HAXE.RTTI.GENERIC *)
 
+let recursive_usage_error ctx p p2 =
+	display_error ctx "Recursive generics may not use their type parameters as values" p;
+	error "Class was used recursively here" p2
+
 let rec build_generic ctx c p tl =
 	let pack = fst c.cl_path in
 	let recurse = ref false in
@@ -225,7 +229,12 @@ let rec build_generic ctx c p tl =
 		| l , name -> String.concat "_" l ^ "_" ^ name
 	) tl)) in
 	if !recurse then
-		TInst (c,tl) (* build a normal instance *)
+		(try
+			let (_,_,p2) = get_meta ":genericT" c.cl_meta in
+			recursive_usage_error ctx p2 p;
+		with Not_found ->
+			if not (has_meta ":usedRecursively" c.cl_meta) then c.cl_meta <- (":usedRecursively",[],p) :: c.cl_meta;
+			TInst (c,tl)) (* build a normal instance *)
 	else try
 		Typeload.load_instance ctx { tpackage = pack; tname = name; tparams = []; tsub = None } p false
 	with Error(Module_not_found path,_) when path = (pack,name) ->
@@ -596,7 +605,7 @@ let on_generate ctx t =
 			let rpath = (fst c.cl_module.m_path,"_" ^ snd c.cl_module.m_path) in
 			if Hashtbl.mem ctx.g.types_module rpath then error ("This private class name will clash with " ^ s_type_path rpath) c.cl_pos;
 		end;
-		if c.cl_kind = KGeneric then c.cl_extern <- true;
+		if c.cl_kind = KGeneric && not (has_meta ":usedRecursively" c.cl_meta) then c.cl_extern <- true;
 		c.cl_restore <- restore c;
 		List.iter (fun m ->
 			match m with

+ 1 - 0
type.ml

@@ -646,6 +646,7 @@ let has_no_field t n = Has_no_field (t,n)
 let has_extra_field t n = Has_extra_field (t,n)
 let error l = raise (Unify_error l)
 let has_meta m ml = List.exists (fun (m2,_,_) -> m = m2) ml
+let get_meta m ml = List.find (fun (m2,_,_) -> m = m2) ml
 let no_meta = []
 
 (*

+ 5 - 0
typer.ml

@@ -1950,6 +1950,11 @@ and type_expr ctx ?(need_val=true) (e,p) =
 				if not (type_iseq tt t) then raise Not_found;
 			with Not_found ->
 				display_error ctx "Only class type parameters can be constructed in generic instances" p);
+			(try
+				let (_,_,p2) = get_meta ":usedRecursively" ctx.curclass.cl_meta in
+				Codegen.recursive_usage_error ctx p2 p;
+			with Not_found -> ());
+			if not (has_meta ":genericT" ctx.curclass.cl_meta) then ctx.curclass.cl_meta <- (":genericT",[],p) :: ctx.curclass.cl_meta;
 			let el = List.map (type_expr ctx) el in
 			let ctor = mk_field "new" (tfun (List.map (fun e -> e.etype) el) ctx.t.tvoid) p in
   			(match c.cl_constructor with