فهرست منبع

@:noClosure meta to prevent usage of methods as values (#8624)

* @:noClosure

* use it
Aleksandr Kuzmenko 6 سال پیش
والد
کامیت
92205bffff

+ 6 - 0
src-json/meta.json

@@ -718,6 +718,12 @@
 		"targets": ["TClassField"],
 		"targets": ["TClassField"],
 		"links": ["https://haxe.org/manual/cr-completion.html"]
 		"links": ["https://haxe.org/manual/cr-completion.html"]
 	},
 	},
+	{
+		"name": "NoClosure",
+		"metadata": ":noClosure",
+		"doc": "Prevents a method or all methods in a class from being used as a value.",
+		"targets": ["TClass", "TClassField"]
+	},
 	{
 	{
 		"name": "NoDebug",
 		"name": "NoDebug",
 		"metadata": ":noDebug",
 		"metadata": ":noDebug",

+ 22 - 0
src/typing/fields.ml

@@ -136,7 +136,29 @@ let check_constructor_access ctx c f p =
 	if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
 	if (Meta.has Meta.CompilerGenerated f.cf_meta) then display_error ctx (error_msg (No_constructor (TClassDecl c))) p;
 	if not (can_access ctx c f true || is_parent c ctx.curclass) && not ctx.untyped then display_error ctx (Printf.sprintf "Cannot access private constructor of %s" (s_class_path c)) p
 	if not (can_access ctx c f true || is_parent c ctx.curclass) && not ctx.untyped then display_error ctx (Printf.sprintf "Cannot access private constructor of %s" (s_class_path c)) p
 
 
+let check_no_closure_meta ctx fa mode p =
+	if mode <> MCall && not (DisplayPosition.display_position#enclosed_in p) then begin
+		let check_field f cl_meta =
+			match f.cf_kind with
+			| Method _ ->
+				if
+					Meta.has Meta.NoClosure cl_meta
+					|| Meta.has Meta.NoClosure f.cf_meta
+				then
+					error ("Method " ^ f.cf_name ^ " cannot be used as a value") p
+			| _ -> ()
+		in
+		match fa with
+		| FStatic (c, ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
+		| FInstance (c, _, ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
+		| FClosure (Some (c, _), ({ cf_kind = Method _} as f)) -> check_field f c.cl_meta
+		| FClosure (None, ({ cf_kind = Method _} as f)) -> check_field f []
+		| FAnon ({ cf_kind = Method _} as f) -> check_field f []
+		| _ -> ()
+	end
+
 let field_access ctx mode f fmode t e p =
 let field_access ctx mode f fmode t e p =
+	check_no_closure_meta ctx fmode mode p;
 	let bypass_accessor = if ctx.bypass_accessor > 0 then (ctx.bypass_accessor <- ctx.bypass_accessor - 1; true) else false in
 	let bypass_accessor = if ctx.bypass_accessor > 0 then (ctx.bypass_accessor <- ctx.bypass_accessor - 1; true) else false in
 	let fnormal() = AKExpr (mk (TField (e,fmode)) t p) in
 	let fnormal() = AKExpr (mk (TField (e,fmode)) t p) in
 	let normal() =
 	let normal() =

+ 1 - 0
std/js/Syntax.hx

@@ -28,6 +28,7 @@ import haxe.extern.Rest;
 	Generate JavaScript syntax not directly supported by Haxe.
 	Generate JavaScript syntax not directly supported by Haxe.
 	Use only at low-level when specific target-specific code-generation is required.
 	Use only at low-level when specific target-specific code-generation is required.
 **/
 **/
+@:noClosure
 extern class Syntax {
 extern class Syntax {
 	/**
 	/**
 		Inject `code` directly into generated source.
 		Inject `code` directly into generated source.

+ 1 - 0
std/php/Syntax.hx

@@ -30,6 +30,7 @@ import haxe.extern.EitherType;
 	Special extern class to support PHP language specifics.
 	Special extern class to support PHP language specifics.
 	Don't use these functions unless you are really sure what you are doing.
 	Don't use these functions unless you are really sure what you are doing.
 **/
 **/
+@:noClosure
 extern class Syntax {
 extern class Syntax {
 	/**
 	/**
 		Embeds plain php code.
 		Embeds plain php code.

+ 1 - 0
std/python/Syntax.hx

@@ -30,6 +30,7 @@ import haxe.macro.ExprTools;
 import haxe.extern.Rest;
 import haxe.extern.Rest;
 
 
 @:noPackageRestrict
 @:noPackageRestrict
+@:noClosure
 extern class Syntax {
 extern class Syntax {
 	#if macro
 	#if macro
 	static var self = macro python.Syntax;
 	static var self = macro python.Syntax;

+ 6 - 0
tests/misc/projects/Issue8618/Main.hx

@@ -0,0 +1,6 @@
+class Main {
+	static function main() {
+		trace(NoClosureClass.notMethod);
+		trace(NoClosureClass.staticMethod);
+	}
+}

+ 5 - 0
tests/misc/projects/Issue8618/Main2.hx

@@ -0,0 +1,5 @@
+class Main2 {
+	static function main() {
+		trace((null:NoClosureClass).instanceMethod);
+	}
+}

+ 5 - 0
tests/misc/projects/Issue8618/Main3.hx

@@ -0,0 +1,5 @@
+class Main3 {
+	static function main() {
+		trace(NormalClass.noClosureStaticMethod);
+	}
+}

+ 5 - 0
tests/misc/projects/Issue8618/Main4.hx

@@ -0,0 +1,5 @@
+class Main4 {
+	static function main() {
+		trace((null:NormalClass).noClosureInstanceMethod);
+	}
+}

+ 6 - 0
tests/misc/projects/Issue8618/NoClosureClass.hx

@@ -0,0 +1,6 @@
+@:noClosure
+class NoClosureClass {
+	static public var notMethod:Void->Void;
+	static public function staticMethod() {}
+	public function instanceMethod() {}
+}

+ 6 - 0
tests/misc/projects/Issue8618/NormalClass.hx

@@ -0,0 +1,6 @@
+class NormalClass {
+	@:noClosure
+	static public function noClosureStaticMethod() {}
+	@:noClosure
+	public function noClosureInstanceMethod() {}
+}

+ 1 - 0
tests/misc/projects/Issue8618/compile-fail.hxml

@@ -0,0 +1 @@
+-main Main

+ 2 - 0
tests/misc/projects/Issue8618/compile-fail.hxml.stderr

@@ -0,0 +1,2 @@
+Main.hx:4: characters 9-36 : Method staticMethod cannot be used as a value
+Main.hx:4: characters 9-36 : For function argument 'v'

+ 1 - 0
tests/misc/projects/Issue8618/compile2-fail.hxml

@@ -0,0 +1 @@
+-main Main2

+ 2 - 0
tests/misc/projects/Issue8618/compile2-fail.hxml.stderr

@@ -0,0 +1,2 @@
+Main2.hx:3: characters 9-45 : Method instanceMethod cannot be used as a value
+Main2.hx:3: characters 9-45 : For function argument 'v'

+ 1 - 0
tests/misc/projects/Issue8618/compile3-fail.hxml

@@ -0,0 +1 @@
+-main Main3

+ 2 - 0
tests/misc/projects/Issue8618/compile3-fail.hxml.stderr

@@ -0,0 +1,2 @@
+Main3.hx:3: characters 9-42 : Method noClosureStaticMethod cannot be used as a value
+Main3.hx:3: characters 9-42 : For function argument 'v'

+ 1 - 0
tests/misc/projects/Issue8618/compile4-fail.hxml

@@ -0,0 +1 @@
+-main Main4

+ 2 - 0
tests/misc/projects/Issue8618/compile4-fail.hxml.stderr

@@ -0,0 +1,2 @@
+Main4.hx:3: characters 9-51 : Method noClosureInstanceMethod cannot be used as a value
+Main4.hx:3: characters 9-51 : For function argument 'v'