diff options
author | Danil Alexeev <danil@alexeev.xyz> | 2024-05-22 10:07:31 +0300 |
---|---|---|
committer | Danil Alexeev <danil@alexeev.xyz> | 2024-05-22 10:07:31 +0300 |
commit | 4b692959de8a70edb0ccaef2289570e7fe7a8203 (patch) | |
tree | 7329c992d6bbaacabe2558adaf5e79546a1481bb | |
parent | 214968243c442c0fdcbdfef23943c1547aeafdbc (diff) | |
download | redot-engine-4b692959de8a70edb0ccaef2289570e7fe7a8203.tar.gz |
GDScript: Fix lambdas capturing non-local variables
3 files changed, 48 insertions, 4 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index a2680c932f..7fe96146da 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -4061,10 +4061,23 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident mark_lambda_use_self(); return; // No need to capture. } - // If the identifier is local, check if it's any kind of capture by comparing their source function. - // Only capture locals and enum values. Constants are still accessible from the lambda using the script reference. If not, this method is done. - if (p_identifier->source == GDScriptParser::IdentifierNode::UNDEFINED_SOURCE || p_identifier->source == GDScriptParser::IdentifierNode::MEMBER_CONSTANT) { - return; + + switch (p_identifier->source) { + case GDScriptParser::IdentifierNode::FUNCTION_PARAMETER: + case GDScriptParser::IdentifierNode::LOCAL_VARIABLE: + case GDScriptParser::IdentifierNode::LOCAL_ITERATOR: + case GDScriptParser::IdentifierNode::LOCAL_BIND: + break; // Need to capture. + case GDScriptParser::IdentifierNode::UNDEFINED_SOURCE: // A global. + case GDScriptParser::IdentifierNode::LOCAL_CONSTANT: + case GDScriptParser::IdentifierNode::MEMBER_VARIABLE: + case GDScriptParser::IdentifierNode::MEMBER_CONSTANT: + case GDScriptParser::IdentifierNode::MEMBER_FUNCTION: + case GDScriptParser::IdentifierNode::MEMBER_SIGNAL: + case GDScriptParser::IdentifierNode::MEMBER_CLASS: + case GDScriptParser::IdentifierNode::INHERITED_VARIABLE: + case GDScriptParser::IdentifierNode::STATIC_VARIABLE: + return; // No need to capture. } GDScriptParser::FunctionNode *function_test = current_lambda->function; diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_captures.gd b/modules/gdscript/tests/scripts/runtime/features/lambda_captures.gd new file mode 100644 index 0000000000..bbdf745540 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/lambda_captures.gd @@ -0,0 +1,26 @@ +# GH-92217 +# TODO: Add more tests. + +static var static_var: int: + set(value): + prints("set static_var", value) + get: + print("get static_var") + return 0 + +var member_var: int: + set(value): + prints("set member_var", value) + get: + print("get member_var") + return 0 + +func test(): + var lambda := func (): + var _tmp := static_var + _tmp = member_var + + static_var = 1 + member_var = 1 + + lambda.call() diff --git a/modules/gdscript/tests/scripts/runtime/features/lambda_captures.out b/modules/gdscript/tests/scripts/runtime/features/lambda_captures.out new file mode 100644 index 0000000000..0bdf74a43f --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/lambda_captures.out @@ -0,0 +1,5 @@ +GDTEST_OK +get static_var +get member_var +set static_var 1 +set member_var 1 |