Przeglądaj źródła

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 13 lat temu
rodzic
commit
37a09bbd73
3 zmienionych plików z 17 dodań i 2 usunięć
  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