@ -1455,7 +1455,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
bool compatible = true ;
GDScriptParser : : DataType op_type = p_assignment - > assigned_value - > get_datatype ( ) ;
if ( p_assignment - > operation ! = GDScriptParser : : AssignmentNode : : OP_NONE ) {
op_type = get_operation_type ( p_assignment - > variant_op , p_assignment - > assignee - > get_datatype ( ) , p_assignment - > assigned_value - > get_datatype ( ) , compatible );
op_type = get_operation_type ( p_assignment - > variant_op , p_assignment - > assignee - > get_datatype ( ) , p_assignment - > assigned_value - > get_datatype ( ) , compatible , p_assignment - > assigned_value );
}
if ( compatible ) {
@ -1618,7 +1618,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
ERR_PRINT ( " Parser bug: unknown binary operation. " ) ;
}
}
p_binary_op - > set_datatype ( type_from_variant ( p_binary_op - > reduced_value )) ;
p_binary_op - > set_datatype ( type_from_variant ( p_binary_op - > reduced_value , p_binary_op )) ;
return ;
}
@ -1632,7 +1632,7 @@ void GDScriptAnalyzer::reduce_binary_op(GDScriptParser::BinaryOpNode *p_binary_o
} else {
if ( p_binary_op - > variant_op < Variant : : OP_MAX ) {
bool valid = false ;
result = get_operation_type ( p_binary_op - > variant_op , p_binary_op - > left_operand - > get_datatype ( ) , right_type , valid );
result = get_operation_type ( p_binary_op - > variant_op , p_binary_op - > left_operand - > get_datatype ( ) , right_type , valid , p_binary_op );
if ( ! valid ) {
push_error ( vformat ( R " (Invalid operands " % s " and " % s " for " % s " operator.) " , p_binary_op - > left_operand - > get_datatype ( ) . to_string ( ) , right_type . to_string ( ) , Variant : : get_operator_name ( p_binary_op - > variant_op ) ) , p_binary_op ) ;
@ -2061,7 +2061,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
if ( valid ) {
p_identifier - > is_constant = true ;
p_identifier - > reduced_value = result ;
p_identifier - > set_datatype ( type_from_variant ( result )) ;
p_identifier - > set_datatype ( type_from_variant ( result , p_identifier )) ;
} else {
push_error ( vformat ( R " (Cannot find constant " % s " on type " % s " .) " , name , base . to_string ( ) ) , p_identifier ) ;
}
@ -2192,7 +2192,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
if ( valid ) {
p_identifier - > is_constant = true ;
p_identifier - > reduced_value = int_constant ;
p_identifier - > set_datatype ( type_from_variant ( int_constant )) ;
p_identifier - > set_datatype ( type_from_variant ( int_constant , p_identifier )) ;
return ;
}
}
@ -2292,7 +2292,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
if ( GDScriptLanguage : : get_singleton ( ) - > get_global_map ( ) . has ( name ) ) {
int idx = GDScriptLanguage : : get_singleton ( ) - > get_global_map ( ) [ name ] ;
Variant constant = GDScriptLanguage : : get_singleton ( ) - > get_global_array ( ) [ idx ] ;
p_identifier - > set_datatype ( type_from_variant ( constant )) ;
p_identifier - > set_datatype ( type_from_variant ( constant , p_identifier )) ;
p_identifier - > is_constant = true ;
p_identifier - > reduced_value = constant ;
return ;
@ -2300,7 +2300,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
if ( GDScriptLanguage : : get_singleton ( ) - > get_named_globals_map ( ) . has ( name ) ) {
Variant constant = GDScriptLanguage : : get_singleton ( ) - > get_named_globals_map ( ) [ name ] ;
p_identifier - > set_datatype ( type_from_variant ( constant )) ;
p_identifier - > set_datatype ( type_from_variant ( constant , p_identifier )) ;
p_identifier - > is_constant = true ;
p_identifier - > reduced_value = constant ;
return ;
@ -2322,7 +2322,7 @@ void GDScriptAnalyzer::reduce_literal(GDScriptParser::LiteralNode *p_literal) {
p_literal - > reduced_value = p_literal - > value ;
p_literal - > is_constant = true ;
p_literal - > set_datatype ( type_from_variant ( p_literal - > reduced_value )) ;
p_literal - > set_datatype ( type_from_variant ( p_literal - > reduced_value , p_literal )) ;
}
void GDScriptAnalyzer : : reduce_preload ( GDScriptParser : : PreloadNode * p_preload ) {
@ -2359,7 +2359,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
p_preload - > is_constant = true ;
p_preload - > reduced_value = p_preload - > resource ;
p_preload - > set_datatype ( type_from_variant ( p_preload - > reduced_value )) ;
p_preload - > set_datatype ( type_from_variant ( p_preload - > reduced_value , p_preload )) ;
}
void GDScriptAnalyzer : : reduce_self ( GDScriptParser : : SelfNode * p_self ) {
@ -2408,7 +2408,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
} else {
p_subscript - > is_constant = true ;
p_subscript - > reduced_value = value ;
result_type = type_from_variant ( value );
result_type = type_from_variant ( value , p_subscript );
}
result_type . kind = GDScriptParser : : DataType : : VARIANT ;
} else {
@ -2448,7 +2448,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
} else {
p_subscript - > is_constant = true ;
p_subscript - > reduced_value = value ;
result_type = type_from_variant ( value );
result_type = type_from_variant ( value , p_subscript );
}
result_type . kind = GDScriptParser : : DataType : : VARIANT ;
} else {
@ -2672,13 +2672,13 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
if ( p_unary_op - > operand - > is_constant ) {
p_unary_op - > is_constant = true ;
p_unary_op - > reduced_value = Variant : : evaluate ( p_unary_op - > variant_op , p_unary_op - > operand - > reduced_value , Variant ( ) ) ;
result = type_from_variant ( p_unary_op - > reduced_value );
result = type_from_variant ( p_unary_op - > reduced_value , p_unary_op );
} else if ( p_unary_op - > operand - > get_datatype ( ) . is_variant ( ) ) {
result . kind = GDScriptParser : : DataType : : VARIANT ;
mark_node_unsafe ( p_unary_op ) ;
} else {
bool valid = false ;
result = get_operation_type ( p_unary_op - > variant_op , p_unary_op - > operand - > get_datatype ( ) , p_unary_op - > operand - > get_datatype ( ) , valid );
result = get_operation_type ( p_unary_op - > variant_op , p_unary_op - > operand - > get_datatype ( ) , p_unary_op - > operand - > get_datatype ( ) , valid , p_unary_op );
if ( ! valid ) {
push_error ( vformat ( R " (Invalid operand of type " % s " for unary operator " % s " .) " , p_unary_op - > operand - > get_datatype ( ) . to_string ( ) , Variant : : get_operator_name ( p_unary_op - > variant_op ) ) , p_unary_op - > operand ) ;
@ -2688,7 +2688,7 @@ void GDScriptAnalyzer::reduce_unary_op(GDScriptParser::UnaryOpNode *p_unary_op)
p_unary_op - > set_datatype ( result ) ;
}
GDScriptParser : : DataType GDScriptAnalyzer : : type_from_variant ( const Variant & p_value ) {
GDScriptParser : : DataType GDScriptAnalyzer : : type_from_variant ( const Variant & p_value , const GDScriptParser : : Node * p_source ) {
GDScriptParser : : DataType result ;
result . is_constant = true ;
result . kind = GDScriptParser : : DataType : : BUILTIN ;
@ -2710,37 +2710,44 @@ GDScriptParser::DataType GDScriptAnalyzer::type_from_variant(const Variant &p_va
scr = obj - > get_script ( ) ;
}
if ( scr . is_valid ( ) ) {
result . script_type = scr ;
result . script_path = scr - > get_path ( ) ;
Ref < GDScript > gds = scr ;
if ( gds . is_valid ( ) ) {
result . kind = GDScriptParser : : DataType : : CLASS ;
// This might be an inner class, so we want to get the parser for the root.
// But still get the inner class from that tree.
GDScript * current = gds . ptr ( ) ;
List < StringName > class_chain ;
while ( current - > _owner ) {
// Push to front so it's in reverse.
class_chain . push_front ( current - > name ) ;
current = current - > _owner ;
}
if ( scr - > is_valid ( ) ) {
result . script_type = scr ;
result . script_path = scr - > get_path ( ) ;
Ref < GDScript > gds = scr ;
if ( gds . is_valid ( ) ) {
result . kind = GDScriptParser : : DataType : : CLASS ;
// This might be an inner class, so we want to get the parser for the root.
// But still get the inner class from that tree.
GDScript * current = gds . ptr ( ) ;
List < StringName > class_chain ;
while ( current - > _owner ) {
// Push to front so it's in reverse.
class_chain . push_front ( current - > name ) ;
current = current - > _owner ;
}
Ref < GDScriptParserRef > ref = get_parser_for ( current - > path ) ;
ref - > raise_status ( GDScriptParserRef : : INTERFACE_SOLVED ) ;
Ref < GDScriptParserRef > ref = get_parser_for ( current - > path ) ;
ref - > raise_status ( GDScriptParserRef : : INTERFACE_SOLVED ) ;
GDScriptParser : : ClassNode * found = ref - > get_parser ( ) - > head ;
GDScriptParser : : ClassNode * found = ref - > get_parser ( ) - > head ;
// It should be okay to assume this exists, since we have a complete script already.
for ( const List < StringName > : : Element * E = class_chain . front ( ) ; E ; E = E - > next ( ) ) {
found = found - > get_member ( E - > get ( ) ) . m_class ;
}
// It should be okay to assume this exists, since we have a complete script already.
for ( const List < StringName > : : Element * E = class_chain . front ( ) ; E ; E = E - > next ( ) ) {
found = found - > get_member ( E - > get ( ) ) . m_class ;
}
result . class_type = found ;
result . script_path = ref - > get_parser ( ) - > script_path ;
result . class_type = found ;
result . script_path = ref - > get_parser ( ) - > script_path ;
} else {
result . kind = GDScriptParser : : DataType : : SCRIPT ;
}
result . native_type = scr - > get_instance_base_type ( ) ;
} else {
result . kind = GDScriptParser : : DataType : : SCRIPT ;
push_error ( vformat ( R " (Constant value uses script from " % s " which is loaded but not compiled.) " , scr - > get_path ( ) ) , p_source ) ;
result . kind = GDScriptParser : : DataType : : VARIANT ;
result . type_source = GDScriptParser : : DataType : : UNDETECTED ;
result . is_meta_type = false ;
}
result . native_type = scr - > get_instance_base_type ( ) ;
} else {
result . kind = GDScriptParser : : DataType : : NATIVE ;
if ( result . native_type = = GDScriptNativeClass : : get_class_static ( ) ) {
@ -2996,7 +3003,7 @@ bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, con
}
# endif
GDScriptParser : : DataType GDScriptAnalyzer : : get_operation_type ( Variant : : Operator p_operation , const GDScriptParser : : DataType & p_a , const GDScriptParser : : DataType & p_b , bool & r_valid ) {
GDScriptParser : : DataType GDScriptAnalyzer : : get_operation_type ( Variant : : Operator p_operation , const GDScriptParser : : DataType & p_a , const GDScriptParser : : DataType & p_b , bool & r_valid , const GDScriptParser : : Node * p_source ) {
// This function creates dummy variant values and apply the operation to those. Less error-prone than keeping a table of valid operations.
GDScriptParser : : DataType result ;
@ -3069,7 +3076,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
Variant : : evaluate ( p_operation , a , b , ret , r_valid ) ;
if ( r_valid ) {
return type_from_variant ( ret );
return type_from_variant ( ret , p_source );
}
return result ;