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

implement resolve on abstracts but comment it out (see #3753)

Simon Krajewski 10 жил өмнө
parent
commit
7aec33f78e
5 өөрчлөгдсөн 86 нэмэгдсэн , 1 устгасан
  1. 1 0
      ast.ml
  2. 1 0
      common.ml
  3. 61 0
      tests/unit/src/unit/issues/Issue3753.hx
  4. 11 0
      typeload.ml
  5. 12 1
      typer.ml

+ 1 - 0
ast.ml

@@ -131,6 +131,7 @@ module Meta = struct
 		| Remove
 		| Require
 		| RequiresAssign
+		(* | Resolve *)
 		| ReplaceReflection
 		| Rtti
 		| Runtime

+ 1 - 0
common.ml

@@ -445,6 +445,7 @@ module MetaInfo = struct
 		| Remove -> ":remove",("Causes an interface to be removed from all implementing classes before generation",[UsedOn TClass])
 		| Require -> ":require",("Allows access to a field only if the specified compiler flag is set",[HasParam "Compiler flag to check";UsedOn TClassField])
 		| RequiresAssign -> ":requiresAssign",("Used internally to mark certain abstract operator overloads",[Internal])
+		(* | Resolve -> ":resolve",("Abstract fields marked with this metadata can be used to resolve unknown fields",[UsedOn TClassField]) *)
 		| ReplaceReflection -> ":replaceReflection",("Used internally to specify a function that should replace its internal __hx_functionName counterpart",[Platforms [Java;Cs]; UsedOnEither[TClass;TEnum]; Internal])
 		| Rtti -> ":rtti",("Adds runtime type informations",[UsedOn TClass])
 		| Runtime -> ":runtime",("?",[])

+ 61 - 0
tests/unit/src/unit/issues/Issue3753.hx

@@ -0,0 +1,61 @@
+package unit.issues;
+
+private abstract A(Map<String, String>) from Map<String, String> {
+	@:resolve
+	function resolve(name:String) {
+		return this[name];
+	}
+}
+
+private abstract B(Map<String, String>) from Map<String, String> {
+	@:resolve
+	static function resolve(lhs:B, name:String) {
+		return lhs.get()[name];
+	}
+
+	function get() return this;
+}
+
+private abstract C(Map<String, String>) from Map<String, String> {
+	@:resolve
+	macro function resolve(ethis:haxe.macro.Expr, name:String) {
+		var s = switch (name) {
+			case "foo": "bar";
+			case "bar": "baz";
+			case _: null;
+		}
+		return macro $v{s};
+	}
+}
+
+private abstract D(Map<String, String>) from Map<String, String> {
+	@:resolve
+	macro static function resolve(ethis:haxe.macro.Expr, name:String) {
+		var s = switch (name) {
+			case "foo": "bar";
+			case "bar": "baz";
+			case _: null;
+		}
+		return macro $v{s};
+	}
+}
+
+class Issue3753 extends Test {
+	function test() {
+		//var a:A = ["foo" => "bar", "bar" => "baz"];
+		//eq("bar", a.foo);
+		//eq("baz", a.bar);
+//
+		//var a:B = ["foo" => "bar", "bar" => "baz"];
+		//eq("bar", a.foo);
+		//eq("baz", a.bar);
+//
+		//var a:C = ["foo" => "bar", "bar" => "baz"];
+		//eq("bar", a.foo);
+		//eq("baz", a.bar);
+//
+		//var a:D = ["foo" => "bar", "bar" => "baz"];
+		//eq("bar", a.foo);
+		//eq("baz", a.bar);
+	}
+}

+ 11 - 0
typeload.ml

@@ -2122,6 +2122,17 @@ let init_class ctx c p context_init herits fields =
 									display_error ctx ("First argument of implementation function must be " ^ (s_type (print_context()) tthis)) f.cff_pos
 							end;
 							loop ml
+(* 						| (Meta.Resolve,_,_) :: _ ->
+							let targ = if Meta.has Meta.Impl f.cff_meta then tthis else ta in
+							begin match follow t with
+								| TFun([(_,_,t1);(_,_,t2)],_) ->
+									if not is_macro then begin
+										if not (type_iseq targ t1) then error ("First argument type must be " ^ (s_type (print_context()) targ)) f.cff_pos;
+										if not (type_iseq ctx.t.tstring t2) then error ("Second argument type must be String") f.cff_pos
+									end
+								| _ ->
+									error ("Field type of resolve must be " ^ (s_type (print_context()) targ) ^ " -> String -> T") f.cff_pos
+							end *)
 						| _ :: ml ->
 							loop ml
 						| [] ->

+ 12 - 1
typer.ml

@@ -67,6 +67,8 @@ type access_kind =
 	| AKUsing of texpr * tclass * tclass_field * texpr
 	| AKAccess of tabstract * tparams * tclass * texpr * texpr
 
+let build_call_ref : (typer -> access_kind -> expr list -> with_type -> pos -> texpr) ref = ref (fun _ _ _ _ _ -> assert false)
+
 let mk_infos ctx p params =
 	let file = if ctx.in_macro then p.pfile else if Common.defined ctx.com Define.AbsolutePath then Common.get_full_path p.pfile else Filename.basename p.pfile in
 	(EObjectDecl (
@@ -1617,6 +1619,14 @@ and type_field ?(resume=false) ctx e i p mode =
 			(match ctx.curfun, e.eexpr with
 			| FunMemberAbstract, TConst (TThis) -> type_field ctx {e with etype = apply_params a.a_params pl a.a_this} i p mode;
 			| _ -> raise Not_found)
+(* 		with Not_found -> try
+			let c = (match a.a_impl with None -> raise Not_found | Some c -> c) in
+			let cf = PMap.find "resolve" c.cl_statics in
+			if not (Meta.has Meta.Resolve cf.cf_meta) then raise Not_found;
+			let et = type_module_type ctx (TClassDecl c) None p in
+			let t = apply_params a.a_params pl (field_type ctx c [] cf p) in
+			let ef = mk (TField (et,FStatic (c,cf))) t p in
+			AKExpr ((!build_call_ref) ctx (AKUsing(ef,c,cf,e)) [EConst (String i),p] NoValue p) *)
 		with Not_found ->
 			if !static_abstract_access_through_instance then error ("Invalid call to static function " ^ i ^ " through abstract instance") p
 			else no_field())
@@ -4914,4 +4924,5 @@ make_call_ref := make_call;
 get_constructor_ref := get_constructor;
 cast_or_unify_ref := Codegen.AbstractCast.cast_or_unify_raise;
 type_module_type_ref := type_module_type;
-find_array_access_raise_ref := Codegen.AbstractCast.find_array_access_raise
+find_array_access_raise_ref := Codegen.AbstractCast.find_array_access_raise;
+build_call_ref := build_call