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:
Ian Lance Taylor 2023-10-19 17:20:40 -07:00
parent 2621bd1bac
commit ac50e9b72b
3 changed files with 277 additions and 1 deletions

View file

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

View file

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

View file

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