Pārlūkot izejas kodu

support overloading `is` operator in abstracts

Dan Korostelev 4 gadi atpakaļ
vecāks
revīzija
a03eecc18e

+ 1 - 0
src/core/tFunctions.ml

@@ -203,6 +203,7 @@ let null_abstract = {
 	a_using = [];
 	a_ops = [];
 	a_unops = [];
+	a_is = None;
 	a_impl = None;
 	a_this = t_dynamic;
 	a_from = [];

+ 1 - 0
src/core/tPrinting.ml

@@ -579,6 +579,7 @@ module Printer = struct
 			"a_params",s_type_params a.a_params;
 			"a_ops",s_list ", " (fun (op,cf) -> Printf.sprintf "%s: %s" (s_binop op) cf.cf_name) a.a_ops;
 			"a_unops",s_list ", " (fun (op,flag,cf) -> Printf.sprintf "%s (%s): %s" (s_unop op) (if flag = Postfix then "postfix" else "prefix") cf.cf_name) a.a_unops;
+			"a_is",s_opt (fun (t,cf) -> Printf.sprintf "%s: %s" (s_type_kind t) cf.cf_name) a.a_is;
 			"a_impl",s_opt (fun c -> s_type_path c.cl_path) a.a_impl;
 			"a_this",s_type_kind a.a_this;
 			"a_from",s_list ", " s_type_kind a.a_from;

+ 1 - 0
src/core/tType.ml

@@ -302,6 +302,7 @@ and tabstract = {
 	(* do not insert any fields above *)
 	mutable a_ops : (Ast.binop * tclass_field) list;
 	mutable a_unops : (Ast.unop * unop_flag * tclass_field) list;
+	mutable a_is : (t * tclass_field) option; (* should this be a list to support overloads? *)
 	mutable a_impl : tclass option;
 	mutable a_this : t;
 	mutable a_from : t list;

+ 36 - 1
src/typing/operators.ml

@@ -920,4 +920,39 @@ let type_unop ctx op flag e with_type p =
 				find_overload_or_make e
 			end
 		| AKUsingField _ | AKResolve _ ->
-			error "Invalid operation" p
+			error "Invalid operation" p
+
+let type_is ctx e t p_t p =
+	match t with
+	| CTPath tp ->
+		if tp.tparams <> [] then display_error ctx "Type parameters are not supported for the `is` operator" p_t;
+
+		let e = type_expr ctx e WithType.value in
+
+		let t = Typeload.load_type_def ctx p_t tp in
+		begin
+			match t with
+			| TAbstractDecl { a_impl = Some c; a_is = Some (arg_t,cf) } ->
+				(* abstract with @:op(v is T) -> generate static call *)
+				let e_method = Texpr.Builder.make_static_field c cf (mk_zero_range_pos p) in
+				let e = AbstractCast.cast_or_unify ctx arg_t e p in
+				mk (TCall (e_method, [e])) ctx.com.basic.tbool p
+
+			| _ ->
+				(* everything else - generate Std.isOfType(v, T) *)
+				let e_t = type_module_type ctx t None p_t in
+				let e_Std_isOfType =
+					match Typeload.load_type_raise ctx ([],"Std") "Std" p with
+					| TClassDecl c ->
+						let cf =
+							try PMap.find "isOfType" c.cl_statics
+							with Not_found -> die "" __LOC__
+						in
+						Texpr.Builder.make_static_field c cf (mk_zero_range_pos p)
+					| _ -> die "" __LOC__
+				in
+				mk (TCall (e_Std_isOfType, [e; e_t])) ctx.com.basic.tbool p
+		end
+	| _ ->
+		display_error ctx "Unsupported type for `is` operator" p_t;
+		Texpr.Builder.make_bool ctx.com.basic false p

+ 14 - 0
src/typing/typeloadFields.ml

@@ -1070,6 +1070,20 @@ let check_abstract (ctx,cctx,fctx) c cf fd t ret p =
 					error (cf.cf_name ^ ": Assignment overloading is not supported") p;
 				| (Meta.Op,[ETernary(_,_,_),_],_) :: _ ->
 					error (cf.cf_name ^ ": Ternary overloading is not supported") p;
+				| (Meta.Op,[EIs(_,_),_],_) :: _ ->
+					if a.a_is <> None then error "Multiple `is` overloads are not supported" cf.cf_pos;
+					if fctx.is_abstract_member then error "`is` overloads must be static" cf.cf_pos;
+					begin match follow t with
+						| TFun ([(_,false,t)], tr) ->
+							delay ctx PCheckConstraint (fun () ->
+								match follow tr with
+								| TAbstract ({ a_path = [],"Bool" },_) -> ()
+								| _ -> error "`is` overloads must return Bool" cf.cf_pos
+							);
+							a.a_is <- Some (t,cf);
+						| _ ->
+							error ("`is` overloads must be a function that takes a single non-optional argument and returns Bool") cf.cf_pos
+					end
 				| (Meta.Op,[EBinop(op,_,_),_],_) :: _ ->
 					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

+ 1 - 0
src/typing/typeloadModule.ml

@@ -325,6 +325,7 @@ let module_pass_1 ctx m tdecls loadp =
 				a_to_field = [];
 				a_ops = [];
 				a_unops = [];
+				a_is = None;
 				a_impl = None;
 				a_array = [];
 				a_this = mk_mono();

+ 1 - 19
src/typing/typer.ml

@@ -1800,25 +1800,7 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 	| EMeta (m,e1) ->
 		type_meta ~mode ctx m e1 with_type p
 	| EIs (e,(t,p_t)) ->
-		match t with
-		| CTPath tp ->
-			if tp.tparams <> [] then display_error ctx "Type parameters are not supported for the `is` operator" p_t;
-			let e = type_expr ctx e WithType.value in
-			let e_t = type_type ctx (tp.tpackage,tp.tname) p_t in
-			let e_Std_isOfType =
-				match Typeload.load_type_raise ctx ([],"Std") "Std" p with
-				| TClassDecl c ->
-					let cf =
-						try PMap.find "isOfType" c.cl_statics
-						with Not_found -> die "" __LOC__
-					in
-					Texpr.Builder.make_static_field c cf (mk_zero_range_pos p)
-				| _ -> die "" __LOC__
-			in
-			mk (TCall (e_Std_isOfType, [e; e_t])) ctx.com.basic.tbool p
-		| _ ->
-			display_error ctx "Unsupported type for `is` operator" p_t;
-			Texpr.Builder.make_bool ctx.com.basic false p
+		type_is ctx e t p_t p
 
 (* ---------------------------------------------------------------------- *)
 (* TYPER INITIALIZATION *)