Browse Source

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

* @:noClosure

* use it
Aleksandr Kuzmenko 6 years ago
parent
commit
92205bffff

+ 6 - 0
src-json/meta.json

@@ -718,6 +718,12 @@
 		"targets": ["TClassField"],
 		"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",
 		"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 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 =
+	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 fnormal() = AKExpr (mk (TField (e,fmode)) t p) in
 	let normal() =

+ 1 - 0
std/js/Syntax.hx

@@ -28,6 +28,7 @@ import haxe.extern.Rest;
 	Generate JavaScript syntax not directly supported by Haxe.
 	Use only at low-level when specific target-specific code-generation is required.
 **/
+@:noClosure
 extern class Syntax {
 	/**
 		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.
 	Don't use these functions unless you are really sure what you are doing.
 **/
+@:noClosure
 extern class Syntax {
 	/**
 		Embeds plain php code.

+ 1 - 0
std/python/Syntax.hx

@@ -30,6 +30,7 @@ import haxe.macro.ExprTools;
 import haxe.extern.Rest;
 
 @:noPackageRestrict
+@:noClosure
 extern class Syntax {
 	#if macro
 	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'