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

allow `@:callable` on abstracts (closes #3218)

Simon Krajewski 11 жил өмнө
parent
commit
8afb74939d

+ 1 - 0
ast.ml

@@ -41,6 +41,7 @@ module Meta = struct
 		| BridgeProperties
 		| Build
 		| BuildXml
+		| Callable
 		| Class
 		| ClassCode
 		| Commutative

+ 1 - 0
common.ml

@@ -347,6 +347,7 @@ module MetaInfo = struct
 		| BridgeProperties -> ":bridgeProperties",("Creates native property bridges for all Haxe properties in this class.",[UsedOn TClass;Platform Cs])
 		| Build -> ":build",("Builds a class or enum from a macro",[HasParam "Build macro call";UsedOnEither [TClass;TEnum]])
 		| BuildXml -> ":buildXml",("",[Platform Cpp])
+		| Callable -> ":callable",("Abstract forwards call to its underlying type",[UsedOn TAbstract])
 		| Class -> ":class",("Used internally to annotate an enum that will be generated as a class",[Platforms [Java;Cs]; UsedOn TEnum; Internal])
 		| ClassCode -> ":classCode",("Used to inject platform-native code into a class",[Platforms [Java;Cs]; UsedOn TClass])
 		| Commutative -> ":commutative",("Declares an abstract operator as commutative",[UsedOn TAbstractField])

+ 1 - 0
extra/CHANGES.txt

@@ -4,6 +4,7 @@
 
 	all : add --display mode for toplevel completion
 	all : add --display mode for position and usage information
+	all : allow @:callable on abstracts to forward calls to their underlying type
 	python : added python target
 	flash : flash player 12-14 support
 	js : add @:jsRequire and js.Lib.require

+ 1 - 0
std/haxe/Constraints.hx

@@ -28,6 +28,7 @@ package haxe;
 	It is intended to be used as a type parameter constraint. If used as a real
 	type, the underlying type will be `Dynamic`.
 **/
+@:callable
 abstract Function(Dynamic) { }
 
 /**

+ 14 - 0
tests/unit/issues/Issue3218.hx

@@ -0,0 +1,14 @@
+package unit.issues;
+
+@:callable
+private abstract A<T>(T) from T {}
+
+class Issue3218 extends Test {
+	function test() {
+		var a:A<Int->Int> = function(x) return x * 2;
+		eq(2, a(1));
+
+		var f:haxe.Constraints.Function = function(){ return 12; }
+        eq(12, f());
+	}
+}

+ 5 - 2
typer.ml

@@ -3807,7 +3807,7 @@ and build_call ctx acc el (with_type:with_type) p =
 		ignore(acc_get ctx acc p);
 		assert false
 	| AKExpr e ->
-		let el , t, e = (match follow e.etype with
+		let rec loop t = match follow t with
 		| TFun (args,r) ->
 			let fopts = (match acc with
 				| AKExpr {eexpr = TField(e, (FStatic (_,f) | FInstance(_,f) | FAnon(f)))} ->
@@ -3821,6 +3821,8 @@ and build_call ctx acc el (with_type:with_type) p =
 				| _ ->
 					let el, tfunc = unify_call_params ctx fopts el args r p false in
 					el,(match tfunc with TFun(_,r) -> r | _ -> assert false), {e with etype = tfunc})
+		| TAbstract(a,tl) when Meta.has Meta.Callable a.a_meta ->
+			loop (Codegen.Abstract.get_underlying_type a tl)
 		| TMono _ ->
 			let t = mk_mono() in
 			let el = List.map (fun e -> type_expr ctx e Value) el in
@@ -3834,7 +3836,8 @@ and build_call ctx acc el (with_type:with_type) p =
 				mk_mono()
 			else
 				error (s_type (print_context()) e.etype ^ " cannot be called") e.epos), e
-		) in
+		in
+		let el , t, e = loop e.etype in
 		mk (TCall (e,el)) t p
 
 (* ---------------------------------------------------------------------- *)