1138: Support pattern bindings within function signitures r=philberty a=philberty

This reuses our code to handle match-arms 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


Co-authored-by: Philip Herron <philip.herron@embecosm.com>
This commit is contained in:
bors[bot] 2022-04-20 08:33:46 +00:00 committed by GitHub
commit 14dbac9a8b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 177 additions and 60 deletions

View File

@ -111,6 +111,7 @@ GRS_OBJS = \
rust/rust-hir-type-check-path.o \
rust/rust-compile-intrinsic.o \
rust/rust-compile-pattern.o \
rust/rust-compile-fnparam.o \
rust/rust-base62.o \
rust/rust-compile-item.o \
rust/rust-compile-implitem.o \

View File

@ -0,0 +1,62 @@
// Copyright (C) 2020-2022 Free Software Foundation, Inc.
// This file is part of GCC.
// GCC is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3, or (at your option) any later
// version.
// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
// You should have received a copy of the GNU General Public License
// along with GCC; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
#include "rust-compile-fnparam.h"
#include "rust-compile-pattern.h"
#include "gimple-expr.h"
namespace Rust {
namespace Compile {
void
CompileFnParam::visit (HIR::StructPattern &pattern)
{
// generate the anon param
tree tmp_ident = create_tmp_var_name ("RSTPRM");
std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident));
decl_type = ctx->get_backend ()->immutable_type (decl_type);
compiled_param
= ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identifier,
decl_type, locus);
// setup the pattern bindings
tree anon_param = ctx->get_backend ()->var_expression (compiled_param, locus);
CompilePatternBindings::Compile (&pattern, anon_param, ctx);
}
void
CompileFnParam::visit (HIR::TupleStructPattern &pattern)
{
// generate the anon param
tree tmp_ident = create_tmp_var_name ("RSTPRM");
std::string cpp_str_identifier = std::string (IDENTIFIER_POINTER (tmp_ident));
decl_type = ctx->get_backend ()->immutable_type (decl_type);
compiled_param
= ctx->get_backend ()->parameter_variable (fndecl, cpp_str_identifier,
decl_type, locus);
// setup the pattern bindings
tree anon_param = ctx->get_backend ()->var_expression (compiled_param, locus);
CompilePatternBindings::Compile (&pattern, anon_param, ctx);
}
} // namespace Compile
} // namespace Rust

View File

@ -63,6 +63,9 @@ public:
= ctx->get_backend ()->parameter_variable (fndecl, "_", decl_type, locus);
}
void visit (HIR::StructPattern &) override;
void visit (HIR::TupleStructPattern &) override;
// Empty visit for unused Pattern HIR nodes.
void visit (HIR::GroupedPattern &) override {}
void visit (HIR::LiteralPattern &) override {}
@ -71,9 +74,7 @@ public:
void visit (HIR::RangePattern &) override {}
void visit (HIR::ReferencePattern &) override {}
void visit (HIR::SlicePattern &) override {}
void visit (HIR::StructPattern &) override {}
void visit (HIR::TuplePattern &) override {}
void visit (HIR::TupleStructPattern &) override {}
private:
CompileFnParam (Context *ctx, tree fndecl, tree decl_type, Location locus)

View File

@ -20,6 +20,8 @@
#include "rust-compile-expr.h"
#include "rust-constexpr.h"
#include "print-tree.h"
namespace Rust {
namespace Compile {
@ -92,18 +94,20 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
// this must be an enum
rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
rust_assert (adt->is_enum ());
rust_assert (adt->number_of_variants () > 0);
// lookup the variant
HirId variant_id;
ok = ctx->get_tyctx ()->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
int variant_index = 0;
TyTy::VariantDef *variant = adt->get_variants ().at (0);
if (adt->is_enum ())
{
HirId variant_id = UNKNOWN_HIRID;
bool ok = ctx->get_tyctx ()->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
int variant_index = -1;
TyTy::VariantDef *variant = nullptr;
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
rust_assert (ok);
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
rust_assert (ok);
}
rust_assert (variant->get_variant_type ()
== TyTy::VariantDef::VariantType::TUPLE);
@ -124,20 +128,37 @@ CompilePatternBindings::visit (HIR::TupleStructPattern &pattern)
rust_assert (items_no_range.get_patterns ().size ()
== variant->num_fields ());
// we are offsetting by + 1 here since the first field in the record
// is always the discriminator
size_t tuple_field_index = 1;
for (auto &pattern : items_no_range.get_patterns ())
if (adt->is_enum ())
{
tree variant_accessor
= ctx->get_backend ()->struct_field_expression (
match_scrutinee_expr, variant_index, pattern->get_locus ());
// we are offsetting by + 1 here since the first field in the record
// is always the discriminator
size_t tuple_field_index = 1;
for (auto &pattern : items_no_range.get_patterns ())
{
tree variant_accessor
= ctx->get_backend ()->struct_field_expression (
match_scrutinee_expr, variant_index, pattern->get_locus ());
tree binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, tuple_field_index++, pattern->get_locus ());
tree binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, tuple_field_index++, pattern->get_locus ());
ctx->insert_pattern_binding (
pattern->get_pattern_mappings ().get_hirid (), binding);
ctx->insert_pattern_binding (
pattern->get_pattern_mappings ().get_hirid (), binding);
}
}
else
{
size_t tuple_field_index = 0;
for (auto &pattern : items_no_range.get_patterns ())
{
tree variant_accessor = match_scrutinee_expr;
tree binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, tuple_field_index++, pattern->get_locus ());
ctx->insert_pattern_binding (
pattern->get_pattern_mappings ().get_hirid (), binding);
}
}
}
break;
@ -156,18 +177,20 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern)
// this must be an enum
rust_assert (lookup->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
rust_assert (adt->is_enum ());
rust_assert (adt->number_of_variants () > 0);
// lookup the variant
HirId variant_id;
ok = ctx->get_tyctx ()->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
int variant_index = 0;
TyTy::VariantDef *variant = adt->get_variants ().at (0);
if (adt->is_enum ())
{
HirId variant_id = UNKNOWN_HIRID;
bool ok = ctx->get_tyctx ()->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
int variant_index = -1;
TyTy::VariantDef *variant = nullptr;
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
rust_assert (ok);
ok = adt->lookup_variant_by_id (variant_id, &variant, &variant_index);
rust_assert (ok);
}
rust_assert (variant->get_variant_type ()
== TyTy::VariantDef::VariantType::STRUCT);
@ -193,19 +216,29 @@ CompilePatternBindings::visit (HIR::StructPattern &pattern)
HIR::StructPatternFieldIdent &ident
= static_cast<HIR::StructPatternFieldIdent &> (*field.get ());
tree variant_accessor
= ctx->get_backend ()->struct_field_expression (
match_scrutinee_expr, variant_index, ident.get_locus ());
size_t offs = 0;
ok
= variant->lookup_field (ident.get_identifier (), nullptr, &offs);
rust_assert (ok);
// we are offsetting by + 1 here since the first field in the record
// is always the discriminator
tree binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, offs + 1, ident.get_locus ());
tree binding = error_mark_node;
if (adt->is_enum ())
{
tree variant_accessor
= ctx->get_backend ()->struct_field_expression (
match_scrutinee_expr, variant_index, ident.get_locus ());
// we are offsetting by + 1 here since the first field in the
// record is always the discriminator
binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, offs + 1, ident.get_locus ());
}
else
{
tree variant_accessor = match_scrutinee_expr;
binding = ctx->get_backend ()->struct_field_expression (
variant_accessor, offs, ident.get_locus ());
}
ctx->insert_pattern_binding (ident.get_mappings ().get_hirid (),
binding);

View File

@ -83,7 +83,7 @@ public:
void visit (HIR::TuplePattern &) override {}
void visit (HIR::WildcardPattern &) override {}
private:
protected:
CompilePatternBindings (Context *ctx, tree match_scrutinee_expr)
: HIRCompileBase (ctx), match_scrutinee_expr (match_scrutinee_expr)
{}

View File

@ -116,6 +116,9 @@ public:
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
// FIXME do we need error checking for patterns here?
// see https://github.com/Rust-GCC/gccrs/issues/995
}
uint8_t flags = TyTy::FnType::FNTYPE_IS_EXTERN_FLAG;
@ -297,6 +300,7 @@ public:
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
}
const CanonicalPath *canonical_path = nullptr;

View File

@ -37,17 +37,19 @@ TypeCheckPattern::visit (HIR::TupleStructPattern &pattern)
rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
rust_assert (adt->is_enum ());
rust_assert (adt->number_of_variants () > 0);
// what variant is this?
HirId variant_id;
bool ok = context->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
TyTy::VariantDef *variant = adt->get_variants ().at (0);
if (adt->is_enum ())
{
HirId variant_id = UNKNOWN_HIRID;
bool ok = context->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
TyTy::VariantDef *variant = nullptr;
ok = adt->lookup_variant_by_id (variant_id, &variant);
rust_assert (ok);
ok = adt->lookup_variant_by_id (variant_id, &variant);
rust_assert (ok);
}
// error[E0532]: expected tuple struct or tuple variant, found struct variant
// `Foo::D`
@ -121,17 +123,19 @@ TypeCheckPattern::visit (HIR::StructPattern &pattern)
rust_assert (infered->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (infered);
rust_assert (adt->is_enum ());
rust_assert (adt->number_of_variants () > 0);
// what variant is this?
HirId variant_id;
bool ok = context->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
TyTy::VariantDef *variant = adt->get_variants ().at (0);
if (adt->is_enum ())
{
HirId variant_id = UNKNOWN_HIRID;
bool ok = context->lookup_variant_definition (
pattern.get_path ().get_mappings ().get_hirid (), &variant_id);
rust_assert (ok);
TyTy::VariantDef *variant = nullptr;
ok = adt->lookup_variant_by_id (variant_id, &variant);
rust_assert (ok);
ok = adt->lookup_variant_by_id (variant_id, &variant);
rust_assert (ok);
}
// error[E0532]: expected tuple struct or tuple variant, found struct variant
// `Foo::D`

View File

@ -448,6 +448,7 @@ public:
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
}
// get the path

View File

@ -416,6 +416,7 @@ public:
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
}
const CanonicalPath *canonical_path = nullptr;

View File

@ -320,6 +320,7 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const
param_tyty));
context->insert_type (param.get_mappings (), param_tyty);
TypeCheckPattern::Resolve (param.get_param_name (), param_tyty);
}
auto mappings = Analysis::Mappings::get ();

View File

@ -0,0 +1,9 @@
struct Pattern(i32);
fn pattern_as_arg(Pattern(value): Pattern) -> i32 {
value
}
fn main() -> i32 {
pattern_as_arg(Pattern(15)) - 15
}