Sfoglia il codice sorgente

add EIs, parse full ComplexType for the `is` operator, move `Std.isOfType` generation to the typer (see #2976) (#9689)

* add EIs, parse full ComplexType for the `is` operator, move `Std.isOfType` generation to the typer (see #2976)

* improve EIs typing, actually expect right hand to be a type (closes #9692)
Dan Korostelev 5 anni fa
parent
commit
ef4b00fcab

+ 10 - 1
src/core/ast.ml

@@ -219,6 +219,7 @@ and expr_def =
 	| EUntyped of expr
 	| EThrow of expr
 	| ECast of expr * type_hint option
+	| EIs of expr * type_hint
 	| EDisplay of expr * display_kind
 	| EDisplayNew of placed_type_path
 	| ETernary of expr * expr * expr
@@ -732,6 +733,10 @@ let map_expr loop (e,p) =
 		let e = loop e in
 		let t = opt type_hint t in
 		ECast (e,t)
+	| EIs (e,t) ->
+		let e = loop e in
+		let t = type_hint t in
+		EIs (e,t)
 	| EDisplay (e,f) -> EDisplay (loop e,f)
 	| EDisplayNew t -> EDisplayNew (tpath t)
 	| ETernary (e1,e2,e3) ->
@@ -753,7 +758,7 @@ let iter_expr loop (e,p) =
 	match e with
 	| EConst _ | EContinue | EBreak | EDisplayNew _ | EReturn None -> ()
 	| EParenthesis e1 | EField(e1,_) | EUnop(_,_,e1) | EReturn(Some e1) | EThrow e1 | EMeta(_,e1)
-	| ECheckType(e1,_) | EDisplay(e1,_) | ECast(e1,_) | EUntyped e1 -> loop e1;
+	| ECheckType(e1,_) | EDisplay(e1,_) | ECast(e1,_) | EIs(e1,_) | EUntyped e1 -> loop e1;
 	| EArray(e1,e2) | EBinop(_,e1,e2) | EFor(e1,e2) | EWhile(e1,e2,_) | EIf(e1,e2,None) -> loop e1; loop e2;
 	| ETernary(e1,e2,e3) | EIf(e1,e2,Some e3) -> loop e1; loop e2; loop e3;
 	| EArrayDecl el | ENew(_,el) | EBlock el -> List.iter loop el
@@ -822,6 +827,7 @@ module Printer = struct
 		| EThrow e -> "throw " ^ s_expr_inner tabs e
 		| ECast (e,Some (t,_)) -> "cast (" ^ s_expr_inner tabs e ^ ", " ^ s_complex_type tabs t ^ ")"
 		| ECast (e,None) -> "cast " ^ s_expr_inner tabs e
+		| EIs (e,(t,_)) -> s_expr_inner tabs e ^ " is " ^ s_complex_type tabs t
 		| ETernary (e1,e2,e3) -> s_expr_inner tabs e1 ^ " ? " ^ s_expr_inner tabs e2 ^ " : " ^ s_expr_inner tabs e3
 		| ECheckType (e,(t,_)) -> "(" ^ s_expr_inner tabs e ^ " : " ^ s_complex_type tabs t ^ ")"
 		| EMeta (m,e) -> s_metadata tabs m ^ " " ^ s_expr_inner tabs e
@@ -1118,6 +1124,9 @@ module Expr = struct
 			| ECast(e1,_) ->
 				add "ECast";
 				loop e1;
+			| EIs(e1,_) ->
+				add "EIs";
+				loop e1;
 			| EDisplay(e1,dk) ->
 				add ("EDisplay " ^ (s_display_kind dk));
 				loop e1

+ 1 - 1
src/macro/eval/evalDebugMisc.ml

@@ -359,7 +359,7 @@ let rec expr_to_value ctx env e =
 			let vc = loop2 ctx.toplevel ["Type";"createInstance"] in
 			safe_call env.env_eval (call_value vc) [v1;encode_array vl]
 		| ETry _ | ESwitch _ | EFunction _ | EFor _ | EDisplay _
-		| EDisplayNew _ | ECast(_,Some _) ->
+		| EDisplayNew _ | ECast(_,Some _) | EIs _ ->
 			raise Exit
 	in
 	loop e

+ 4 - 2
src/macro/macroApi.ml

@@ -502,6 +502,8 @@ and encode_expr e =
 				27, [loop e; encode_ctype t]
 			| EMeta (m,e) ->
 				28, [encode_meta_entry m;loop e]
+			| EIs (e,t) ->
+				29, [loop e;encode_ctype t]
 		in
 		encode_obj [
 			"pos", encode_pos p;
@@ -827,8 +829,8 @@ and decode_expr v =
 			ECheckType (loop e, (decode_ctype t))
 		| 28, [m;e] ->
 			EMeta (decode_meta_entry m,loop e)
-		| 29, [e;f] ->
-			EField (loop e, decode_string f) (*** deprecated EType, keep until haxe 3 **)
+		| 29, [e;t] ->
+			EIs (loop e,decode_ctype t)
 		| _ ->
 			raise Invalid_expr
 	in

+ 3 - 3
src/syntax/grammar.mly

@@ -1489,10 +1489,10 @@ and expr_next' e1 = parser
 		end
 	| [< '(Kwd In,_); e2 = expr >] ->
 		make_binop OpIn e1 e2
-	| [< '(Const (Ident "is"),p_is); tp = parse_type_path; s >] ->
+	| [< '(Const (Ident "is"),p_is); t = parse_complex_type; s >] ->
 		let p1 = pos e1 in
-		let p2 = pos tp in
-		let e_is = make_is e1 tp (punion p1 p2) p_is in
+		let p2 = pos t in
+		let e_is = EIs (e1,t), (punion p1 p2) in
 		expr_next e_is s
 	| [< >] -> e1
 

+ 0 - 5
src/syntax/parser.ml

@@ -307,11 +307,6 @@ let rec make_meta name params ((v,p2) as e) p1 =
 	| ETernary (e1,e2,e3) -> ETernary (make_meta name params e1 p1 , e2, e3), punion p1 p2
 	| _ -> EMeta((name,params,p1),e),punion p1 p2
 
-let make_is e (t,p_t) p p_is =
-	let e_is = EField((EConst(Ident "Std"),null_pos),"isOfType"),p_is in
-	let e2 = expr_of_type_path (t.tpackage,t.tname) p_t in
-	ECall(e_is,[e;e2]),p
-
 let handle_xml_literal p1 =
 	Lexer.reset();
 	let i = Lexer.lex_xml p1.pmin !code_ref in

+ 2 - 0
src/syntax/reification.ml

@@ -328,6 +328,8 @@ let reify in_macro =
 			expr "EThrow" [loop e]
 		| ECast (e,ct) ->
 			expr "ECast" [loop e; to_opt to_type_hint ct p]
+		| EIs (e,ct) ->
+			expr "EIs" [loop e; to_type_hint ct p]
 		| EDisplay (e,dk) ->
 			expr "EDisplay" [loop e; to_display_kind dk p]
 		| EDisplayNew t ->

+ 20 - 0
src/typing/typer.ml

@@ -1804,6 +1804,26 @@ and type_expr ?(mode=MGet) ctx (e,p) (with_type:WithType.t) =
 		if e.etype == t then e else mk (TCast (e,None)) t p
 	| 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
 
 (* ---------------------------------------------------------------------- *)
 (* TYPER INITIALIZATION *)

+ 5 - 0
std/haxe/macro/Expr.hx

@@ -559,6 +559,11 @@ enum ExprDef {
 		A `@m e` expression.
 	**/
 	EMeta(s:MetadataEntry, e:Expr);
+
+	/**
+		An `expr is Type` expression.
+	**/
+	EIs(e:Expr, t:ComplexType);
 }
 
 enum DisplayKind {

+ 2 - 1
std/haxe/macro/ExprTools.hx

@@ -71,7 +71,7 @@ class ExprTools {
 	static public function iter(e:Expr, f:Expr->Void):Void {
 		switch (e.expr) {
 			case EConst(_), EContinue, EBreak, EDisplayNew(_):
-			case EField(e, _), EParenthesis(e), EUntyped(e), EThrow(e), EDisplay(e, _), ECheckType(e, _), EUnop(_, _, e), ECast(e, _), EMeta(_, e):
+			case EField(e, _), EParenthesis(e), EUntyped(e), EThrow(e), EDisplay(e, _), ECheckType(e, _), EUnop(_, _, e), ECast(e, _), EIs(e, _) | EMeta(_, e):
 				f(e);
 			case EArray(e1, e2), EWhile(e1, e2, _), EBinop(_, e1, e2), EFor(e1, e2):
 				f(e1);
@@ -172,6 +172,7 @@ class ExprTools {
 				case EUntyped(e): EUntyped(f(e));
 				case EThrow(e): EThrow(f(e));
 				case ECast(e, t): ECast(f(e), t);
+				case EIs(e, t): EIs(f(e), t);
 				case EDisplay(e, dk): EDisplay(f(e), dk);
 				case ETernary(econd, eif, eelse): ETernary(f(econd), f(eif), f(eelse));
 				case ECheckType(e, t): ECheckType(f(e), t);

+ 4 - 0
std/haxe/macro/Printer.hx

@@ -277,6 +277,7 @@ class Printer {
 			case EThrow(e1): "throw " + printExpr(e1);
 			case ECast(e1, cto) if (cto != null): 'cast(${printExpr(e1)}, ${printComplexType(cto)})';
 			case ECast(e1, _): "cast " + printExpr(e1);
+			case EIs(e1, ct): '${printExpr(e1)} is ${printComplexType(ct)}';
 			case EDisplay(e1, _): '#DISPLAY(${printExpr(e1)})';
 			case EDisplayNew(tp): '#DISPLAY(${printTypePath(tp)})';
 			case ETernary(econd, eif, eelse): '${printExpr(econd)} ? ${printExpr(eif)} : ${printExpr(eelse)}';
@@ -534,6 +535,9 @@ class Printer {
 				case ECast(e, t):
 					add("ECast");
 					loopI(e);
+				case EIs(e, t):
+					add("EIs");
+					loopI(e);
 				case EDisplay(e, displayKind):
 					add("EDisplay");
 					loopI(e);