Skip to content

Commit 61b29a9

Browse files
compiler: move lowering pass after check types pass
This change moves the lowering pass after the type determination and the type checking passes. This lets us simplify some of the code that determines the type of an expression, which previously had to work correctly both before and after type determination. I'm doing this to help with future generic support. For example, with generics, we can see code like func ident[T any](v T) T { return v } func F() int32 { s := int32(1) return ident(s) } Before this change, we would type check return statements in the lowering pass (see Return_statement::do_lower). With a generic example like the above, that means we have to determine the type of s, and use that to infer the type arguments passed to ident, and use that to determine the result type of ident. That is too much to do at lowering time. Of course we can change the way that return statements work, but similar issues arise with index expressions, the types of closures for function literals, and probably other cases as well. Rather than try to deal with all those cases, we move the lowering pass after type checking. This requires a bunch of changes, notably for determining constant types. We have to add type checking for various constructs that formerly disappeared in the lowering pass. So it's a lot of shuffling. Sorry for the size of the patch. Change-Id: Ic269e816f324c87feb708ca4cde0eff7f2f70c7b Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/536643 Reviewed-by: Ian Lance Taylor <[email protected]> Reviewed-by: Than McIntosh <[email protected]>
1 parent f5d708f commit 61b29a9

12 files changed

+4080
-1641
lines changed

Diff for: go/expressions.cc

+2,627-1,145
Large diffs are not rendered by default.

Diff for: go/expressions.h

+183-53
Large diffs are not rendered by default.

Diff for: go/go.cc

+12-9
Original file line numberDiff line numberDiff line change
@@ -118,36 +118,39 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
118118
::gogo->add_linkname(p->first, p->second.is_exported, p->second.ext_name,
119119
p->second.loc);
120120

121+
// Lower calls to builtin functions.
122+
::gogo->lower_builtin_calls();
123+
121124
// Finalize method lists and build stub methods for named types.
122125
::gogo->finalize_methods();
123126

124127
// Check that functions have a terminating statement.
125128
::gogo->check_return_statements();
126129

127-
// Now that we have seen all the names, lower the parse tree into a
128-
// form which is easier to use.
129-
::gogo->lower_parse_tree();
130-
131130
// At this point we have handled all inline functions, so we no
132131
// longer need the linemap.
133132
::gogo->linemap()->stop();
134133

135-
// Create function descriptors as needed.
136-
::gogo->create_function_descriptors();
134+
// Work out types of unspecified constants and variables.
135+
::gogo->determine_types();
137136

138137
// Now that we have seen all the names, verify that types are
139138
// correct.
140139
::gogo->verify_types();
141140

142-
// Work out types of unspecified constants and variables.
143-
::gogo->determine_types();
144-
145141
// Check types and issue errors as appropriate.
146142
::gogo->check_types();
147143

144+
// Now that we have seen all the names and we know all the types,
145+
// lower the parse tree into a form which is easier to use.
146+
::gogo->lower_parse_tree();
147+
148148
if (only_check_syntax)
149149
return;
150150

151+
// Create function descriptors as needed.
152+
::gogo->create_function_descriptors();
153+
151154
// Record global variable initializer dependencies.
152155
::gogo->record_global_init_refs();
153156

Diff for: go/gogo.cc

+155-54
Original file line numberDiff line numberDiff line change
@@ -2998,10 +2998,7 @@ Lower_parse_tree::constant(Named_object* no, bool)
29982998
return TRAVERSE_CONTINUE;
29992999
nc->set_lowering();
30003000

3001-
go_assert(this->iota_value_ == -1);
3002-
this->iota_value_ = nc->iota_value();
30033001
nc->traverse_expression(this);
3004-
this->iota_value_ = -1;
30053002

30063003
nc->clear_lowering();
30073004

@@ -3018,8 +3015,6 @@ Lower_parse_tree::constant(Named_object* no, bool)
30183015
int
30193016
Lower_parse_tree::function(Named_object* no)
30203017
{
3021-
no->func_value()->set_closure_type();
3022-
30233018
go_assert(this->function_ == NULL);
30243019
this->function_ = no;
30253020
int t = no->func_value()->traverse(this);
@@ -3482,6 +3477,43 @@ Gogo::create_function_descriptors()
34823477
this->traverse(&cfd);
34833478
}
34843479

3480+
// Lower calls to builtin functions. We need to do this early because
3481+
// some builtin calls are constant expressions. In particular we need
3482+
// to do this before finalize_methods, because finalize_methods calls
3483+
// is_direct_iface_type, which needs to know whether something like
3484+
// [unsafe.Sizeof(byte(0))]*byte is a direct-iface type.
3485+
3486+
class Lower_builtin_calls : public Traverse
3487+
{
3488+
public:
3489+
Lower_builtin_calls(Gogo* gogo)
3490+
: Traverse(traverse_expressions),
3491+
gogo_(gogo)
3492+
{ }
3493+
3494+
int
3495+
expression(Expression**);
3496+
3497+
private:
3498+
Gogo* gogo_;
3499+
};
3500+
3501+
int
3502+
Lower_builtin_calls::expression(Expression** pexpr)
3503+
{
3504+
Call_expression* ce = (*pexpr)->call_expression();
3505+
if (ce != NULL)
3506+
*pexpr = ce->lower_builtin(this->gogo_);
3507+
return TRAVERSE_CONTINUE;
3508+
}
3509+
3510+
void
3511+
Gogo::lower_builtin_calls()
3512+
{
3513+
Lower_builtin_calls lbc(this);
3514+
this->traverse(&lbc);
3515+
}
3516+
34853517
// Finalize the methods of an interface type.
34863518

34873519
int
@@ -3625,47 +3657,7 @@ Gogo::finalize_methods_for_type(Type* type)
36253657
void
36263658
Gogo::determine_types()
36273659
{
3628-
Bindings* bindings = this->current_bindings();
3629-
for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
3630-
p != bindings->end_definitions();
3631-
++p)
3632-
{
3633-
if ((*p)->is_function())
3634-
(*p)->func_value()->determine_types(this);
3635-
else if ((*p)->is_variable())
3636-
(*p)->var_value()->determine_type(this);
3637-
else if ((*p)->is_const())
3638-
(*p)->const_value()->determine_type(this);
3639-
3640-
// See if a variable requires us to build an initialization
3641-
// function. We know that we will see all global variables
3642-
// here.
3643-
if (!this->need_init_fn_ && (*p)->is_variable())
3644-
{
3645-
Variable* variable = (*p)->var_value();
3646-
3647-
// If this is a global variable which requires runtime
3648-
// initialization, we need an initialization function.
3649-
if (!variable->is_global())
3650-
;
3651-
else if (variable->init() == NULL)
3652-
;
3653-
else if (variable->type()->interface_type() != NULL)
3654-
this->need_init_fn_ = true;
3655-
else if (variable->init()->is_constant())
3656-
;
3657-
else if (!variable->init()->is_composite_literal())
3658-
this->need_init_fn_ = true;
3659-
else if (variable->init()->is_nonconstant_composite_literal())
3660-
this->need_init_fn_ = true;
3661-
3662-
// If this is a global variable which holds a pointer value,
3663-
// then we need an initialization function to register it as a
3664-
// GC root.
3665-
if (variable->is_global() && variable->type()->has_pointer())
3666-
this->need_init_fn_ = true;
3667-
}
3668-
}
3660+
this->current_bindings()->determine_types(this);
36693661

36703662
// Determine the types of constants in packages.
36713663
for (Packages::const_iterator p = this->packages_.begin();
@@ -3756,15 +3748,23 @@ Check_types_traverse::variable(Named_object* named_object)
37563748
no->message_name().c_str());
37573749
}
37583750
}
3751+
37593752
if (!var->is_used()
37603753
&& !var->is_global()
37613754
&& !var->is_parameter()
37623755
&& !var->is_receiver()
37633756
&& !var->type()->is_error()
37643757
&& (init == NULL || !init->is_error_expression())
37653758
&& !Lex::is_invalid_identifier(named_object->name()))
3766-
go_error_at(var->location(), "%qs declared but not used",
3767-
named_object->message_name().c_str());
3759+
{
3760+
// Avoid giving an error if the initializer is invalid.
3761+
if (init != NULL)
3762+
init->check_types(this->gogo_);
3763+
3764+
if (init == NULL || !init->is_error_expression())
3765+
go_error_at(var->location(), "%qs declared but not used",
3766+
named_object->message_name().c_str());
3767+
}
37683768
}
37693769
return TRAVERSE_CONTINUE;
37703770
}
@@ -3788,6 +3788,11 @@ Check_types_traverse::constant(Named_object* named_object, bool)
37883788
go_error_at(constant->location(), "invalid constant type");
37893789
constant->set_error();
37903790
}
3791+
else if (constant->expr()->is_error_expression())
3792+
{
3793+
go_assert(saw_errors());
3794+
constant->set_error();
3795+
}
37913796
else if (!constant->expr()->is_constant())
37923797
{
37933798
go_error_at(constant->expr()->location(), "expression is not constant");
@@ -4396,6 +4401,7 @@ Shortcuts::convert_shortcut(Block* enclosing, Expression** pshortcut)
43964401

43974402
Statement* if_statement = Statement::make_if_statement(cond, block, NULL,
43984403
loc);
4404+
if_statement->determine_types(this->gogo_);
43994405
retblock->add_statement(if_statement);
44004406

44014407
*pshortcut = Expression::make_temporary_reference(ts, loc);
@@ -4817,7 +4823,7 @@ Build_recover_thunks::function(Named_object* orig_no)
48174823
// Any varargs call has already been lowered.
48184824
call->set_varargs_are_lowered();
48194825

4820-
Statement* s = Statement::make_return_from_call(call, location);
4826+
Statement* s = Statement::make_return_from_call(new_no, call, location);
48214827
s->determine_types(this->gogo_);
48224828
gogo->add_statement(s);
48234829

@@ -5894,6 +5900,7 @@ Function::traverse(Traverse* traverse)
58945900
void
58955901
Function::determine_types(Gogo* gogo)
58965902
{
5903+
this->set_closure_type();
58975904
if (this->block_ != NULL)
58985905
this->block_->determine_types(gogo);
58995906
}
@@ -7465,8 +7472,8 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no)
74657472
if (!Block::import_block(outer, &ifb, start_loc))
74667473
return;
74677474

7468-
gogo->lower_block(no, outer);
74697475
outer->determine_types(gogo);
7476+
gogo->lower_block(no, outer);
74707477

74717478
gogo->add_imported_inline_function(no);
74727479
}
@@ -7670,9 +7677,13 @@ Variable::has_type() const
76707677
Type*
76717678
Variable::type_from_tuple(Expression* expr, bool report_error) const
76727679
{
7673-
if (expr->map_index_expression() != NULL)
7680+
if (Index_expression::is_map_index(expr))
76747681
{
7675-
Map_type* mt = expr->map_index_expression()->get_map_type();
7682+
Map_type* mt;
7683+
if (expr->map_index_expression() != NULL)
7684+
mt = expr->map_index_expression()->get_map_type();
7685+
else
7686+
mt = expr->index_expression()->left()->type()->map_type();
76767687
if (mt == NULL)
76777688
return Type::make_error_type();
76787689
return mt->val_type();
@@ -7701,7 +7712,9 @@ Variable::type_from_range(Expression* expr, bool get_index_type,
77017712
bool report_error) const
77027713
{
77037714
Type* t = expr->type();
7704-
if (t->array_type() != NULL
7715+
if (t->is_error_type())
7716+
return t;
7717+
else if (t->array_type() != NULL
77057718
|| (t->points_to() != NULL
77067719
&& t->points_to()->array_type() != NULL
77077720
&& !t->points_to()->is_slice_type()))
@@ -8211,14 +8224,50 @@ Named_constant::traverse_expression(Traverse* traverse)
82118224
return Expression::traverse(&this->expr_, traverse);
82128225
}
82138226

8227+
// Set the iota value in a constant expression.
8228+
8229+
class Set_iota_value : public Traverse
8230+
{
8231+
public:
8232+
Set_iota_value(int iota_value)
8233+
: Traverse(traverse_expressions),
8234+
iota_value_(iota_value)
8235+
{ }
8236+
8237+
int
8238+
expression(Expression**);
8239+
8240+
private:
8241+
int iota_value_;
8242+
};
8243+
8244+
int
8245+
Set_iota_value::expression(Expression** pexpr)
8246+
{
8247+
Expression* expr = *pexpr;
8248+
if (expr->const_expression() != NULL)
8249+
expr->const_expression()->set_iota_value(this->iota_value_);
8250+
else if (expr->unknown_expression() != NULL)
8251+
{
8252+
// This case can happen for an array length that is not set in
8253+
// the determine types pass.
8254+
expr->unknown_expression()->set_iota_value(this->iota_value_);
8255+
}
8256+
return TRAVERSE_CONTINUE;
8257+
}
8258+
82148259
// Determine the type of the constant.
82158260

82168261
void
82178262
Named_constant::determine_type(Gogo* gogo)
82188263
{
8264+
if (this->type_is_determined_)
8265+
return;
8266+
this->type_is_determined_ = true;
8267+
82198268
if (this->type_ != NULL)
82208269
{
8221-
Type_context context(this->type_, false);
8270+
Type_context context(this->type_, this->type_->is_abstract());
82228271
this->expr_->determine_type(gogo, &context);
82238272
}
82248273
else
@@ -8229,6 +8278,9 @@ Named_constant::determine_type(Gogo* gogo)
82298278
this->type_ = this->expr_->type();
82308279
go_assert(this->type_ != NULL);
82318280
}
8281+
8282+
Set_iota_value siv(this->iota_value_);
8283+
this->traverse_expression(&siv);
82328284
}
82338285

82348286
// Indicate that we found and reported an error for this constant.
@@ -9353,6 +9405,55 @@ Bindings::traverse(Traverse* traverse, bool is_global)
93539405
return TRAVERSE_CONTINUE;
93549406
}
93559407

9408+
// Determine types for the objects.
9409+
9410+
void
9411+
Bindings::determine_types(Gogo* gogo)
9412+
{
9413+
// We don't use an iterator because the traversal can add new
9414+
// bindings.
9415+
for (size_t i = 0; i < this->named_objects_.size(); ++i)
9416+
{
9417+
Named_object* no = this->named_objects_[i];
9418+
if (no->is_function())
9419+
no->func_value()->determine_types(gogo);
9420+
else if (no->is_variable())
9421+
no->var_value()->determine_type(gogo);
9422+
else if (no->is_const())
9423+
no->const_value()->determine_type(gogo);
9424+
9425+
// See if a variable requires us to build an initialization
9426+
// function. We know that we will see all global variables
9427+
// here.
9428+
if (!gogo->need_init_fn() && no->is_variable())
9429+
{
9430+
Variable* variable = no->var_value();
9431+
9432+
// If this is a global variable which requires runtime
9433+
// initialization, we need an initialization function.
9434+
9435+
if (!variable->is_global())
9436+
continue;
9437+
9438+
if (variable->init() == NULL)
9439+
;
9440+
else if (variable->type()->interface_type() != NULL)
9441+
gogo->set_need_init_fn();
9442+
else if (variable->init()->is_constant())
9443+
;
9444+
else if (!variable->init()->is_composite_literal())
9445+
gogo->set_need_init_fn();
9446+
else if (variable->init()->is_nonconstant_composite_literal())
9447+
gogo->set_need_init_fn();
9448+
9449+
// If this global variable holds a pointer value, we need an
9450+
// initialization function to register it as a GC root.
9451+
if (variable->type()->has_pointer())
9452+
gogo->set_need_init_fn();
9453+
}
9454+
}
9455+
}
9456+
93569457
void
93579458
Bindings::debug_dump()
93589459
{

0 commit comments

Comments
 (0)