compiler: add Expression::is_untyped method
This method is not currently used by anything, but it will be used by later CLs in this series. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/536639
This commit is contained in:
parent
2621bd1bac
commit
ac50e9b72b
3 changed files with 277 additions and 1 deletions
|
@ -1,4 +1,4 @@
|
|||
081ec9824a74ec9d82628d8d2f6b9a7a4c35a529
|
||||
1c0a7c9338801d15afba7e39109554ed3406654e
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -201,6 +201,19 @@ Expression::report_error(const char* msg)
|
|||
this->set_is_error();
|
||||
}
|
||||
|
||||
// A convenience function for handling a type in do_is_untyped. If
|
||||
// TYPE is not abstract, return false. Otherwise set *PTYPE to TYPE
|
||||
// and return true.
|
||||
|
||||
bool
|
||||
Expression::is_untyped_type(Type* type, Type** ptype)
|
||||
{
|
||||
if (!type->is_abstract())
|
||||
return false;
|
||||
*ptype = type;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set types of variables and constants. This is implemented by the
|
||||
// child class.
|
||||
|
||||
|
@ -826,6 +839,10 @@ class Error_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const
|
||||
{ return false; }
|
||||
|
||||
bool
|
||||
do_numeric_constant_value(Numeric_constant* nc) const
|
||||
{
|
||||
|
@ -1965,6 +1982,9 @@ class Boolean_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_zero_value() const
|
||||
{ return this->val_ == false; }
|
||||
|
@ -2023,6 +2043,15 @@ Boolean_expression::do_traverse(Traverse* traverse)
|
|||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
bool
|
||||
Boolean_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->type_ != NULL)
|
||||
return Expression::is_untyped_type(this->type_, ptype);
|
||||
*ptype = Type::make_boolean_type();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the type.
|
||||
|
||||
Type*
|
||||
|
@ -2096,6 +2125,15 @@ String_expression::do_traverse(Traverse* traverse)
|
|||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
bool
|
||||
String_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->type_ != NULL)
|
||||
return Expression::is_untyped_type(this->type_, ptype);
|
||||
*ptype = Type::make_string_type();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Get the type.
|
||||
|
||||
Type*
|
||||
|
@ -2485,6 +2523,9 @@ class Integer_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_zero_value() const
|
||||
{ return mpz_sgn(this->val_) == 0; }
|
||||
|
@ -2568,6 +2609,18 @@ Integer_expression::do_numeric_constant_value(Numeric_constant* nc) const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
Integer_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->type_ != NULL)
|
||||
return Expression::is_untyped_type(this->type_, ptype);
|
||||
if (this->is_character_constant_)
|
||||
*ptype = Type::make_abstract_character_type();
|
||||
else
|
||||
*ptype = Type::make_abstract_integer_type();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the current type. If we haven't set the type yet, we return
|
||||
// an abstract integer type.
|
||||
|
||||
|
@ -2913,6 +2966,9 @@ class Float_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_zero_value() const
|
||||
{
|
||||
|
@ -2979,6 +3035,15 @@ Float_expression::do_traverse(Traverse* traverse)
|
|||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
bool
|
||||
Float_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->type_ != NULL)
|
||||
return Expression::is_untyped_type(this->type_, ptype);
|
||||
*ptype = Type::make_abstract_float_type();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the current type. If we haven't set the type yet, we return
|
||||
// an abstract float type.
|
||||
|
||||
|
@ -3135,6 +3200,9 @@ class Complex_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_zero_value() const
|
||||
{
|
||||
|
@ -3205,6 +3273,15 @@ Complex_expression::do_traverse(Traverse* traverse)
|
|||
return TRAVERSE_CONTINUE;
|
||||
}
|
||||
|
||||
bool
|
||||
Complex_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->type_ != NULL)
|
||||
return Expression::is_untyped_type(this->type_, ptype);
|
||||
*ptype = Type::make_abstract_complex_type();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return the current type. If we haven't set the type yet, we return
|
||||
// an abstract complex type.
|
||||
|
||||
|
@ -3458,6 +3535,21 @@ Const_expression::do_boolean_constant_value(bool* val) const
|
|||
return ok;
|
||||
}
|
||||
|
||||
// Whether this is untyped.
|
||||
|
||||
bool
|
||||
Const_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->type_ != NULL)
|
||||
return Expression::is_untyped_type(this->type_, ptype);
|
||||
|
||||
Named_constant* nc = this->constant_->const_value();
|
||||
if (nc->type() != NULL)
|
||||
return Expression::is_untyped_type(nc->type(), ptype);
|
||||
|
||||
return nc->expr()->is_untyped(ptype);
|
||||
}
|
||||
|
||||
// Return the type of the const reference.
|
||||
|
||||
Type*
|
||||
|
@ -3707,6 +3799,13 @@ class Nil_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_untyped_type(Type** ptype) const
|
||||
{
|
||||
*ptype = Type::make_nil_type();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_zero_value() const
|
||||
{ return true; }
|
||||
|
@ -4774,6 +4873,14 @@ Unary_expression::do_is_constant() const
|
|||
return this->expr_->is_constant();
|
||||
}
|
||||
|
||||
bool
|
||||
Unary_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->op_ == OPERATOR_MULT || this->op_ == OPERATOR_AND)
|
||||
return false;
|
||||
return this->expr_->is_untyped(ptype);
|
||||
}
|
||||
|
||||
// Return whether a unary expression can be used as a constant
|
||||
// initializer.
|
||||
|
||||
|
@ -5523,6 +5630,81 @@ Binary_expression::do_traverse(Traverse* traverse)
|
|||
return Expression::traverse(&this->right_, traverse);
|
||||
}
|
||||
|
||||
// Return whether a binary expression is untyped.
|
||||
|
||||
bool
|
||||
Binary_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->type_ != NULL)
|
||||
return Expression::is_untyped_type(this->type_, ptype);
|
||||
|
||||
switch (this->op_)
|
||||
{
|
||||
case OPERATOR_EQEQ:
|
||||
case OPERATOR_NOTEQ:
|
||||
case OPERATOR_LT:
|
||||
case OPERATOR_LE:
|
||||
case OPERATOR_GT:
|
||||
case OPERATOR_GE:
|
||||
// Comparisons are untyped by default.
|
||||
*ptype = Type::make_boolean_type();
|
||||
return true;
|
||||
|
||||
case OPERATOR_LSHIFT:
|
||||
case OPERATOR_RSHIFT:
|
||||
// A shift operation is untyped if the left hand expression is
|
||||
// untyped. The right hand expression is irrelevant.
|
||||
return this->left_->is_untyped(ptype);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Type* tleft;
|
||||
Type* tright;
|
||||
if (!this->left_->is_untyped(&tleft)
|
||||
|| !this->right_->is_untyped(&tright))
|
||||
return false;
|
||||
|
||||
// If both sides are numeric, pick a type based on the kind.
|
||||
enum kind { INT, RUNE, FLOAT, COMPLEX };
|
||||
enum kind kleft, kright;
|
||||
|
||||
if (tleft->integer_type() != NULL)
|
||||
kleft = tleft->integer_type()->is_rune() ? RUNE : INT;
|
||||
else if (tleft->float_type() != NULL)
|
||||
kleft = FLOAT;
|
||||
else if (tleft->complex_type() != NULL)
|
||||
kleft = COMPLEX;
|
||||
else
|
||||
{
|
||||
// Not numeric. If the types are different, we will report an
|
||||
// error later.
|
||||
*ptype = tleft;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (tright->integer_type() != NULL)
|
||||
kright = tright->integer_type()->is_rune() ? RUNE : INT;
|
||||
else if (tright->float_type() != NULL)
|
||||
kright = FLOAT;
|
||||
else if (tright->complex_type() != NULL)
|
||||
kright = COMPLEX;
|
||||
else
|
||||
{
|
||||
// Types are different. We will report an error later.
|
||||
*ptype = tleft;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (kleft > kright)
|
||||
*ptype = tleft;
|
||||
else
|
||||
*ptype = tright;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Return whether this expression may be used as a static initializer.
|
||||
|
||||
bool
|
||||
|
@ -7645,6 +7827,21 @@ String_concat_expression::do_is_constant() const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
String_concat_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
for (Expression_list::iterator pe = this->exprs_->begin();
|
||||
pe != this->exprs_->end();
|
||||
++pe)
|
||||
{
|
||||
if (!(*pe)->is_untyped(ptype))
|
||||
return false;
|
||||
}
|
||||
|
||||
*ptype = Type::make_string_type();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
String_concat_expression::do_is_zero_value() const
|
||||
{
|
||||
|
@ -9671,6 +9868,47 @@ Builtin_call_expression::do_is_constant() const
|
|||
return false;
|
||||
}
|
||||
|
||||
// Return whether a builtin call is untyped. Most builtin functions
|
||||
// have a known type, but complex, real, and imag can be untyped.
|
||||
|
||||
bool
|
||||
Builtin_call_expression::do_is_untyped(Type** ptype) const
|
||||
{
|
||||
if (this->is_error_expression())
|
||||
return false;
|
||||
|
||||
switch (this->code_)
|
||||
{
|
||||
default:
|
||||
return false;
|
||||
|
||||
case BUILTIN_COMPLEX:
|
||||
{
|
||||
const Expression_list* args = this->args();
|
||||
if (args == NULL || args->size() != 2)
|
||||
return false;
|
||||
Type* dummy;
|
||||
if (!args->front()->is_untyped(&dummy)
|
||||
|| !args->back()->is_untyped(&dummy))
|
||||
return false;
|
||||
*ptype = Type::make_abstract_complex_type();
|
||||
return true;
|
||||
}
|
||||
|
||||
case BUILTIN_REAL:
|
||||
case BUILTIN_IMAG:
|
||||
{
|
||||
Expression* arg = this->one_arg();
|
||||
if (arg == NULL)
|
||||
return false;
|
||||
if (!arg->is_untyped(ptype))
|
||||
return false;
|
||||
*ptype = Type::make_abstract_float_type();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return a numeric constant if possible.
|
||||
|
||||
bool
|
||||
|
|
|
@ -566,6 +566,15 @@ class Expression
|
|||
is_constant() const
|
||||
{ return this->do_is_constant(); }
|
||||
|
||||
// Return whether this expression is untyped. This isn't quite the
|
||||
// same as is_constant with an abstract type, as 1<<val is untyped
|
||||
// even if val is a variable. If this returns true, it sets *PTYPE
|
||||
// to an abstract type, which is the type the expression will have
|
||||
// if there is no context.
|
||||
bool
|
||||
is_untyped(Type** ptype) const
|
||||
{ return this->do_is_untyped(ptype); }
|
||||
|
||||
// Return whether this is the zero value of its type.
|
||||
bool
|
||||
is_zero_value() const
|
||||
|
@ -1169,6 +1178,11 @@ class Expression
|
|||
do_is_constant() const
|
||||
{ return false; }
|
||||
|
||||
// Return whether this expression is untyped.
|
||||
virtual bool
|
||||
do_is_untyped(Type**) const
|
||||
{ return false; }
|
||||
|
||||
// Return whether this is the zero value of its type.
|
||||
virtual bool
|
||||
do_is_zero_value() const
|
||||
|
@ -1274,6 +1288,12 @@ class Expression
|
|||
void
|
||||
report_error(const char*);
|
||||
|
||||
// A convenience function for handling a type in do_is_untyped. If
|
||||
// TYPE is not abstract, return false. Otherwise set *PTYPE to TYPE
|
||||
// and return true.
|
||||
static bool
|
||||
is_untyped_type(Type* type, Type** ptype);
|
||||
|
||||
// Write a name to export data.
|
||||
static void
|
||||
export_name(Export_function_body* efb, const Named_object*);
|
||||
|
@ -1501,6 +1521,9 @@ class Const_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_zero_value() const;
|
||||
|
||||
|
@ -1830,6 +1853,9 @@ class String_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_zero_value() const
|
||||
{ return this->val_ == ""; }
|
||||
|
@ -2136,6 +2162,9 @@ class Unary_expression : public Expression
|
|||
bool
|
||||
do_is_constant() const;
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_static_initializer() const;
|
||||
|
||||
|
@ -2293,6 +2322,9 @@ class Binary_expression : public Expression
|
|||
do_is_constant() const
|
||||
{ return this->left_->is_constant() && this->right_->is_constant(); }
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_static_initializer() const;
|
||||
|
||||
|
@ -2415,6 +2447,9 @@ class String_concat_expression : public Expression
|
|||
bool
|
||||
do_is_constant() const;
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_is_zero_value() const;
|
||||
|
||||
|
@ -2767,6 +2802,9 @@ class Builtin_call_expression : public Call_expression
|
|||
bool
|
||||
do_is_constant() const;
|
||||
|
||||
bool
|
||||
do_is_untyped(Type**) const;
|
||||
|
||||
bool
|
||||
do_numeric_constant_value(Numeric_constant*) const;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue