Merge pull request #20468 from vnen/typed-gds-fixes

General GDScript fixes
This commit is contained in:
Rémi Verschelde 2018-07-26 13:48:37 +02:00 committed by GitHub
commit 96d37769d9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 110 additions and 50 deletions

View file

@ -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);
}

View file

@ -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 {

View file

@ -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) {

View file

@ -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);