Skip to content

Commit 80ab17f

Browse files
committed
Add support for enums on the match expression
TODO Fixes #190
1 parent a8a3456 commit 80ab17f

File tree

6 files changed

+379
-0
lines changed

6 files changed

+379
-0
lines changed

gcc/rust/Make-lang.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ GRS_OBJS = \
9494
rust/rust-lint-marklive.o \
9595
rust/rust-hir-type-check-path.o \
9696
rust/rust-compile-intrinsic.o \
97+
rust/rust-compile-pattern.o \
9798
rust/rust-base62.o \
9899
rust/rust-compile-expr.o \
99100
rust/rust-compile-type.o \

gcc/rust/backend/rust-compile-expr.cc

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "rust-hir-path-probe.h"
2525
#include "rust-hir-type-bounds.h"
2626
#include "rust-hir-dot-operator.h"
27+
#include "rust-compile-pattern.h"
2728

2829
namespace Rust {
2930
namespace Compile {
@@ -154,6 +155,159 @@ CompileExpr::visit (HIR::DereferenceExpr &expr)
154155
known_valid, expr.get_locus ());
155156
}
156157

158+
void
159+
CompileExpr::visit (HIR::MatchExpr &expr)
160+
{
161+
// https://gcc.gnu.org/onlinedocs/gccint/Basic-Statements.html#Basic-Statements
162+
// TODO
163+
// SWITCH_ALL_CASES_P is true if the switch includes a default label or the
164+
// case label ranges cover all possible values of the condition expression
165+
166+
/* Switch expression.
167+
168+
TREE_TYPE is the original type of the condition, before any
169+
language required type conversions. It may be NULL, in which case
170+
the original type and final types are assumed to be the same.
171+
172+
Operand 0 is the expression used to perform the branch,
173+
Operand 1 is the body of the switch, which probably contains
174+
CASE_LABEL_EXPRs. It may also be NULL, in which case operand 2
175+
must not be NULL. */
176+
// DEFTREECODE (SWITCH_EXPR, "switch_expr", tcc_statement, 2)
177+
178+
/* Used to represent a case label.
179+
180+
Operand 0 is CASE_LOW. It may be NULL_TREE, in which case the label
181+
is a 'default' label.
182+
Operand 1 is CASE_HIGH. If it is NULL_TREE, the label is a simple
183+
(one-value) case label. If it is non-NULL_TREE, the case is a range.
184+
Operand 2 is CASE_LABEL, which has the corresponding LABEL_DECL.
185+
Operand 3 is CASE_CHAIN. This operand is only used in tree-cfg.c to
186+
speed up the lookup of case labels which use a particular edge in
187+
the control flow graph. */
188+
// DEFTREECODE (CASE_LABEL_EXPR, "case_label_expr", tcc_statement, 4)
189+
190+
TyTy::BaseType *scrutinee_expr_tyty = nullptr;
191+
if (!ctx->get_tyctx ()->lookup_type (
192+
expr.get_scrutinee_expr ()->get_mappings ().get_hirid (),
193+
&scrutinee_expr_tyty))
194+
{
195+
translated = ctx->get_backend ()->error_expression ();
196+
return;
197+
}
198+
199+
rust_assert (scrutinee_expr_tyty->get_kind () == TyTy::TypeKind::ADT);
200+
201+
// this will need to change but for now the first pass implementation, lets
202+
// assert this is the case
203+
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (scrutinee_expr_tyty);
204+
rust_assert (adt->is_enum ());
205+
rust_assert (adt->number_of_variants () > 0);
206+
207+
TyTy::BaseType *expr_tyty = nullptr;
208+
if (!ctx->get_tyctx ()->lookup_type (expr.get_mappings ().get_hirid (),
209+
&expr_tyty))
210+
{
211+
translated = ctx->get_backend ()->error_expression ();
212+
return;
213+
}
214+
215+
fncontext fnctx = ctx->peek_fn ();
216+
Bvariable *tmp = NULL;
217+
bool needs_temp = !expr_tyty->is_unit ();
218+
if (needs_temp)
219+
{
220+
tree enclosing_scope = ctx->peek_enclosing_scope ();
221+
tree block_type = TyTyResolveCompile::compile (ctx, expr_tyty);
222+
223+
bool is_address_taken = false;
224+
tree ret_var_stmt = nullptr;
225+
tmp = ctx->get_backend ()->temporary_variable (
226+
fnctx.fndecl, enclosing_scope, block_type, NULL, is_address_taken,
227+
expr.get_locus (), &ret_var_stmt);
228+
ctx->add_statement (ret_var_stmt);
229+
}
230+
231+
// lets compile the scrutinee expression
232+
tree match_scrutinee_expr
233+
= CompileExpr::Compile (expr.get_scrutinee_expr ().get (), ctx);
234+
235+
// need to access the qualifier field, if we use QUAL_UNION_TYPE this would be
236+
// DECL_QUALIFIER i think. For now this will just access the first record
237+
// field and its respective qualifier because it will always be set because
238+
// this is all a big special union
239+
tree scrutinee_first_record_expr
240+
= ctx->get_backend ()->struct_field_expression (
241+
match_scrutinee_expr, 0, expr.get_scrutinee_expr ()->get_locus ());
242+
tree match_scrutinee_expr_qualifier_expr
243+
= ctx->get_backend ()->struct_field_expression (
244+
scrutinee_first_record_expr, 0, expr.get_scrutinee_expr ()->get_locus ());
245+
246+
tree fndecl = fnctx.fndecl;
247+
Location start_location; // FIXME
248+
Location end_location; // FIXME
249+
tree enclosing_scope = ctx->peek_enclosing_scope ();
250+
tree switch_body_block
251+
= ctx->get_backend ()->block (fndecl, enclosing_scope, {}, start_location,
252+
end_location);
253+
ctx->push_block (switch_body_block);
254+
255+
std::vector<tree> switch_case_exprs;
256+
for (auto &kase : expr.get_match_cases ())
257+
{
258+
// for now lets just get single pattern's working
259+
HIR::MatchArm &kase_arm = kase.get_arm ();
260+
rust_assert (kase_arm.get_patterns ().size () > 0);
261+
262+
// generate implicit label
263+
Location arm_locus = kase_arm.get_patterns ().at (0)->get_locus ();
264+
tree case_label = create_artificial_label (arm_locus.gcc_location ());
265+
266+
// setup the bindings for the block
267+
for (auto &kase_pattern : kase_arm.get_patterns ())
268+
{
269+
CompilePatternBindings::Compile (kase_pattern.get (), ctx);
270+
}
271+
272+
// compile the expr and setup the assignment if required when tmp != NULL
273+
tree kase_expr_tree = CompileExpr::Compile (kase.get_expr ().get (), ctx);
274+
if (tmp != NULL)
275+
{
276+
tree result_reference
277+
= ctx->get_backend ()->var_expression (tmp, arm_locus);
278+
tree assignment = ctx->get_backend ()->assignment_statement (
279+
fnctx.fndecl, result_reference, kase_expr_tree, arm_locus);
280+
ctx->add_statement (assignment);
281+
}
282+
283+
// add implicit break to stop implicit fallthough
284+
// TODO
285+
286+
for (auto &kase_pattern : kase_arm.get_patterns ())
287+
{
288+
tree switch_kase_expr
289+
= CompilePatternCaseLabelExpr::Compile (kase_pattern.get (),
290+
case_label, ctx);
291+
switch_case_exprs.push_back (switch_kase_expr);
292+
}
293+
}
294+
295+
ctx->get_backend ()->block_add_statements (switch_body_block,
296+
switch_case_exprs);
297+
tree match_body = ctx->pop_block ();
298+
299+
tree match_expr_stmt
300+
= build2_loc (expr.get_locus ().gcc_location (), SWITCH_EXPR,
301+
TREE_TYPE (match_scrutinee_expr_qualifier_expr),
302+
match_scrutinee_expr_qualifier_expr, match_body);
303+
ctx->add_statement (match_expr_stmt);
304+
305+
if (tmp != NULL)
306+
{
307+
translated = ctx->get_backend ()->var_expression (tmp, expr.get_locus ());
308+
}
309+
}
310+
157311
void
158312
CompileExpr::visit (HIR::CallExpr &expr)
159313
{

gcc/rust/backend/rust-compile-expr.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,8 @@ class CompileExpr : public HIRCompileBase
10431043

10441044
void visit (HIR::DereferenceExpr &expr) override;
10451045

1046+
void visit (HIR::MatchExpr &expr) override;
1047+
10461048
protected:
10471049
tree compile_dyn_dispatch_call (const TyTy::DynamicObjectType *dyn,
10481050
TyTy::BaseType *receiver,
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// Copyright (C) 2020-2021 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
19+
#include "rust-compile-pattern.h"
20+
21+
namespace Rust {
22+
namespace Compile {
23+
24+
void
25+
CompilePatternCaseLabelExpr::visit (HIR::PathInExpression &pattern)
26+
{
27+
// lookup the type
28+
TyTy::BaseType *lookup = nullptr;
29+
bool ok
30+
= ctx->get_tyctx ()->lookup_type (pattern.get_mappings ().get_hirid (),
31+
&lookup);
32+
rust_assert (ok);
33+
34+
// this must be an enum
35+
rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
36+
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
37+
rust_assert (adt->is_enum ());
38+
39+
// lookup the variant
40+
HirId variant_id;
41+
ok = ctx->get_tyctx ()->lookup_variant_definition (
42+
pattern.get_mappings ().get_hirid (), &variant_id);
43+
rust_assert (ok);
44+
45+
TyTy::VariantDef *variant = nullptr;
46+
ok = adt->lookup_variant_by_id (variant_id, &variant);
47+
rust_assert (ok);
48+
49+
mpz_t disciminantl;
50+
if (variant->get_variant_type () == TyTy::VariantDef::VariantType::NUM)
51+
{
52+
mpz_init_set_ui (disciminantl, variant->get_discriminant ());
53+
}
54+
else
55+
{
56+
HirId variant_id = variant->get_id ();
57+
mpz_init_set_ui (disciminantl, variant_id);
58+
}
59+
60+
tree t = TyTyResolveCompile::get_implicit_enumeral_node_type (ctx);
61+
tree case_low
62+
= double_int_to_tree (t, mpz_get_double_int (t, disciminantl, true));
63+
64+
case_label_expr
65+
= build_case_label (case_low, NULL_TREE, associated_case_label);
66+
}
67+
68+
void
69+
CompilePatternCaseLabelExpr::visit (HIR::StructPattern &pattern)
70+
{
71+
CompilePatternCaseLabelExpr::visit (pattern.get_path ());
72+
}
73+
74+
void
75+
CompilePatternCaseLabelExpr::visit (HIR::TupleStructPattern &pattern)
76+
{
77+
CompilePatternCaseLabelExpr::visit (pattern.get_path ());
78+
}
79+
80+
// setup the bindings
81+
82+
void
83+
CompilePatternBindings::visit (HIR::StructPattern &pattern)
84+
{}
85+
86+
void
87+
CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
88+
{}
89+
90+
} // namespace Compile
91+
} // namespace Rust
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright (C) 2020-2021 Free Software Foundation, Inc.
2+
3+
// This file is part of GCC.
4+
5+
// GCC is free software; you can redistribute it and/or modify it under
6+
// the terms of the GNU General Public License as published by the Free
7+
// Software Foundation; either version 3, or (at your option) any later
8+
// version.
9+
10+
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
11+
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
12+
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13+
// for more details.
14+
15+
// You should have received a copy of the GNU General Public License
16+
// along with GCC; see the file COPYING3. If not see
17+
// <http://www.gnu.org/licenses/>.
18+
19+
#include "rust-compile-base.h"
20+
21+
namespace Rust {
22+
namespace Compile {
23+
24+
class CompilePatternCaseLabelExpr : public HIRCompileBase
25+
{
26+
using Rust::Compile::HIRCompileBase::visit;
27+
28+
public:
29+
static tree Compile (HIR::Pattern *pattern, tree associated_case_label,
30+
Context *ctx)
31+
{
32+
CompilePatternCaseLabelExpr compiler (ctx, associated_case_label);
33+
pattern->accept_vis (compiler);
34+
return compiler.case_label_expr;
35+
}
36+
37+
void visit (HIR::PathInExpression &pattern) override;
38+
39+
void visit (HIR::StructPattern &pattern) override;
40+
41+
void visit (HIR::TupleStructPattern &pattern) override;
42+
43+
private:
44+
CompilePatternCaseLabelExpr (Context *ctx, tree associated_case_label)
45+
: HIRCompileBase (ctx), case_label_expr (error_mark_node),
46+
associated_case_label (associated_case_label)
47+
{}
48+
49+
tree case_label_expr;
50+
tree associated_case_label;
51+
};
52+
53+
class CompilePatternBindings : public HIRCompileBase
54+
{
55+
using Rust::Compile::HIRCompileBase::visit;
56+
57+
public:
58+
static void Compile (HIR::Pattern *pattern, Context *ctx)
59+
{
60+
CompilePatternBindings compiler (ctx);
61+
pattern->accept_vis (compiler);
62+
}
63+
64+
void visit (HIR::StructPattern &pattern) override;
65+
66+
void visit (HIR::TupleStructPattern &pattern) override;
67+
68+
private:
69+
CompilePatternBindings (Context *ctx) : HIRCompileBase (ctx) {}
70+
};
71+
72+
} // namespace Compile
73+
} // namespace Rust

0 commit comments

Comments
 (0)