Sfoglia il codice sorgente

[typer] generalize accessor calling

closes #9770
Simon Krajewski 5 anni fa
parent
commit
e6b8e09681
3 ha cambiato i file con 141 aggiunte e 31 eliminazioni
  1. 21 23
      src/typing/calls.ml
  2. 8 8
      src/typing/operators.ml
  3. 112 0
      tests/unit/src/unit/issues/Issue9770.hx

+ 21 - 23
src/typing/calls.ml

@@ -582,13 +582,26 @@ object(self)
 		let e_name = Texpr.Builder.make_string ctx.t name null_pos in
 		self#field_call sea.se_access [eparam;e_name] []
 
-	method setter_call fa el_typed el =
-		let fa_set = match FieldAccess.resolve_accessor fa (MSet None) with
-			| AccessorFound fa -> fa
-			| _ -> error "Could not resolve accessor" p
-		in
-		let dispatcher = new call_dispatcher ctx (MCall el) with_type p in
-		dispatcher#field_call fa_set el_typed el
+	(* Resolves the accessor function for `fa` and calls it with the provided arguments.
+	   If no accessor function is found (AccessorAnon case), a generic field access is generated instead.
+	*)
+	method accessor_call fa el_typed el =
+		match FieldAccess.resolve_accessor fa mode with
+			| AccessorFound fa_accessor ->
+				let dispatcher = new call_dispatcher ctx (MCall el) with_type p in
+				let e = dispatcher#field_call fa_accessor el_typed el in
+				let t = FieldAccess.get_map_function fa fa.fa_field.cf_type in
+				if not (type_iseq_strict t e.etype) then mk (TCast(e,None)) t e.epos else e
+			| AccessorAnon ->
+				let e = fa.fa_on in
+				let t = FieldAccess.get_map_function fa fa.fa_field.cf_type in
+				let el = List.map (fun e -> type_expr ctx e WithType.value) el in
+				let el_typed = el_typed @ el in
+				let tf = tfun (List.map (fun e -> e.etype) el_typed) t in
+				let name = Printf.sprintf "%s_%s" (if is_set then "set" else "get") fa.fa_field.cf_name in
+				make_call ctx (mk (TField (e,quick_field_dynamic e.etype name)) tf p) el_typed t p
+			| _ ->
+				error "Could not resolve accessor" p
 
 	(* Calls the field represented by `fa` with the typed arguments `el_typed` and the syntactic arguments `el`.
 
@@ -621,22 +634,7 @@ object(self)
 		| Var v ->
 			begin match (if is_set then v.v_write else v.v_read) with
 			| AccCall ->
-				begin match FieldAccess.resolve_accessor fa mode with
-				| AccessorFound fa' ->
-					let t = FieldAccess.get_map_function fa fa.fa_field.cf_type in
-					let e = self#field_call fa' el_typed el in
-					if not (type_iseq_strict t e.etype) then mk (TCast(e,None)) t e.epos else e
-				| AccessorAnon ->
-					(* Anons might not have the accessor defined and rely on FDynamic in such cases *)
-					let e = fa.fa_on in
-					let t = FieldAccess.get_map_function fa fa.fa_field.cf_type in
-					let tf = tfun (List.map (fun e -> e.etype) el_typed) t in
-					make_call ctx (mk (TField (e,quick_field_dynamic e.etype ("get_" ^ fa.fa_field.cf_name))) tf p) el_typed t p
-				| AccessorNotFound ->
-					error ("Could not resolve accessor") fa.fa_pos
-				| AccessorInvalid ->
-					die "Trying to resolve accessor on field that isn't AccCall" __LOC__
-				end
+				self#accessor_call fa el_typed el
 			| _ ->
 				self#expr_call (FieldAccess.get_field_expr fa FCall) el
 			end

+ 8 - 8
src/typing/operators.ml

@@ -591,8 +591,8 @@ let type_assign ctx e1 e2 with_type p =
 	| AKExpr e1  ->
 		assign_to e1
 	| AKAccessor fa ->
-		let dispatcher = new call_dispatcher ctx (MCall [e2]) with_type p in
-		dispatcher#setter_call fa [] [e2]
+		let dispatcher = new call_dispatcher ctx (MSet (Some e2)) with_type p in
+		dispatcher#accessor_call fa [] [e2]
 	| AKAccess(a,tl,c,ebase,ekey) ->
 		let e2 = type_rhs WithType.value in
 		mk_array_set_call ctx (AbstractCast.find_array_access ctx a tl ekey (Some e2) p) c ebase p
@@ -666,8 +666,8 @@ let type_assign_op ctx op e1 e2 with_type p =
 	let set vr fa t_lhs r_rhs el =
 		let assign e_rhs =
 			let e_rhs = AbstractCast.cast_or_unify ctx t_lhs e_rhs p in
-			let dispatcher = new call_dispatcher ctx (MCall [e2]) with_type p in
-			dispatcher#setter_call fa (el @ [e_rhs]) [];
+			let dispatcher = new call_dispatcher ctx (MSet (Some e2)) with_type p in
+			dispatcher#accessor_call fa (el @ [e_rhs]) [];
 		in
 		let e = BinopResult.to_texpr vr r_rhs assign in
 		vr#to_texpr e
@@ -868,15 +868,15 @@ let type_unop ctx op flag e p =
 			let fa = {fa with fa_on = ef} in
 			let e_lhs,e_out = read_on vr ef fa in
 			let e_op = mk (TBinop(binop,e_lhs,e_one)) e_lhs.etype p in
-			let dispatcher = new call_dispatcher ctx (MCall []) WithType.value p in
-			let e = dispatcher#setter_call fa [e_op] [] in
+			let dispatcher = new call_dispatcher ctx (MSet None) WithType.value p in
+			let e = dispatcher#accessor_call fa [e_op] [] in
 			generate vr e_out e
 		| AKUsingAccessor sea ->
 			let ef,vr = process_lhs_expr ctx "fh" sea.se_this in
 			let e_lhs,e_out = read_on vr ef sea.se_access in
 			let e_op = mk (TBinop(binop,e_lhs,e_one)) e_lhs.etype p in
-			let dispatcher = new call_dispatcher ctx (MCall []) WithType.value p in
-			let e = dispatcher#setter_call sea.se_access [ef;e_op] [] in
+			let dispatcher = new call_dispatcher ctx (MSet None) WithType.value p in
+			let e = dispatcher#accessor_call sea.se_access [ef;e_op] [] in
 			generate vr e_out e
 		| AKAccess(a,tl,c,ebase,ekey) ->
 			begin try

+ 112 - 0
tests/unit/src/unit/issues/Issue9770.hx

@@ -0,0 +1,112 @@
+package unit.issues;
+
+private abstract A1(I) {
+	var v(get, set):Int;
+
+	public function new(self:I) {
+		this = self;
+	}
+
+	function get_v():Int
+		return this.v;
+
+	function set_v(v:Int):Int
+		return this.v = v;
+}
+
+private interface I {
+	var v(get, set):Int;
+}
+
+private abstract A2(T) {
+	var v(get, set):Int;
+
+	public function new(self:T) {
+		this = self;
+	}
+
+	function get_v():Int
+		return this.v;
+
+	function set_v(v:Int):Int
+		return this.v = v;
+}
+
+private typedef T = {
+	var v(get, set):Int;
+}
+
+private class C implements I {
+	@:isVar public var v(get, set):Int;
+
+	public function new(value:Int) {
+		v = value;
+	}
+
+	public function get_v():Int {
+		return v;
+	}
+
+	public function set_v(value:Int):Int {
+		return v = value;
+	}
+}
+
+class Issue9770 extends unit.Test {
+	function test() {
+		var c = new C(12);
+		eq(12, c.v);
+		eq(13, c.v = c.v + 1);
+		eq(13, c.v);
+		eq(14, c.v += 1);
+		eq(14, c.v);
+		eq(14, c.v++);
+		eq(15, c.v);
+		eq(16, ++c.v);
+		eq(16, c.v);
+
+		var c:I = new C(12);
+		eq(12, c.v);
+		eq(13, c.v = c.v + 1);
+		eq(13, c.v);
+		eq(14, c.v += 1);
+		eq(14, c.v);
+		eq(14, c.v++);
+		eq(15, c.v);
+		eq(16, ++c.v);
+		eq(16, c.v);
+
+		var c:T = new C(12);
+		eq(12, c.v);
+		eq(13, c.v = c.v + 1);
+		eq(13, c.v);
+		eq(14, c.v += 1);
+		eq(14, c.v);
+		eq(14, c.v++);
+		eq(15, c.v);
+		eq(16, ++c.v);
+		eq(16, c.v);
+
+		var c = new A1(new C(12));
+		eq(12, c.v);
+		eq(13, c.v = c.v + 1);
+		eq(13, c.v);
+		eq(14, c.v += 1);
+		eq(14, c.v);
+		eq(14, c.v++);
+		eq(15, c.v);
+		eq(16, ++c.v);
+		eq(16, c.v);
+
+		var c = new A2(new C(12));
+		eq(12, c.v);
+		eq(13, c.v = c.v + 1);
+		eq(13, c.v);
+		eq(14, c.v += 1);
+		eq(14, c.v);
+		eq(14, c.v++);
+		eq(15, c.v);
+		eq(16, ++c.v);
+		eq(16, c.v);
+	}
+}