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

support for abstract type parameters (fixed issue #1400)

Simon Krajewski 12 жил өмнө
parent
commit
4797b4d47c
4 өөрчлөгдсөн 77 нэмэгдсэн , 48 устгасан
  1. 21 18
      codegen.ml
  2. 35 24
      optimizer.ml
  3. 6 2
      typeload.ml
  4. 15 4
      typer.ml

+ 21 - 18
codegen.ml

@@ -1301,26 +1301,29 @@ let check_local_vars_init e =
 (* ABSTRACT CASTS *)
 (* ABSTRACT CASTS *)
 
 
 let handle_abstract_casts ctx e =
 let handle_abstract_casts ctx e =
-	let make_cast_call c cf earg t p =
+	let make_cast_call c cf a pl args t p =
 		let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in
 		let ta = TAnon { a_fields = c.cl_statics; a_status = ref (Statics c) } in
 		let ethis = mk (TTypeExpr (TClassDecl c)) ta p in
 		let ethis = mk (TTypeExpr (TClassDecl c)) ta p in
+		let def () =
+			let e = mk (TField (ethis,(FStatic (c,cf)))) cf.cf_type p in
+			mk (TCall(e,args)) t p
+		in
 		(match cf.cf_expr with
 		(match cf.cf_expr with
-		| Some { eexpr = TFunction fd } ->
-			(match Optimizer.type_inline ctx cf fd ethis earg t p false with
+		| Some { eexpr = TFunction fd } when cf.cf_kind = Method MethInline ->
+			(match Optimizer.type_inline ctx cf fd ethis args t (Some (a.a_types <> [], apply_params a.a_types pl)) p true with
 				| Some e -> e
 				| Some e -> e
 				| None ->
 				| None ->
-					let e = mk (TField (ethis,(FStatic (c,cf)))) cf.cf_type p in
-					mk (TCall(e,earg)) t p)
+					def())
 		| _ ->
 		| _ ->
-			assert false)
+			def())
 	in
 	in
-	let find_from_cast c a t p =
+	let find_from_cast c a pl t p =
 		let rec loop cfl = match cfl with
 		let rec loop cfl = match cfl with
 			| [] ->
 			| [] ->
 				raise Not_found
 				raise Not_found
 			| cf :: cfl when has_meta ":from" cf.cf_meta ->
 			| cf :: cfl when has_meta ":from" cf.cf_meta ->
 				begin match follow cf.cf_type with
 				begin match follow cf.cf_type with
-				| TFun([_,_,ta],_) when type_iseq ta t ->
+				| TFun([_,_,ta],_) when type_iseq (apply_params a.a_types pl ta) t ->
 					cf
 					cf
 				| _ ->
 				| _ ->
 					loop cfl
 					loop cfl
@@ -1349,25 +1352,25 @@ let handle_abstract_casts ctx e =
 	let rec check_cast tleft eright p =
 	let rec check_cast tleft eright p =
 		let eright = loop eright in
 		let eright = loop eright in
 		try (match follow tleft,follow eright.etype with
 		try (match follow tleft,follow eright.etype with
-			| (TAbstract({a_impl = Some c1} as a1,_) as t1),(TAbstract({a_impl = Some c2} as a2,_) as t2) ->
+			| (TAbstract({a_impl = Some c1} as a1,pl1) as t1),(TAbstract({a_impl = Some c2} as a2,pl2) as t2) ->
 				if a1 == a2 then
 				if a1 == a2 then
 					eright
 					eright
 				else begin
 				else begin
-					let c,cf = try
-						c1,find_from_cast c1 a1 t2 p
+					let c,cf,a,pl = try
+						c1,find_from_cast c1 a1 pl1 t2 p,a1,pl1
 					with Not_found ->
 					with Not_found ->
-						c2,find_to_cast c2 a2 t1 p
+						c2,find_to_cast c2 a2 t1 p,a2,pl2
 					in
 					in
-					make_cast_call c cf [eright] tleft p
+					make_cast_call c cf a pl [eright] tleft p
 				end
 				end
 			| TDynamic _,_ | _,TDynamic _ ->
 			| TDynamic _,_ | _,TDynamic _ ->
 				eright
 				eright
-			| TAbstract({a_impl = Some c} as a ,_),t ->
-				let cf = find_from_cast c a eright.etype p in
-				make_cast_call c cf [eright] tleft p
-			| t,TAbstract({a_impl = Some c} as a,_) ->
+			| TAbstract({a_impl = Some c} as a,pl),t ->
+				let cf = find_from_cast c a pl eright.etype p in
+				make_cast_call c cf a pl [eright] tleft p
+			| t,TAbstract({a_impl = Some c} as a,pl) ->
 				let cf = find_to_cast c a t p in
 				let cf = find_to_cast c a t p in
-				make_cast_call c cf [eright] tleft p
+				make_cast_call c cf a pl [eright] tleft p
 			| _ ->
 			| _ ->
 				eright)
 				eright)
 		with Not_found ->
 		with Not_found ->

+ 35 - 24
optimizer.ml

@@ -80,7 +80,29 @@ type in_local = {
 	mutable i_read : int;
 	mutable i_read : int;
 }
 }
 
 
-let rec type_inline ctx cf f ethis params tret p force =
+let inline_default_config cf t =
+	(* type substitution on both class and function type parameters *)
+	let rec get_params c pl =
+		match c.cl_super with
+		| None -> c.cl_types, pl
+		| Some (csup,spl) ->
+			let spl = (match apply_params c.cl_types pl (TInst (csup,spl)) with
+			| TInst (_,pl) -> pl
+			| _ -> assert false
+			) in
+			let ct, cpl = get_params csup spl in
+			c.cl_types @ ct, pl @ cpl
+	in
+	let tparams = (match follow t with
+		| TInst (c,pl) -> get_params c pl
+		| _ -> ([],[]))
+	in
+	let pmonos = List.map (fun _ -> mk_mono()) cf.cf_params in
+	let tmonos = snd tparams @ pmonos in
+	let tparams = fst tparams @ cf.cf_params in
+	tparams <> [], apply_params tparams tmonos
+
+let rec type_inline ctx cf f ethis params tret config p force =
 	(* perform some specific optimization before we inline the call since it's not possible to detect at final optimization time *)
 	(* perform some specific optimization before we inline the call since it's not possible to detect at final optimization time *)
 	try
 	try
 		let cl = (match follow ethis.etype with
 		let cl = (match follow ethis.etype with
@@ -92,25 +114,7 @@ let rec type_inline ctx cf f ethis params tret p force =
 		| None -> raise Exit
 		| None -> raise Exit
 		| Some e -> Some e)
 		| Some e -> Some e)
 	with Exit ->
 	with Exit ->
-	(* type substitution on both class and function type parameters *)
-	let has_params, map_type =
-		let rec get_params c pl =
-			match c.cl_super with
-			| None -> c.cl_types, pl
-			| Some (csup,spl) ->
-				let spl = (match apply_params c.cl_types pl (TInst (csup,spl)) with
-				| TInst (_,pl) -> pl
-				| _ -> assert false
-				) in
-				let ct, cpl = get_params csup spl in
-				c.cl_types @ ct, pl @ cpl
-		in
-		let tparams = (match follow ethis.etype with TInst (c,pl) -> get_params c pl | _ -> ([],[])) in
-		let pmonos = List.map (fun _ -> mk_mono()) cf.cf_params in
-		let tmonos = snd tparams @ pmonos in
-		let tparams = fst tparams @ cf.cf_params in
-		tparams <> [], apply_params tparams tmonos
-	in
+	let has_params,map_type = match config with Some config -> config | None -> inline_default_config cf ethis.etype in
 	(* locals substitution *)
 	(* locals substitution *)
 	let locals = Hashtbl.create 0 in
 	let locals = Hashtbl.create 0 in
 	let local v =
 	let local v =
@@ -332,7 +336,7 @@ let rec type_inline ctx cf f ethis params tret p force =
 		(* force inlining if we modify 'this' *)
 		(* force inlining if we modify 'this' *)
 		if i.i_write && i.i_var.v_name = "this" then force := true;
 		if i.i_write && i.i_var.v_name = "this" then force := true;
 		(* force inlining of 'this' variable if the expression is writable *)
 		(* force inlining of 'this' variable if the expression is writable *)
-		let flag = if not flag && i.i_var.v_name = "this" then begin			
+		let flag = if not flag && i.i_var.v_name = "this" then begin
 			if i.i_write && not (is_writable e) then error "Cannot modify the abstract value, store it into a local first" p;
 			if i.i_write && not (is_writable e) then error "Cannot modify the abstract value, store it into a local first" p;
 			true
 			true
 		end else flag in
 		end else flag in
@@ -387,7 +391,14 @@ let rec type_inline ctx cf f ethis params tret p force =
 			Some e
 			Some e
 		else
 		else
 			let mt = map_type cf.cf_type in
 			let mt = map_type cf.cf_type in
-			unify_raise ctx mt (TFun (List.map (fun e -> "",false,e.etype) params,tret)) p;
+			let unify_func () = unify_raise ctx mt (TFun (List.map (fun e -> "",false,e.etype) params,tret)) p in
+			(match follow ethis.etype with
+			| TAnon a -> (match !(a.a_status) with
+				| Statics {cl_kind = KAbstractImpl a } ->
+					(* TODO: we might have to unify something here *)
+					()
+				| _ -> unify_func())
+			| _ -> unify_func());
 			(*
 			(*
 				this is very expensive since we are building the substitution list for
 				this is very expensive since we are building the substitution list for
 				every expression, but hopefully in such cases the expression size is small
 				every expression, but hopefully in such cases the expression size is small
@@ -892,7 +903,7 @@ let rec reduce_loop ctx e =
 		let cf = mk_field "" ef.etype e.epos in
 		let cf = mk_field "" ef.etype e.epos in
 		let ethis = mk (TConst TThis) t_dynamic e.epos in
 		let ethis = mk (TConst TThis) t_dynamic e.epos in
 		let rt = (match follow ef.etype with TFun (_,rt) -> rt | _ -> assert false) in
 		let rt = (match follow ef.etype with TFun (_,rt) -> rt | _ -> assert false) in
-		let inl = (try type_inline ctx cf func ethis el rt e.epos false with Error (Custom _,_) -> None) in
+		let inl = (try type_inline ctx cf func ethis el rt None e.epos false with Error (Custom _,_) -> None) in
 		(match inl with
 		(match inl with
 		| None -> reduce_expr ctx e
 		| None -> reduce_expr ctx e
 		| Some e -> reduce_loop ctx e)
 		| Some e -> reduce_loop ctx e)
@@ -919,7 +930,7 @@ let rec make_constant_expression ctx e =
 		(try
 		(try
 			let func = match cf.cf_expr with Some ({eexpr = TFunction func}) -> func | _ -> raise Not_found in
 			let func = match cf.cf_expr with Some ({eexpr = TFunction func}) -> func | _ -> raise Not_found in
 			let ethis = mk (TConst TThis) t_dynamic e.epos in
 			let ethis = mk (TConst TThis) t_dynamic e.epos in
-			let inl = (try type_inline ctx cf func ethis el ret e.epos false with Error (Custom _,_) -> None) in
+			let inl = (try type_inline ctx cf func ethis el ret None e.epos false with Error (Custom _,_) -> None) in
 			(match inl with
 			(match inl with
 			| None -> None
 			| None -> None
 			| Some e -> make_constant_expression ctx e)
 			| Some e -> make_constant_expression ctx e)

+ 6 - 2
typeload.ml

@@ -148,7 +148,7 @@ let make_module ctx mpath file tdecls loadp =
 					| _ ->
 					| _ ->
 						f
 						f
 				) fields in
 				) fields in
-				let acc = make_decl acc (EClass { d_name = d.d_name ^ "Impl"; d_flags = [HPrivate]; d_data = fields; d_doc = None; d_params = d.d_params; d_meta = [] },p) in
+				let acc = make_decl acc (EClass { d_name = d.d_name ^ "Impl"; d_flags = [HPrivate]; d_data = fields; d_doc = None; d_params = []; d_meta = [] },p) in
 				(match !decls with
 				(match !decls with
 				| (TClassDecl c,_) :: _ ->
 				| (TClassDecl c,_) :: _ ->
 					a.a_impl <- Some c;
 					a.a_impl <- Some c;
@@ -1302,7 +1302,11 @@ let init_class ctx c p context_init herits fields =
 			let parent = (if not stat then get_parent c name else None) in
 			let parent = (if not stat then get_parent c name else None) in
 			let dynamic = List.mem ADynamic f.cff_access || (match parent with Some { cf_kind = Method MethDynamic } -> true | _ -> false) in
 			let dynamic = List.mem ADynamic f.cff_access || (match parent with Some { cf_kind = Method MethDynamic } -> true | _ -> false) in
 			if inline && dynamic then error "You can't have both 'inline' and 'dynamic'" p;
 			if inline && dynamic then error "You can't have both 'inline' and 'dynamic'" p;
-			ctx.type_params <- if stat then params else params @ ctx.type_params;
+			ctx.type_params <- (match c.cl_kind with
+				| KAbstractImpl a ->
+					params @ a.a_types
+				| _ ->
+					if stat then params else params @ ctx.type_params);
 			let constr = (name = "new") in
 			let constr = (name = "new") in
 			let ret = if constr then ctx.t.tvoid else type_opt ctx p fd.f_type in
 			let ret = if constr then ctx.t.tvoid else type_opt ctx p fd.f_type in
 			let args = List.map (fun (name,opt,t,c) ->
 			let args = List.map (fun (name,opt,t,c) ->

+ 15 - 4
typer.ml

@@ -548,7 +548,7 @@ let get_constructor ctx c params p =
 	| KAbstractImpl a ->
 	| KAbstractImpl a ->
 		let f = (try PMap.find "_new" c.cl_statics with Not_found -> error (s_type_path a.a_path ^ " does not have a constructor") p) in
 		let f = (try PMap.find "_new" c.cl_statics with Not_found -> error (s_type_path a.a_path ^ " does not have a constructor") p) in
 		let ct = field_type ctx c params f p in
 		let ct = field_type ctx c params f p in
-		apply_params c.cl_types params ct, f
+		apply_params a.a_types params ct, f
 	| _ ->
 	| _ ->
 		let ct, f = (try Type.get_constructor (fun f -> field_type ctx c params f p) c with Not_found -> error (s_type_path c.cl_path ^ " does not have a constructor") p) in
 		let ct, f = (try Type.get_constructor (fun f -> field_type ctx c params f p) c with Not_found -> error (s_type_path c.cl_path ^ " does not have a constructor") p) in
 		apply_params c.cl_types params ct, f
 		apply_params c.cl_types params ct, f
@@ -568,11 +568,21 @@ let make_call ctx e params t p =
 			| _ when has_meta ":extern" f.cf_meta -> true
 			| _ when has_meta ":extern" f.cf_meta -> true
 			| _ -> false
 			| _ -> false
 		) in
 		) in
+		let config = match cl with
+			| Some ({cl_kind = KAbstractImpl _ }) ->
+				(match if fname = "_new" then t else follow (List.hd params).etype with
+					| TAbstract(a,pl) ->
+						Some (a.a_types <> [], apply_params a.a_types pl)
+					| _ ->
+						None);
+			| _ ->
+				None
+		in
 		ignore(follow f.cf_type); (* force evaluation *)
 		ignore(follow f.cf_type); (* force evaluation *)
 		let params = List.map (ctx.g.do_optimize ctx) params in
 		let params = List.map (ctx.g.do_optimize ctx) params in
 		(match f.cf_expr with
 		(match f.cf_expr with
 		| Some { eexpr = TFunction fd } ->
 		| Some { eexpr = TFunction fd } ->
-			(match Optimizer.type_inline ctx f fd ethis params t p is_extern with
+			(match Optimizer.type_inline ctx f fd ethis params t config p is_extern with
 			| None ->
 			| None ->
 				if is_extern then error "Inline could not be done" p;
 				if is_extern then error "Inline could not be done" p;
 				raise Exit;
 				raise Exit;
@@ -1011,6 +1021,7 @@ and type_field ctx e i p mode =
 			let c = (match a.a_impl with None -> raise Not_found | Some c -> c) in
 			let c = (match a.a_impl with None -> raise Not_found | Some c -> c) in
 			let f = PMap.find i c.cl_statics in
 			let f = PMap.find i c.cl_statics in
 			let t = field_type ctx c [] f p in
 			let t = field_type ctx c [] f p in
+			let t = apply_params a.a_types pl t in
 			let et = type_module_type ctx (TClassDecl c) None p in
 			let et = type_module_type ctx (TClassDecl c) None p in
 			AKUsing ((mk (TField (et,FStatic (c,f))) t p),c,f,e)
 			AKUsing ((mk (TField (et,FStatic (c,f))) t p),c,f,e)
 		with Not_found -> try
 		with Not_found -> try
@@ -3206,7 +3217,7 @@ and flush_macro_context mint ctx =
 	(* we should maybe ensure that all filters in Main are applied. Not urgent atm *)
 	(* we should maybe ensure that all filters in Main are applied. Not urgent atm *)
 	Interp.add_types mint types (Codegen.post_process [Codegen.captured_vars mctx.com; Codegen.rename_local_vars mctx.com]);
 	Interp.add_types mint types (Codegen.post_process [Codegen.captured_vars mctx.com; Codegen.rename_local_vars mctx.com]);
 	Codegen.post_process_end()
 	Codegen.post_process_end()
-	
+
 let create_macro_interp ctx mctx =
 let create_macro_interp ctx mctx =
 	let com2 = mctx.com in
 	let com2 = mctx.com in
 	let mint, init = (match !macro_interp_cache with
 	let mint, init = (match !macro_interp_cache with
@@ -3227,7 +3238,7 @@ let create_macro_interp ctx mctx =
 	mctx.g.macros <- Some macro;
 	mctx.g.macros <- Some macro;
 	(* mctx.g.core_api <- ctx.g.core_api; // causes some issues because of optional args and Null type in Flash9 *)
 	(* mctx.g.core_api <- ctx.g.core_api; // causes some issues because of optional args and Null type in Flash9 *)
 	init()
 	init()
-	
+
 let get_macro_context ctx p =
 let get_macro_context ctx p =
 	let api = make_macro_api ctx p in
 	let api = make_macro_api ctx p in
 	match ctx.g.macros with
 	match ctx.g.macros with