Преглед изворни кода

[abstracts] fix operator overloading with external methods (#10074)

Dmitrii Maganov пре 4 година
родитељ
комит
8ce5f05a6b

+ 4 - 4
src/typing/calls.ml

@@ -76,10 +76,10 @@ let make_call ctx e params t ?(force_inline=false) p =
 		mk (TCall (e,params)) t p
 
 let mk_array_get_call ctx (cf,tf,r,e1,e2o) c ebase p = match cf.cf_expr with
-	| None ->
+	| None when not (has_class_field_flag cf CfExtern) ->
 		if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive array get method" p;
 		mk (TArray(ebase,e1)) r p
-	| Some _ ->
+	| _ ->
 		let et = type_module_type ctx (TClassDecl c) None p in
 		let ef = mk (TField(et,(FStatic(c,cf)))) tf p in
 		make_call ctx ef [ebase;e1] r p
@@ -87,11 +87,11 @@ let mk_array_get_call ctx (cf,tf,r,e1,e2o) c ebase p = match cf.cf_expr with
 let mk_array_set_call ctx (cf,tf,r,e1,e2o) c ebase p =
 	let evalue = match e2o with None -> die "" __LOC__ | Some e -> e in
 	match cf.cf_expr with
-		| None ->
+		| None when not (has_class_field_flag cf CfExtern) ->
 			if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive array set method" p;
 			let ea = mk (TArray(ebase,e1)) r p in
 			mk (TBinop(OpAssign,ea,evalue)) r p
-		| Some _ ->
+		| _ ->
 			let et = type_module_type ctx (TClassDecl c) None p in
 			let ef = mk (TField(et,(FStatic(c,cf)))) tf p in
 			make_call ctx ef [ebase;e1;evalue] r p

+ 1 - 1
src/typing/operators.ml

@@ -451,7 +451,7 @@ let make_binop ctx op e1 e2 is_assign_op with_type p =
 let find_abstract_binop_overload ctx op e1 e2 a c tl left is_assign_op with_type p =
 	let map = apply_params a.a_params tl in
 	let make op_cf cf e1 e2 tret needs_assign swapped =
-		if cf.cf_expr = None then begin
+		if cf.cf_expr = None && not (has_class_field_flag cf CfExtern) then begin
 			if not (Meta.has Meta.NoExpr cf.cf_meta) then display_error ctx "Recursive operator method" p;
 			if not (Meta.has Meta.CoreType a.a_meta) then begin
 				(* for non core-types we require that the return type is compatible to the native result type *)

+ 13 - 15
src/typing/typeloadFields.ml

@@ -1008,6 +1008,10 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 			let ta = TAbstract(a,List.map (fun _ -> mk_mono()) a.a_params) in
 			let tthis = if fctx.is_abstract_member || Meta.has Meta.To cf.cf_meta then monomorphs a.a_params a.a_this else a.a_this in
 			let allows_no_expr = ref (Meta.has Meta.CoreType a.a_meta) in
+			let allow_no_expr () = if not (has_class_field_flag cf CfExtern) then begin
+				allows_no_expr := true;
+				fctx.expr_presence_matters <- true;
+			end in
 			let rec loop ml =
 				(match ml with
 				| (Meta.From,_,_) :: _ ->
@@ -1065,7 +1069,7 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 				| ((Meta.ArrayAccess,_,_) | (Meta.Op,[(EArrayDecl _),_],_)) :: _ ->
 					if fctx.is_macro then error (cf.cf_name ^ ": Macro array-access functions are not supported") p;
 					a.a_array <- cf :: a.a_array;
-					fctx.expr_presence_matters <- true;
+					allow_no_expr();
 				| (Meta.Op,[EBinop(OpAssign,_,_),_],_) :: _ ->
 					error (cf.cf_name ^ ": Assignment overloading is not supported") p;
 				| (Meta.Op,[ETernary(_,_,_),_],_) :: _ ->
@@ -1085,15 +1089,13 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 					if not (left_eq || right_eq) then error (cf.cf_name ^ ": The left or right argument type must be " ^ (s_type (print_context()) targ)) cf.cf_pos;
 					if right_eq && Meta.has Meta.Commutative cf.cf_meta then error (cf.cf_name ^ ": @:commutative is only allowed if the right argument is not " ^ (s_type (print_context()) targ)) cf.cf_pos;
 					a.a_ops <- (op,cf) :: a.a_ops;
-					allows_no_expr := true;
-					fctx.expr_presence_matters <- true;
+					allow_no_expr();
 				| (Meta.Op,[EUnop(op,flag,_),_],_) :: _ ->
 					if fctx.is_macro then error (cf.cf_name ^ ": Macro operator functions are not supported") p;
 					let targ = if fctx.is_abstract_member then tthis else ta in
 					(try type_eq EqStrict t (tfun [targ] (mk_mono())) with Unify_error l -> raise (Error ((Unify l),cf.cf_pos)));
 					a.a_unops <- (op,flag,cf) :: a.a_unops;
-					allows_no_expr := true;
-					fctx.expr_presence_matters <- true;
+					allow_no_expr();
 				| ((Meta.Resolve,_,_) | (Meta.Op,[EField _,_],_)) :: _ ->
 					let targ = if fctx.is_abstract_member then tthis else ta in
 					let check_fun t1 t2 =
@@ -1120,20 +1122,16 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 				| [] -> ()
 			in
 			loop cf.cf_meta;
-			let check_bind () =
-				if fd.f_expr = None then begin
-					if fctx.is_inline then error (cf.cf_name ^ ": Inline functions must have an expression") cf.cf_pos;
-					begin match fd.f_type with
-						| None -> error (cf.cf_name ^ ": Functions without expressions must have an explicit return type") cf.cf_pos
-						| Some _ -> ()
-					end;
+			if cf.cf_name = "_new" && Meta.has Meta.MultiType a.a_meta then fctx.do_bind <- false;
+			if fd.f_expr = None then begin
+				if fctx.is_inline then error (cf.cf_name ^ ": Inline functions must have an expression") cf.cf_pos;
+				if fd.f_type = None then error (cf.cf_name ^ ": Functions without expressions must have an explicit return type") cf.cf_pos;
+				if !allows_no_expr then begin
 					cf.cf_meta <- (Meta.NoExpr,[],null_pos) :: cf.cf_meta;
 					fctx.do_bind <- false;
 					if not (Meta.has Meta.CoreType a.a_meta) then fctx.do_add <- false;
 				end
-			in
-			if cf.cf_name = "_new" && Meta.has Meta.MultiType a.a_meta then fctx.do_bind <- false;
-			if !allows_no_expr then check_bind()
+			end
 		| _ ->
 			()
 

+ 1 - 1
std/haxe/Int32.hx

@@ -68,7 +68,7 @@ abstract Int32(Int) from Int to Int {
 
 	@:op(A - B) private static function subFloat(a:Int32, b:Float):Float;
 
-	@:op(A - B) public static function floatSub(a:Float, b:Int32):Float;
+	@:op(A - B) private static function floatSub(a:Float, b:Int32):Float;
 
 	#if (js || php || python || lua)
 	#if js

+ 41 - 0
tests/unit/src/unit/issues/Issue10073.hx

@@ -0,0 +1,41 @@
+package unit.issues;
+
+private abstract Foo(Array<Int>) from Array<Int> {
+  @:op([])
+  function get(index: Int): Int;
+
+  @:op([])
+  function set(index: Int, value: Int): Void;
+}
+
+#if eval
+abstract Bar(Int) from Int {
+  @:op(_ + _)
+  extern function add(other: Int): Int;
+
+  @:op([])
+  extern function get(index: Int): Int;
+
+  @:native('add')
+  function doAdd(other: Int): Int
+    return 39;
+
+  @:native('get')
+  function doGet(index: Int)
+    return (this + index) * 2;
+}
+#end
+
+class Issue10073 extends Test {
+  function test() {
+    var foo: Foo = [];
+    foo[0] = 3;
+    eq(3, foo[0]);
+
+    #if eval
+    var bar: Bar = 71;
+    eq(39, bar + 1);
+    eq(144, bar[1]);
+    #end
+  }
+}

+ 8 - 8
tests/unit/src/unit/issues/Issue3345.hx

@@ -8,14 +8,14 @@ private abstract Meters(Float) from Float {
 		this = f;
 	}
 
-	@:op(-A) extern public static function neg(s:Meters):Meters;
-	@:op(A+B) extern public static function add(lhs:Meters, rhs:Meters):Meters;
-	@:op(A-B) extern public static function sub(lhs:Meters, rhs:Meters):Meters;
-	@:op(A>B) extern public static function gt(lhs:Meters, rhs:Meters):Bool;
-	@:op(A>=B) extern public static function gte(lhs:Meters, rhs:Meters):Bool;
-	@:op(A<B) extern public static function lt(lhs:Meters, rhs:Meters):Bool;
-	@:op(A<=B) extern public static function lte(lhs:Meters, rhs:Meters):Bool;
-	@:op(A==B) extern public static function eq(lhs:Meters, rhs:Meters):Bool;
+	@:op(-A) static private function neg(s:Meters):Meters;
+	@:op(A+B) static private function add(lhs:Meters, rhs:Meters):Meters;
+	@:op(A-B) static private function sub(lhs:Meters, rhs:Meters):Meters;
+	@:op(A>B) static private function gt(lhs:Meters, rhs:Meters):Bool;
+	@:op(A>=B) static private function gte(lhs:Meters, rhs:Meters):Bool;
+	@:op(A<B) static private function lt(lhs:Meters, rhs:Meters):Bool;
+	@:op(A<=B) static private function lte(lhs:Meters, rhs:Meters):Bool;
+	@:op(A==B) static private function eq(lhs:Meters, rhs:Meters):Bool;
 	extern inline public function float() return this;
 
 	@:to inline public function toString() {