Browse Source

add TypeTools.applyTypeParameters

Simon Krajewski 12 years ago
parent
commit
9c6f77e990
3 changed files with 56 additions and 3 deletions
  1. 25 0
      interp.ml
  2. 8 3
      std/haxe/macro/Type.hx
  3. 23 0
      std/haxe/macro/TypeTools.hx

+ 25 - 0
interp.ml

@@ -193,11 +193,13 @@ let decode_expr_ref = ref (fun e -> assert false)
 let encode_clref_ref = ref (fun c -> assert false)
 let enc_hash_ref = ref (fun h -> assert false)
 let enc_array_ref = ref (fun l -> assert false)
+let dec_array_ref = ref (fun v -> assert false)
 let enc_string_ref = ref (fun s -> assert false)
 let make_ast_ref = ref (fun _ -> assert false)
 let make_complex_type_ref = ref (fun _ -> assert false)
 let get_ctx() = (!get_ctx_ref)()
 let enc_array (l:value list) : value = (!enc_array_ref) l
+let dec_array (l:value) : value list = (!dec_array_ref) l
 let encode_complex_type (t:Ast.complex_type) : value = (!encode_complex_type_ref) t
 let encode_type (t:Type.t) : value = (!encode_type_ref) t
 let decode_type (v:value) : Type.t = (!decode_type_ref) v
@@ -2463,6 +2465,28 @@ let macro_lib =
 				VNull
 			| _ -> error()
 		);
+		"apply_params", Fun3 (fun tpl tl t ->
+			let tpl = List.map (fun v ->
+				match v with
+				| VObject o ->
+					let name = match get_field o (hash "name") with VString s -> s | _ -> assert false in
+					let t = decode_type (get_field o (hash "t")) in
+					name,t
+				| _ -> assert false
+			) (dec_array tpl) in
+			let tl = List.map decode_type (dec_array tl) in
+			let rec map t = match t with
+				| TInst({cl_kind = KTypeParameter _},_) ->
+					begin try
+						(* use non-physical equality check here to make apply_params work *)
+						snd (List.find (fun (_,t2) -> type_iseq t t2) tpl)
+					with Not_found ->
+						Type.map map t
+					end
+				| _ -> Type.map map t
+			in
+			encode_type (apply_params tpl tl (map (decode_type t)))
+		);
 	]
 
 (* ---------------------------------------------------------------------- *)
@@ -4541,6 +4565,7 @@ make_ast_ref := make_ast;
 make_complex_type_ref := make_type;
 encode_complex_type_ref := encode_ctype;
 enc_array_ref := enc_array;
+dec_array_ref := dec_array;
 encode_type_ref := encode_type;
 decode_type_ref := decode_type;
 encode_expr_ref := encode_expr;

+ 8 - 3
std/haxe/macro/Type.hx

@@ -43,6 +43,11 @@ typedef AnonType = {
 	//var status : AnonStatus;
 }
 
+typedef TypeParameter = {
+	var name: String;
+	var t: Type;
+}
+
 typedef BaseType = {
 	var pack : Array<String>;
 	var name : String;
@@ -50,7 +55,7 @@ typedef BaseType = {
 	var pos : Expr.Position;
 	var isPrivate : Bool;
 	var isExtern : Bool;
-	var params : Array<{ name : String, t : Type }>;
+	var params : Array<TypeParameter>;
 	var meta : MetaAccess;
 	var doc : Null<String>;
 	function exclude() : Void;
@@ -60,7 +65,7 @@ typedef ClassField = {
 	var name : String;
 	var type : Type;
 	var isPublic : Bool;
-	var params : Array<{ name : String, t : Type }>;
+	var params : Array<TypeParameter>;
 	var meta : MetaAccess;
 	var kind : FieldKind;
 	function expr() : Null<TypedExpr>;
@@ -99,7 +104,7 @@ typedef EnumField = {
 	var meta : MetaAccess;
 	var index : Int;
 	var doc : Null<String>;
-	var params : Array<{ name : String, t : Type }>;
+	var params : Array<TypeParameter>;
 }
 
 typedef EnumType = {> BaseType,

+ 23 - 0
std/haxe/macro/TypeTools.hx

@@ -97,6 +97,29 @@ class TypeTools {
 		case _: throw "Enum instance expected";
 	}
 
+	/**
+		Applies the type parameters `typeParameters` to type `t` with the given
+		types `concreteTypes`.
+		
+		This function replaces occurences of type parameters in `t` if they are
+		part of `typeParameters`. The array index of such a type parameter is
+		then used to lookup the concrete type in `concreteTypes`.
+		
+		If `typeParameters.length` is not equal to `concreteTypes.length`, an
+		exception of type `String` is thrown.
+		
+		If `typeParameters.length` is 0, `t` is returned unchanged.
+		
+		If either argument is `null`, the result is unspecified.
+	**/
+	static public function applyTypeParameters(t:Type, typeParameters:Array<TypeParameter>, concreteTypes:Array<Type>):Type {
+		if (typeParameters.length != concreteTypes.length)
+			throw 'Incompatible arguments: ${typeParameters.length} type parameters and ${concreteTypes.length} concrete types';
+		else if (typeParameters.length == 0)
+			return t;
+		return Context.load("apply_params", 3)(typeParameters.map(function(tp) return {name:untyped tp.name.__s, t:tp.t}), concreteTypes, t);
+	}
+	
 	/**
 		Converts type `t` to a human-readable String representation.
 	**/