1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-05 12:10:55 +00:00

Merge pull request #47569 from vnen/gdscript-typed-return

GDScript: Properly validate return type
This commit is contained in:
Rémi Verschelde
2021-04-05 15:16:43 +02:00
committed by GitHub
4 changed files with 304 additions and 6 deletions

View File

@@ -1286,8 +1286,85 @@ void GDScriptByteCodeGenerator::write_newline(int p_line) {
}
void GDScriptByteCodeGenerator::write_return(const Address &p_return_value) {
append(GDScriptFunction::OPCODE_RETURN, 1);
append(p_return_value);
if (!function->return_type.has_type || p_return_value.type.has_type) {
// Either the function is untyped or the return value is also typed.
// If this is a typed function, then we need to check for potential conversions.
if (function->return_type.has_type) {
if (function->return_type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
// Typed array.
const GDScriptDataType &element_type = function->return_type.get_container_element_type();
Variant script = function->return_type.script_type;
int script_idx = get_constant_pos(script);
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
append(p_return_value);
append(script_idx);
append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT);
append(element_type.native_type);
} else if (function->return_type.kind == GDScriptDataType::BUILTIN && p_return_value.type.kind == GDScriptDataType::BUILTIN && function->return_type.builtin_type != p_return_value.type.builtin_type) {
// Add conversion.
append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1);
append(p_return_value);
append(function->return_type.builtin_type);
} else {
// Just assign.
append(GDScriptFunction::OPCODE_RETURN, 1);
append(p_return_value);
}
} else {
append(GDScriptFunction::OPCODE_RETURN, 1);
append(p_return_value);
}
} else {
switch (function->return_type.kind) {
case GDScriptDataType::BUILTIN: {
if (function->return_type.builtin_type == Variant::ARRAY && function->return_type.has_container_element_type()) {
const GDScriptDataType &element_type = function->return_type.get_container_element_type();
Variant script = function->return_type.script_type;
int script_idx = get_constant_pos(script);
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_RETURN_TYPED_ARRAY, 2);
append(p_return_value);
append(script_idx);
append(element_type.kind == GDScriptDataType::BUILTIN ? element_type.builtin_type : Variant::OBJECT);
append(element_type.native_type);
} else {
append(GDScriptFunction::OPCODE_RETURN_TYPED_BUILTIN, 1);
append(p_return_value);
append(function->return_type.builtin_type);
}
} break;
case GDScriptDataType::NATIVE: {
append(GDScriptFunction::OPCODE_RETURN_TYPED_NATIVE, 2);
append(p_return_value);
int class_idx = GDScriptLanguage::get_singleton()->get_global_map()[function->return_type.native_type];
class_idx |= (GDScriptFunction::ADDR_TYPE_GLOBAL << GDScriptFunction::ADDR_BITS);
append(class_idx);
} break;
case GDScriptDataType::GDSCRIPT:
case GDScriptDataType::SCRIPT: {
Variant script = function->return_type.script_type;
int script_idx = get_constant_pos(script);
script_idx |= (GDScriptFunction::ADDR_TYPE_LOCAL_CONSTANT << GDScriptFunction::ADDR_BITS);
append(GDScriptFunction::OPCODE_RETURN_TYPED_SCRIPT, 2);
append(p_return_value);
append(script_idx);
} break;
default: {
ERR_PRINT("Compiler bug: unresolved return.");
// Shouldn't get here, but fail-safe to a regular return;
append(GDScriptFunction::OPCODE_RETURN, 1);
append(p_return_value);
} break;
}
}
}
void GDScriptByteCodeGenerator::write_assert(const Address &p_test, const Address &p_message) {