2
0
Эх сурвалжийг харах

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 жил өмнө
parent
commit
37a09bbd73
3 өөрчлөгдсөн 17 нэмэгдсэн , 2 устгасан
  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 *)
 (* 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 rec build_generic ctx c p tl =
 	let pack = fst c.cl_path in
 	let pack = fst c.cl_path in
 	let recurse = ref false in
 	let recurse = ref false in
@@ -225,7 +229,12 @@ let rec build_generic ctx c p tl =
 		| l , name -> String.concat "_" l ^ "_" ^ name
 		| l , name -> String.concat "_" l ^ "_" ^ name
 	) tl)) in
 	) tl)) in
 	if !recurse then
 	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
 	else try
 		Typeload.load_instance ctx { tpackage = pack; tname = name; tparams = []; tsub = None } p false
 		Typeload.load_instance ctx { tpackage = pack; tname = name; tparams = []; tsub = None } p false
 	with Error(Module_not_found path,_) when path = (pack,name) ->
 	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
 			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;
 			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;
 		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;
 		c.cl_restore <- restore c;
 		List.iter (fun m ->
 		List.iter (fun m ->
 			match m with
 			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 has_extra_field t n = Has_extra_field (t,n)
 let error l = raise (Unify_error l)
 let error l = raise (Unify_error l)
 let has_meta m ml = List.exists (fun (m2,_,_) -> m = m2) ml
 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 = []
 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;
 				if not (type_iseq tt t) then raise Not_found;
 			with Not_found ->
 			with Not_found ->
 				display_error ctx "Only class type parameters can be constructed in generic instances" p);
 				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 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
 			let ctor = mk_field "new" (tfun (List.map (fun e -> e.etype) el) ctx.t.tvoid) p in
   			(match c.cl_constructor with
   			(match c.cl_constructor with