Skip to content

Commit c3a3e10

Browse files
committed
Support pattern bindings within function signitures
This reuses our code to handle match-arams within MatchExpressions, we resolve the pattern's type's and implicitly create types for that binding. For code-generation we create a tmp var name for the name of the parameter which is the base type and for the destructuring we reuse the same match arm code to generate the implicit bindings to the parts of the structure ```c __attribute__((cdecl)) i32 test::pattern_as_arg (const struct test::Pattern RSTPRM.0) { i32 RUSTTMP.1; return RSTPRM.0.0; } ``` Fixes #995
1 parent d17e0aa commit c3a3e10

11 files changed

+177
-60
lines changed

gcc/rust/Make-lang.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ GRS_OBJS = \
110110
rust/rust-hir-type-check-path.o \
111111
rust/rust-compile-intrinsic.o \
112112
rust/rust-compile-pattern.o \
113+
rust/rust-compile-fnparam.o \
113114
rust/rust-base62.o \
114115
rust/rust-compile-item.o \
115116
rust/rust-compile-implitem.o \
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// Copyright (C) 2020-2022 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-fnparam.h"
20+
#include "rust-compile-pattern.h"
21+
22+
#include "gimple-expr.h"
23+
24+
namespace Rust {
25+
namespace Compile {
26+
27+
void
28+
CompileFnParam::visit (HIR::StructPattern &pattern)
29+
{
30+
// generate the anon param
31+
tree tmp_ident = create_tmp_var_name ("RSTPRM");
32+
std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident));
33+
34+
decl_type = ctx->get_backend ()->immutable_type (decl_type);
35+
compiled_param
36+
= ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identifier,
37+
decl_type, locus);
38+
39+
// setup the pattern bindings
40+
tree anon_param = ctx->get_backend ()->var_expression (compiled_param, locus);
41+
CompilePatternBindings::Compile (&pattern, anon_param, ctx);
42+
}
43+
44+
void
45+
CompileFnParam::visit (HIR::TupleStructPattern &pattern)
46+
{
47+
// generate the anon param
48+
tree tmp_ident = create_tmp_var_name ("RSTPRM");
49+
std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident));
50+
51+
decl_type = ctx->get_backend ()->immutable_type (decl_type);
52+
compiled_param
53+
= ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identifier,
54+
decl_type, locus);
55+
56+
// setup the pattern bindings
57+
tree anon_param = ctx->get_backend ()->var_expression (compiled_param, locus);
58+
CompilePatternBindings::Compile (&pattern, anon_param, ctx);
59+
}
60+
61+
} // namespace Compile
62+
} // namespace Rust

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ class CompileFnParam : public HIRCompileBase, public HIR::HIRPatternVisitor
6363
= ctx->get_backend ()->parameter_variable (fndecl, "_", decl_type, locus);
6464
}
6565

66+
void visit (HIR::StructPattern &) override;
67+
void visit (HIR::TupleStructPattern &) override;
68+
6669
// Empty visit for unused Pattern HIR nodes.
6770
void visit (HIR::GroupedPattern &) override {}
6871
void visit (HIR::LiteralPattern &) override {}
@@ -71,9 +74,7 @@ class CompileFnParam : public HIRCompileBase, public HIR::HIRPatternVisitor
7174
void visit (HIR::RangePattern &) override {}
7275
void visit (HIR::ReferencePattern &) override {}
7376
void visit (HIR::SlicePattern &) override {}
74-
void visit (HIR::StructPattern &) override {}
7577
void visit (HIR::TuplePattern &) override {}
76-
void visit (HIR::TupleStructPattern &) override {}
7778

7879
private:
7980
CompileFnParam (Context *ctx, tree fndecl, tree decl_type, Location locus)

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

Lines changed: 72 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "rust-compile-expr.h"
2121
#include "rust-constexpr.h"
2222

23+
#include "print-tree.h"
24+
2325
namespace Rust {
2426
namespace Compile {
2527

@@ -92,18 +94,20 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
9294
// this must be an enum
9395
rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
9496
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
95-
rust_assert (adt->is_enum ());
97+
rust_assert (adt->number_of_variants () > 0);
9698

97-
// lookup the variant
98-
HirId variant_id;
99-
ok = ctx->get_tyctx ()->lookup_variant_definition (
100-
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
101-
rust_assert (ok);
99+
int variant_index = 0;
100+
TyTy::VariantDef *variant = adt->get_variants ().at (0);
101+
if (adt->is_enum ())
102+
{
103+
HirId variant_id = UNKNOWN_HIRID;
104+
bool ok = ctx->get_tyctx ()->lookup_variant_definition (
105+
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
106+
rust_assert (ok);
102107

103-
int variant_index = -1;
104-
TyTy::VariantDef *variant = nullptr;
105-
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
106-
rust_assert (ok);
108+
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
109+
rust_assert (ok);
110+
}
107111

108112
rust_assert (variant->get_variant_type ()
109113
== TyTy::VariantDef::VariantType::TUPLE);
@@ -124,20 +128,37 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
124128
rust_assert (items_no_range.get_patterns ().size ()
125129
== variant->num_fields ());
126130

127-
// we are offsetting by + 1 here since the first field in the record
128-
// is always the discriminator
129-
size_t tuple_field_index = 1;
130-
for (auto &pattern : items_no_range.get_patterns ())
131+
if (adt->is_enum ())
132+
{
133+
// we are offsetting by + 1 here since the first field in the record
134+
// is always the discriminator
135+
size_t tuple_field_index = 1;
136+
for (auto &pattern : items_no_range.get_patterns ())
137+
{
138+
tree variant_accessor
139+
= ctx->get_backend ()->struct_field_expression (
140+
match_scrutinee_expr, variant_index, pattern->get_locus ());
141+
142+
tree binding = ctx->get_backend ()->struct_field_expression (
143+
variant_accessor, tuple_field_index++, pattern->get_locus ());
144+
145+
ctx->insert_pattern_binding (
146+
pattern->get_pattern_mappings ().get_hirid (), binding);
147+
}
148+
}
149+
else
131150
{
132-
tree variant_accessor
133-
= ctx->get_backend ()->struct_field_expression (
134-
match_scrutinee_expr, variant_index, pattern->get_locus ());
151+
size_t tuple_field_index = 0;
152+
for (auto &pattern : items_no_range.get_patterns ())
153+
{
154+
tree variant_accessor = match_scrutinee_expr;
135155

136-
tree binding = ctx->get_backend ()->struct_field_expression (
137-
variant_accessor, tuple_field_index++, pattern->get_locus ());
156+
tree binding = ctx->get_backend ()->struct_field_expression (
157+
variant_accessor, tuple_field_index++, pattern->get_locus ());
138158

139-
ctx->insert_pattern_binding (
140-
pattern->get_pattern_mappings ().get_hirid (), binding);
159+
ctx->insert_pattern_binding (
160+
pattern->get_pattern_mappings ().get_hirid (), binding);
161+
}
141162
}
142163
}
143164
break;
@@ -156,18 +177,20 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern)
156177
// this must be an enum
157178
rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
158179
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
159-
rust_assert (adt->is_enum ());
180+
rust_assert (adt->number_of_variants () > 0);
160181

161-
// lookup the variant
162-
HirId variant_id;
163-
ok = ctx->get_tyctx ()->lookup_variant_definition (
164-
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
165-
rust_assert (ok);
182+
int variant_index = 0;
183+
TyTy::VariantDef *variant = adt->get_variants ().at (0);
184+
if (adt->is_enum ())
185+
{
186+
HirId variant_id = UNKNOWN_HIRID;
187+
bool ok = ctx->get_tyctx ()->lookup_variant_definition (
188+
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
189+
rust_assert (ok);
166190

167-
int variant_index = -1;
168-
TyTy::VariantDef *variant = nullptr;
169-
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
170-
rust_assert (ok);
191+
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
192+
rust_assert (ok);
193+
}
171194

172195
rust_assert (variant->get_variant_type ()
173196
== TyTy::VariantDef::VariantType::STRUCT);
@@ -193,19 +216,29 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern)
193216
HIR::StructPatternFieldIdent &ident
194217
= static_cast<HIR::StructPatternFieldIdent &> (*field.get ());
195218

196-
tree variant_accessor
197-
= ctx->get_backend ()->struct_field_expression (
198-
match_scrutinee_expr, variant_index, ident.get_locus ());
199-
200219
size_t offs = 0;
201220
ok
202221
= variant->lookup_field (ident.get_identifier (), nullptr, &offs);
203222
rust_assert (ok);
204223

205-
// we are offsetting by + 1 here since the first field in the record
206-
// is always the discriminator
207-
tree binding = ctx->get_backend ()->struct_field_expression (
208-
variant_accessor, offs + 1, ident.get_locus ());
224+
tree binding = error_mark_node;
225+
if (adt->is_enum ())
226+
{
227+
tree variant_accessor
228+
= ctx->get_backend ()->struct_field_expression (
229+
match_scrutinee_expr, variant_index, ident.get_locus ());
230+
231+
// we are offsetting by + 1 here since the first field in the
232+
// record is always the discriminator
233+
binding = ctx->get_backend ()->struct_field_expression (
234+
variant_accessor, offs + 1, ident.get_locus ());
235+
}
236+
else
237+
{
238+
tree variant_accessor = match_scrutinee_expr;
239+
binding = ctx->get_backend ()->struct_field_expression (
240+
variant_accessor, offs, ident.get_locus ());
241+
}
209242

210243
ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (),
211244
binding);

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class CompilePatternBindings : public HIRCompileBase,
8383
void visit (HIR::TuplePattern &) override {}
8484
void visit (HIR::WildcardPattern &) override {}
8585

86-
private:
86+
protected:
8787
CompilePatternBindings (Context *ctx, tree match_scrutinee_expr)
8888
: HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr)
8989
{}

gcc/rust/typecheck/rust-hir-type-check-implitem.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ class TypeCheckTopLevelExternItem : public TypeCheckBase
116116
param_tyty));
117117

118118
context->insert_type (param.get_mappings (), param_tyty);
119+
120+
// FIXME do we need error checking for patterns here?
121+
// see https://github.com/Rust-GCC/gccrs/issues/995
119122
}
120123

121124
uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG;
@@ -297,6 +300,7 @@ class TypeCheckTopLevelImplItem : public TypeCheckBase
297300
param_tyty));
298301

299302
context->insert_type (param.get_mappings (), param_tyty);
303+
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
300304
}
301305

302306
const CanonicalPath *canonical_path = nullptr;

gcc/rust/typecheck/rust-hir-type-check-pattern.cc

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,17 +37,19 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
3737

3838
rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
3939
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
40-
rust_assert (adt->is_enum ());
40+
rust_assert (adt->number_of_variants () > 0);
4141

42-
// what variant is this?
43-
HirId variant_id;
44-
bool ok = context->lookup_variant_definition (
45-
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
46-
rust_assert (ok);
42+
TyTy::VariantDef *variant = adt->get_variants ().at (0);
43+
if (adt->is_enum ())
44+
{
45+
HirId variant_id = UNKNOWN_HIRID;
46+
bool ok = context->lookup_variant_definition (
47+
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
48+
rust_assert (ok);
4749

48-
TyTy::VariantDef *variant = nullptr;
49-
ok = adt->lookup_variant_by_id (variant_id, &variant);
50-
rust_assert (ok);
50+
ok = adt->lookup_variant_by_id (variant_id, &variant);
51+
rust_assert (ok);
52+
}
5153

5254
// error[E0532]: expected tuple struct or tuple variant, found struct variant
5355
// `Foo::D`
@@ -121,17 +123,19 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
121123

122124
rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
123125
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
124-
rust_assert (adt->is_enum ());
126+
rust_assert (adt->number_of_variants () > 0);
125127

126-
// what variant is this?
127-
HirId variant_id;
128-
bool ok = context->lookup_variant_definition (
129-
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
130-
rust_assert (ok);
128+
TyTy::VariantDef *variant = adt->get_variants ().at (0);
129+
if (adt->is_enum ())
130+
{
131+
HirId variant_id = UNKNOWN_HIRID;
132+
bool ok = context->lookup_variant_definition (
133+
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
134+
rust_assert (ok);
131135

132-
TyTy::VariantDef *variant = nullptr;
133-
ok = adt->lookup_variant_by_id (variant_id, &variant);
134-
rust_assert (ok);
136+
ok = adt->lookup_variant_by_id (variant_id, &variant);
137+
rust_assert (ok);
138+
}
135139

136140
// error[E0532]: expected tuple struct or tuple variant, found struct variant
137141
// `Foo::D`

gcc/rust/typecheck/rust-hir-type-check-stmt.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -448,6 +448,7 @@ class TypeCheckStmt : public TypeCheckBase
448448
param_tyty));
449449

450450
context->insert_type (param.get_mappings (), param_tyty);
451+
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
451452
}
452453

453454
// get the path

gcc/rust/typecheck/rust-hir-type-check-toplevel.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,7 @@ class TypeCheckTopLevel : public TypeCheckBase
416416
param_tyty));
417417

418418
context->insert_type (param.get_mappings (), param_tyty);
419+
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
419420
}
420421

421422
const CanonicalPath *canonical_path = nullptr;

gcc/rust/typecheck/rust-hir-type-check.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,7 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const
320320
param_tyty));
321321

322322
context->insert_type (param.get_mappings (), param_tyty);
323+
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
323324
}
324325

325326
auto mappings = Analysis::Mappings::get ();

0 commit comments

Comments
 (0)