Переглянути джерело

Merge pull request #83486 from dalexeev/gds-fix-call-non-static-in-static-var-lambda

GDScript: Fix non-static call is allowed in static var lambda body
Rémi Verschelde 1 рік тому
батько
коміт
b075c61662

+ 27 - 15
modules/gdscript/gdscript_analyzer.cpp

@@ -1585,7 +1585,13 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
 	GDScriptParser::FunctionNode *previous_function = parser->current_function;
 	GDScriptParser::FunctionNode *previous_function = parser->current_function;
 	parser->current_function = p_function;
 	parser->current_function = p_function;
 	bool previous_static_context = static_context;
 	bool previous_static_context = static_context;
-	static_context = p_function->is_static;
+	if (p_is_lambda) {
+		// For lambdas this is determined from the context, the `static` keyword is not allowed.
+		p_function->is_static = static_context;
+	} else {
+		// For normal functions, this is determined in the parser by the `static` keyword.
+		static_context = p_function->is_static;
+	}
 
 
 	GDScriptParser::DataType prev_datatype = p_function->get_datatype();
 	GDScriptParser::DataType prev_datatype = p_function->get_datatype();
 
 
@@ -3317,15 +3323,16 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
 		}
 		}
 
 
 		if (is_self && static_context && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
 		if (is_self && static_context && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
-			if (parser->current_function) {
-				// Get the parent function above any lambda.
-				GDScriptParser::FunctionNode *parent_function = parser->current_function;
-				while (parent_function->source_lambda) {
-					parent_function = parent_function->source_lambda->parent_function;
-				}
+			// Get the parent function above any lambda.
+			GDScriptParser::FunctionNode *parent_function = parser->current_function;
+			while (parent_function && parent_function->source_lambda) {
+				parent_function = parent_function->source_lambda->parent_function;
+			}
+
+			if (parent_function) {
 				push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call);
 				push_error(vformat(R"*(Cannot call non-static function "%s()" from static function "%s()".)*", p_call->function_name, parent_function->identifier->name), p_call);
 			} else {
 			} else {
-				push_error(vformat(R"*(Cannot call non-static function "%s()" for static variable initializer.)*", p_call->function_name), p_call);
+				push_error(vformat(R"*(Cannot call non-static function "%s()" from a static variable initializer.)*", p_call->function_name), p_call);
 			}
 			}
 		} else if (!is_self && base_type.is_meta_type && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
 		} else if (!is_self && base_type.is_meta_type && !method_flags.has_flag(METHOD_FLAG_STATIC)) {
 			base_type.is_meta_type = false; // For `to_string()`.
 			base_type.is_meta_type = false; // For `to_string()`.
@@ -3908,15 +3915,16 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
 		bool source_is_variable = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
 		bool source_is_variable = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_VARIABLE || p_identifier->source == GDScriptParser::IdentifierNode::INHERITED_VARIABLE;
 		bool source_is_signal = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_SIGNAL;
 		bool source_is_signal = p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_SIGNAL;
 		if ((source_is_variable || source_is_signal) && static_context) {
 		if ((source_is_variable || source_is_signal) && static_context) {
-			if (parser->current_function) {
-				// Get the parent function above any lambda.
-				GDScriptParser::FunctionNode *parent_function = parser->current_function;
-				while (parent_function->source_lambda) {
-					parent_function = parent_function->source_lambda->parent_function;
-				}
+			// Get the parent function above any lambda.
+			GDScriptParser::FunctionNode *parent_function = parser->current_function;
+			while (parent_function && parent_function->source_lambda) {
+				parent_function = parent_function->source_lambda->parent_function;
+			}
+
+			if (parent_function) {
 				push_error(vformat(R"*(Cannot access %s "%s" from the static function "%s()".)*", source_is_signal ? "signal" : "instance variable", p_identifier->name, parent_function->identifier->name), p_identifier);
 				push_error(vformat(R"*(Cannot access %s "%s" from the static function "%s()".)*", source_is_signal ? "signal" : "instance variable", p_identifier->name, parent_function->identifier->name), p_identifier);
 			} else {
 			} else {
-				push_error(vformat(R"*(Cannot access %s "%s" for a static variable initializer.)*", source_is_signal ? "signal" : "instance variable", p_identifier->name), p_identifier);
+				push_error(vformat(R"*(Cannot access %s "%s" from a static variable initializer.)*", source_is_signal ? "signal" : "instance variable", p_identifier->name), p_identifier);
 			}
 			}
 		}
 		}
 
 
@@ -5459,12 +5467,15 @@ void GDScriptAnalyzer::resolve_pending_lambda_bodies() {
 	}
 	}
 
 
 	GDScriptParser::LambdaNode *previous_lambda = current_lambda;
 	GDScriptParser::LambdaNode *previous_lambda = current_lambda;
+	bool previous_static_context = static_context;
 
 
 	List<GDScriptParser::LambdaNode *> lambdas = pending_body_resolution_lambdas;
 	List<GDScriptParser::LambdaNode *> lambdas = pending_body_resolution_lambdas;
 	pending_body_resolution_lambdas.clear();
 	pending_body_resolution_lambdas.clear();
 
 
 	for (GDScriptParser::LambdaNode *lambda : lambdas) {
 	for (GDScriptParser::LambdaNode *lambda : lambdas) {
 		current_lambda = lambda;
 		current_lambda = lambda;
+		static_context = lambda->function->is_static;
+
 		resolve_function_body(lambda->function, true);
 		resolve_function_body(lambda->function, true);
 
 
 		int captures_amount = lambda->captures.size();
 		int captures_amount = lambda->captures.size();
@@ -5493,6 +5504,7 @@ void GDScriptAnalyzer::resolve_pending_lambda_bodies() {
 	}
 	}
 
 
 	current_lambda = previous_lambda;
 	current_lambda = previous_lambda;
+	static_context = previous_static_context;
 }
 }
 
 
 bool GDScriptAnalyzer::class_exists(const StringName &p_class) const {
 bool GDScriptAnalyzer::class_exists(const StringName &p_class) const {

+ 1 - 1
modules/gdscript/gdscript_parser.h

@@ -838,7 +838,7 @@ public:
 		HashMap<StringName, int> parameters_indices;
 		HashMap<StringName, int> parameters_indices;
 		TypeNode *return_type = nullptr;
 		TypeNode *return_type = nullptr;
 		SuiteNode *body = nullptr;
 		SuiteNode *body = nullptr;
-		bool is_static = false;
+		bool is_static = false; // For lambdas it's determined in the analyzer.
 		bool is_coroutine = false;
 		bool is_coroutine = false;
 		Variant rpc_config;
 		Variant rpc_config;
 		MethodInfo info;
 		MethodInfo info;

+ 14 - 0
modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda.gd

@@ -0,0 +1,14 @@
+# GH-83468
+
+func non_static_func():
+	pass
+
+static func static_func():
+	var f := func ():
+		var g := func ():
+			non_static_func()
+		g.call()
+	f.call()
+
+func test():
+	pass

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot call non-static function "non_static_func()" from static function "static_func()".

+ 15 - 0
modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda_param.gd

@@ -0,0 +1,15 @@
+# GH-83468
+
+func non_static_func():
+	pass
+
+static func static_func(
+		f := func ():
+			var g := func ():
+				non_static_func()
+			g.call()
+):
+	f.call()
+
+func test():
+	pass

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/static_func_call_non_static_in_lambda_param.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot call non-static function "non_static_func()" from static function "static_func()".

+ 14 - 0
modules/gdscript/tests/scripts/analyzer/errors/static_var_init_call_non_static_in_lambda.gd

@@ -0,0 +1,14 @@
+# GH-83468
+
+func non_static_func():
+	pass
+
+static var static_var = func ():
+	var f := func ():
+		var g := func ():
+			non_static_func()
+		g.call()
+	f.call()
+
+func test():
+	pass

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/static_var_init_call_non_static_in_lambda.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot call non-static function "non_static_func()" from a static variable initializer.

+ 15 - 0
modules/gdscript/tests/scripts/analyzer/errors/static_var_init_call_non_static_in_lambda_setter.gd

@@ -0,0 +1,15 @@
+# GH-83468
+
+func non_static_func():
+	pass
+
+static var static_var:
+	set(_value):
+		var f := func ():
+			var g := func ():
+				non_static_func()
+			g.call()
+		f.call()
+
+func test():
+	pass

+ 2 - 0
modules/gdscript/tests/scripts/analyzer/errors/static_var_init_call_non_static_in_lambda_setter.out

@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot call non-static function "non_static_func()" from static function "@static_var_setter()".

+ 1 - 1
modules/gdscript/tests/scripts/analyzer/errors/static_var_init_non_static_call.out

@@ -1,2 +1,2 @@
 GDTEST_ANALYZER_ERROR
 GDTEST_ANALYZER_ERROR
-Cannot call non-static function "non_static()" for static variable initializer.
+Cannot call non-static function "non_static()" from a static variable initializer.