Merge pull request #20468 from vnen/typed-gds-fixes
General GDScript fixes
This commit is contained in:
commit
96d37769d9
4 changed files with 110 additions and 50 deletions
|
@ -140,7 +140,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
|
|||
} break;
|
||||
case GDScriptParser::DataType::CLASS: {
|
||||
result.kind = GDScriptDataType::GDSCRIPT;
|
||||
if (p_datatype.class_type->name == StringName()) {
|
||||
if (!p_datatype.class_type->owner) {
|
||||
result.script_type = Ref<GDScript>(main_script);
|
||||
} else {
|
||||
result.script_type = class_map[p_datatype.class_type->name];
|
||||
|
@ -482,7 +482,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
|||
|
||||
Variant script;
|
||||
int idx = -1;
|
||||
if (cn->cast_type.class_type->name == StringName()) {
|
||||
if (!cn->cast_type.class_type->owner) {
|
||||
script = codegen.script;
|
||||
} else {
|
||||
StringName name = cn->cast_type.class_type->name;
|
||||
|
@ -1181,7 +1181,7 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser::
|
|||
|
||||
Variant script;
|
||||
int idx = -1;
|
||||
if (assign_type.class_type->name == StringName()) {
|
||||
if (!assign_type.class_type->owner) {
|
||||
script = codegen.script;
|
||||
} else {
|
||||
StringName name = assign_type.class_type->name;
|
||||
|
@ -1994,7 +1994,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, GDScript *p_owner
|
|||
p_script->_signals[name] = p_class->_signals[i].arguments;
|
||||
}
|
||||
|
||||
if (p_class->name != StringName()) {
|
||||
if (!p_class->owner) {
|
||||
parsed_classes.insert(p_class->name);
|
||||
}
|
||||
|
||||
|
|
|
@ -742,13 +742,22 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
|
||||
GD_ERR_BREAK(var_type < 0 || var_type >= Variant::VARIANT_MAX);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
if (src->get_type() != var_type) {
|
||||
err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
|
||||
"' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
|
||||
OPCODE_BREAK;
|
||||
if (Variant::can_convert_strict(src->get_type(), var_type)) {
|
||||
Variant::CallError ce;
|
||||
*dst = Variant::construct(var_type, const_cast<const Variant **>(&src), 1, ce);
|
||||
} else {
|
||||
err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
|
||||
"' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
} else {
|
||||
#endif // DEBUG_ENABLED
|
||||
*dst = *src;
|
||||
#ifdef DEBUG_ENABLED
|
||||
}
|
||||
|
||||
*dst = *src;
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
ip += 4;
|
||||
}
|
||||
|
@ -761,17 +770,22 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
GET_VARIANT_PTR(dst, 2);
|
||||
GET_VARIANT_PTR(src, 3);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
GDScriptNativeClass *nc = Object::cast_to<GDScriptNativeClass>(type->operator Object *());
|
||||
GD_ERR_BREAK(!nc);
|
||||
if (!src->get_type() != Variant::OBJECT && !src->get_type() != Variant::NIL) {
|
||||
err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
|
||||
"' to a variable of type '" + nc->get_name() + "'.";
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
Object *src_obj = src->operator Object *();
|
||||
GD_ERR_BREAK(!src_obj);
|
||||
|
||||
if (!ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
|
||||
if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
|
||||
err_text = "Trying to assign value of type '" + src_obj->get_class_name() +
|
||||
"' to a variable of type '" + nc->get_name() + "'.";
|
||||
OPCODE_BREAK;
|
||||
}
|
||||
|
||||
#endif // DEBUG_ENABLED
|
||||
*dst = *src;
|
||||
|
||||
ip += 4;
|
||||
|
@ -785,6 +799,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
GET_VARIANT_PTR(dst, 2);
|
||||
GET_VARIANT_PTR(src, 3);
|
||||
|
||||
#ifdef DEBUG_ENABLED
|
||||
Script *base_type = Object::cast_to<Script>(type->operator Object *());
|
||||
|
||||
GD_ERR_BREAK(!base_type);
|
||||
|
@ -820,6 +835,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
|
|||
OPCODE_BREAK;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
|
||||
*dst = *src;
|
||||
|
||||
|
@ -1579,7 +1595,7 @@ StringName GDScriptFunction::get_global_name(int p_idx) const {
|
|||
|
||||
int GDScriptFunction::get_default_argument_count() const {
|
||||
|
||||
return default_arguments.size();
|
||||
return _default_arg_count;
|
||||
}
|
||||
int GDScriptFunction::get_default_argument_addr(int p_idx) const {
|
||||
|
||||
|
|
|
@ -1412,7 +1412,7 @@ bool GDScriptFunctions::is_deterministic(Function p_func) {
|
|||
|
||||
MethodInfo GDScriptFunctions::get_info(Function p_func) {
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
#ifdef DEBUG_ENABLED
|
||||
//using a switch, so the compiler generates a jumptable
|
||||
|
||||
switch (p_func) {
|
||||
|
|
|
@ -3332,6 +3332,9 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
|||
|
||||
switch (token) {
|
||||
|
||||
case GDScriptTokenizer::TK_CURSOR: {
|
||||
tokenizer->advance();
|
||||
} break;
|
||||
case GDScriptTokenizer::TK_EOF:
|
||||
p_class->end_line = tokenizer->get_token_line();
|
||||
case GDScriptTokenizer::TK_ERROR: {
|
||||
|
@ -3552,7 +3555,10 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
|||
|
||||
DataType argtype;
|
||||
if (tokenizer->get_token() == GDScriptTokenizer::TK_COLON) {
|
||||
if (!_parse_type(argtype)) {
|
||||
if (tokenizer->get_token(1) == GDScriptTokenizer::TK_OP_ASSIGN) {
|
||||
argtype.infer_type = true;
|
||||
tokenizer->advance();
|
||||
} else if (!_parse_type(argtype)) {
|
||||
_set_error("Expected type for argument.");
|
||||
return;
|
||||
}
|
||||
|
@ -4187,6 +4193,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
|||
current_export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
|
||||
|
||||
current_export.hint_string = native_class->get_name();
|
||||
current_export.class_name = native_class->get_name();
|
||||
|
||||
} else {
|
||||
current_export = PropertyInfo();
|
||||
|
@ -4546,6 +4553,7 @@ void GDScriptParser::_parse_class(ClassNode *p_class) {
|
|||
member._export.type = Variant::OBJECT;
|
||||
member._export.hint = PROPERTY_HINT_RESOURCE_TYPE;
|
||||
member._export.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
|
||||
member._export.hint_string = member.data_type.native_type;
|
||||
member._export.class_name = member.data_type.native_type;
|
||||
} else {
|
||||
_set_error("Invalid export type. Only built-in and native resource types can be exported.", member.line);
|
||||
|
@ -5433,6 +5441,9 @@ GDScriptParser::DataType GDScriptParser::_get_operation_type(const Variant::Oper
|
|||
if (b_type == Variant::INT || b_type == Variant::REAL) {
|
||||
Variant::evaluate(Variant::OP_ADD, b, 1, b, r_valid);
|
||||
}
|
||||
if (a_type == Variant::STRING) {
|
||||
a = "%s"; // Work around for formatting operator (%)
|
||||
}
|
||||
|
||||
Variant ret;
|
||||
Variant::evaluate(p_op, a, b, ret, r_valid);
|
||||
|
@ -6770,7 +6781,26 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
|
|||
// Check classes in current file
|
||||
ClassNode *base = NULL;
|
||||
if (!p_base_type) {
|
||||
// Possibly this is a global, check first
|
||||
base = current_class;
|
||||
base_type.has_type = true;
|
||||
base_type.is_constant = true;
|
||||
base_type.kind = DataType::CLASS;
|
||||
base_type.class_type = base;
|
||||
} else {
|
||||
base_type = DataType(*p_base_type);
|
||||
if (base_type.kind == DataType::CLASS) {
|
||||
base = base_type.class_type;
|
||||
}
|
||||
}
|
||||
|
||||
DataType member_type;
|
||||
|
||||
if (_get_member_type(base_type, p_identifier, member_type)) {
|
||||
return member_type;
|
||||
}
|
||||
|
||||
if (!p_base_type) {
|
||||
// Possibly this is a global, check before failing
|
||||
|
||||
if (ClassDB::class_exists(p_identifier) || ClassDB::class_exists("_" + p_identifier.operator String())) {
|
||||
DataType result;
|
||||
|
@ -6796,6 +6826,9 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
|
|||
result.class_type = outer_class;
|
||||
return result;
|
||||
}
|
||||
if (outer_class->constant_expressions.has(p_identifier)) {
|
||||
return outer_class->constant_expressions[p_identifier].type;
|
||||
}
|
||||
for (int i = 0; i < outer_class->subclasses.size(); i++) {
|
||||
if (outer_class->subclasses[i] == current_class) {
|
||||
continue;
|
||||
|
@ -6885,27 +6918,6 @@ GDScriptParser::DataType GDScriptParser::_reduce_identifier_type(const DataType
|
|||
}
|
||||
}
|
||||
|
||||
// Nothing found, keep looking in local scope
|
||||
|
||||
base = current_class;
|
||||
base_type.has_type = true;
|
||||
base_type.is_constant = true;
|
||||
base_type.kind = DataType::CLASS;
|
||||
base_type.class_type = base;
|
||||
} else {
|
||||
base_type = *p_base_type;
|
||||
if (base_type.kind == DataType::CLASS) {
|
||||
base = base_type.class_type;
|
||||
}
|
||||
}
|
||||
|
||||
DataType member_type;
|
||||
|
||||
if (_get_member_type(base_type, p_identifier, member_type)) {
|
||||
return member_type;
|
||||
}
|
||||
|
||||
if (!p_base_type) {
|
||||
// This means looking in the current class, which type is always known
|
||||
_set_error("Identifier '" + p_identifier.operator String() + "' is not declared in the current scope.", p_line);
|
||||
}
|
||||
|
@ -7131,11 +7143,9 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
|
|||
// Arguments
|
||||
int defaults_ofs = p_function->arguments.size() - p_function->default_values.size();
|
||||
for (int i = 0; i < p_function->arguments.size(); i++) {
|
||||
|
||||
// Resolve types
|
||||
p_function->argument_types.write[i] = _resolve_type(p_function->argument_types[i], p_function->line);
|
||||
|
||||
if (i >= defaults_ofs) {
|
||||
if (i < defaults_ofs) {
|
||||
p_function->argument_types.write[i] = _resolve_type(p_function->argument_types[i], p_function->line);
|
||||
} else {
|
||||
if (p_function->default_values[i - defaults_ofs]->type != Node::TYPE_OPERATOR) {
|
||||
_set_error("Parser bug: invalid argument default value.", p_function->line, p_function->column);
|
||||
return;
|
||||
|
@ -7150,17 +7160,25 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
|
|||
|
||||
DataType def_type = _reduce_node_type(op->arguments[1]);
|
||||
|
||||
if (!_is_type_compatible(p_function->argument_types[i], def_type, true)) {
|
||||
String arg_name = p_function->arguments[i];
|
||||
_set_error("Value type (" + def_type.to_string() + ") doesn't match the type of argument '" +
|
||||
arg_name + "' (" + p_function->arguments[i] + ")",
|
||||
p_function->line);
|
||||
if (p_function->argument_types[i].infer_type) {
|
||||
def_type.is_constant = false;
|
||||
p_function->argument_types.write[i] = def_type;
|
||||
} else {
|
||||
p_function->return_type = _resolve_type(p_function->return_type, p_function->line);
|
||||
|
||||
if (!_is_type_compatible(p_function->argument_types[i], def_type, true)) {
|
||||
String arg_name = p_function->arguments[i];
|
||||
_set_error("Value type (" + def_type.to_string() + ") doesn't match the type of argument '" +
|
||||
arg_name + "' (" + p_function->arguments[i] + ")",
|
||||
p_function->line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(p_function->name == "_init")) {
|
||||
// Signature for the initializer may vary
|
||||
#ifdef DEBUG_ENABLED
|
||||
DataType return_type;
|
||||
List<DataType> arg_types;
|
||||
int default_arg_count = 0;
|
||||
|
@ -7171,18 +7189,44 @@ void GDScriptParser::_check_function_types(FunctionNode *p_function) {
|
|||
if (_get_function_signature(base_type, p_function->name, return_type, arg_types, default_arg_count, _static, vararg)) {
|
||||
bool valid = _static == p_function->_static;
|
||||
valid = valid && return_type == p_function->return_type;
|
||||
valid = valid && p_function->default_values.size() >= default_arg_count;
|
||||
valid = valid && arg_types.size() == p_function->arguments.size();
|
||||
int argsize_diff = p_function->arguments.size() - arg_types.size();
|
||||
valid = valid && argsize_diff >= 0;
|
||||
valid = valid && p_function->default_values.size() >= default_arg_count + argsize_diff;
|
||||
int i = 0;
|
||||
for (List<DataType>::Element *E = arg_types.front(); valid && E; E = E->next()) {
|
||||
valid = valid && E->get() == p_function->argument_types[i++];
|
||||
}
|
||||
|
||||
if (!valid) {
|
||||
_set_error("Function signature doesn't match the parent.", p_function->line);
|
||||
String parent_signature = return_type.has_type ? return_type.to_string() : "Variant";
|
||||
if (parent_signature == "null") {
|
||||
parent_signature = "void";
|
||||
}
|
||||
parent_signature += " " + p_function->name + "(";
|
||||
if (arg_types.size()) {
|
||||
int i = 0;
|
||||
for (List<DataType>::Element *E = arg_types.front(); E; E = E->next()) {
|
||||
if (E != arg_types.front()) {
|
||||
parent_signature += ", ";
|
||||
}
|
||||
String arg = E->get().to_string();
|
||||
if (arg == "null" || arg == "var") {
|
||||
arg = "Variant";
|
||||
}
|
||||
parent_signature += arg;
|
||||
if (i == arg_types.size() - default_arg_count) {
|
||||
parent_signature += "=default";
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
parent_signature += ")";
|
||||
_set_error("Function signature doesn't match the parent. Parent signature is: '" + parent_signature + "'.", p_function->line);
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif // DEBUG_ENABLED
|
||||
} else {
|
||||
if (p_function->return_type.has_type && (p_function->return_type.kind != DataType::BUILTIN || p_function->return_type.builtin_type != Variant::NIL)) {
|
||||
_set_error("Constructor cannot return a value.", p_function->line);
|
||||
|
|
Loading…
Reference in a new issue