From: Owen Avery <[email protected]>
Slice patterns with bound rest patterns still aren't supported in type
checking and compilation to GENERIC.
gcc/rust/ChangeLog:
* backend/rust-compile-pattern.cc
(CompilePatternBindings::visit (SlicePattern)): Assert that the
rest pattern isn't bound (currently unsupported).
* checks/errors/borrowck/rust-bir-builder-pattern.cc
(PatternBindingBuilder::visit (SlicePattern)): Handle bound rest
pattern.
* checks/errors/rust-ast-validation.cc
(ASTValidation::visit (AST::SlicePattern)): Likewise.
* hir/rust-ast-lower-pattern.cc
(ASTLoweringPattern::visit (AST::SlicePattern)): Likewise.
* hir/rust-hir-dump.cc (Dump::visit (SlicePatternItemsHasRest)):
Likewise.
* hir/tree/rust-hir-pattern.h
(SlicePatternItemsHasRest::rest_bind): New member variable.
(SlicePatternItemsHasRest::SlicePatternItemsHasRest): Initialize
rest_bind.
(SlicePatternItemsHasRest::operator=): Likewise.
(SlicePatternItemsHasRest::has_rest_bind): New member function.
(SlicePatternItemsHasRest::get_rest_bind): Likewise.
* hir/tree/rust-hir-visitor.cc
(DefaultHIRVisitor::walk (SlicePatternItemsHasRest)): Handle
bound rest pattern.
* hir/tree/rust-hir.cc (SlicePatternItemsHasRest::to_string):
Likewise.
* typecheck/rust-hir-type-check-pattern.cc
(TypeCheckPattern::visit (SlicePattern)): Assert that the rest
pattern isn't bound (currently unsupported).
gcc/testsuite/ChangeLog:
* rust/compile/slice_rest_pattern_2.rs: New test.
Signed-off-by: Owen Avery <[email protected]>
---
This change was merged into the gccrs repository and is posted here for
upstream visibility and potential drive-by review, as requested by GCC
release managers.
Each commit email contains a link to its details on github from where you can
find the Pull-Request and associated discussions.
Commit on github:
https://github.com/Rust-GCC/gccrs/commit/78016dea955c55b476aef6a2d54786b060246c51
The commit has NOT been mentioned in any issue.
The commit has been mentioned in the following pull-request(s):
- https://github.com/Rust-GCC/gccrs/pull/4774
gcc/rust/backend/rust-compile-pattern.cc | 4 ++
.../borrowck/rust-bir-builder-pattern.cc | 4 ++
gcc/rust/checks/errors/rust-ast-validation.cc | 21 +++++++++--
gcc/rust/hir/rust-ast-lower-pattern.cc | 37 +++++++++++++++++--
gcc/rust/hir/rust-hir-dump.cc | 2 +
gcc/rust/hir/tree/rust-hir-pattern.h | 26 ++++++++++++-
gcc/rust/hir/tree/rust-hir-visitor.cc | 2 +
gcc/rust/hir/tree/rust-hir.cc | 6 +++
.../typecheck/rust-hir-type-check-pattern.cc | 4 ++
.../rust/compile/slice_rest_pattern_2.rs | 11 ++++++
10 files changed, 107 insertions(+), 10 deletions(-)
create mode 100644 gcc/testsuite/rust/compile/slice_rest_pattern_2.rs
diff --git a/gcc/rust/backend/rust-compile-pattern.cc
b/gcc/rust/backend/rust-compile-pattern.cc
index e2f54d7ac..19f5bc4ed 100644
--- a/gcc/rust/backend/rust-compile-pattern.cc
+++ b/gcc/rust/backend/rust-compile-pattern.cc
@@ -1233,6 +1233,10 @@ CompilePatternBindings::visit (HIR::SlicePattern
&pattern)
{
auto &items
= static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+
+ // TODO: support rest_bind (c in [a, b, c @ ..])
+ rust_assert (!items.has_rest_bind ());
+
for (auto &pattern_member : items.get_lower_patterns ())
{
tree index_tree
diff --git a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
index e78d75050..5bd061470 100644
--- a/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
+++ b/gcc/rust/checks/errors/borrowck/rust-bir-builder-pattern.cc
@@ -92,6 +92,10 @@ PatternBindingBuilder::visit (HIR::SlicePattern &pattern)
{
member->accept_vis (*this);
}
+ if (items.has_rest_bind ())
+ {
+ items.get_rest_bind ().accept_vis (*this);
+ }
for (auto &member : items.get_upper_patterns ())
{
member->accept_vis (*this);
diff --git a/gcc/rust/checks/errors/rust-ast-validation.cc
b/gcc/rust/checks/errors/rust-ast-validation.cc
index e3262b947..b2825fb2c 100644
--- a/gcc/rust/checks/errors/rust-ast-validation.cc
+++ b/gcc/rust/checks/errors/rust-ast-validation.cc
@@ -205,14 +205,27 @@ ASTValidation::visit (AST::SlicePattern &pattern)
// for nicer errors
bool had_rest = false;
+ auto note_rest = [&] (location_t locus) {
+ if (had_rest)
+ rust_error_at (locus, "%<..%> can only be used once per slice pattern");
+ had_rest = true;
+ };
+
for (auto &pat : pattern.get_patterns ())
{
if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest)
{
- if (had_rest)
- rust_error_at (pat->get_locus (),
- "%<..%> can only be used once per slice pattern");
- had_rest = true;
+ note_rest (pat->get_locus ());
+ }
+ else if (pat->get_pattern_kind () == AST::Pattern::Kind::Identifier)
+ {
+ auto &ident_pat = static_cast<AST::IdentifierPattern &> (*pat);
+ if (ident_pat.has_subpattern ())
+ {
+ auto &ident_sub_pat = ident_pat.get_subpattern ();
+ if (ident_sub_pat.get_pattern_kind () == AST::Pattern::Kind::Rest)
+ note_rest (ident_sub_pat.get_locus ());
+ }
}
}
}
diff --git a/gcc/rust/hir/rust-ast-lower-pattern.cc
b/gcc/rust/hir/rust-ast-lower-pattern.cc
index b19a6411d..17d4dc981 100644
--- a/gcc/rust/hir/rust-ast-lower-pattern.cc
+++ b/gcc/rust/hir/rust-ast-lower-pattern.cc
@@ -353,17 +353,46 @@ void
ASTLoweringPattern::visit (AST::SlicePattern &pattern)
{
tl::optional<size_t> rest_index;
+ tl::optional<HIR::IdentifierPattern> rest_bind;
std::vector<std::unique_ptr<AST::Pattern>> &sub_patterns
= pattern.get_patterns ();
+ // need this earlier than usual
+ // since we might need to produce rest_bind
+ auto crate_num = mappings.get_current_crate ();
+
for (size_t i = 0; i < sub_patterns.size (); i++)
{
auto &pat = sub_patterns[i];
- if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest)
+
+ // ASTValidation verified there's only one Rest pattern
+ // so we can break once we find the first one
+ if (pat->get_pattern_kind () == AST::Pattern::Kind::Identifier)
+ {
+ auto &ident_pat = static_cast<AST::IdentifierPattern &> (*pat);
+ if (ident_pat.has_subpattern ())
+ {
+ if (ident_pat.get_subpattern ().get_pattern_kind ()
+ == AST::Pattern::Kind::Rest)
+ {
+ Analysis::NodeMapping rest_bind_mapping (
+ crate_num, ident_pat.get_node_id (),
+ mappings.get_next_hir_id (crate_num), UNKNOWN_LOCAL_DEFID);
+
+ rest_bind = HIR::IdentifierPattern (
+ std::move (rest_bind_mapping), ident_pat.get_ident (),
+ ident_pat.get_locus (), ident_pat.get_is_ref (),
+ ident_pat.get_is_mut () ? Mutability::Mut
+ : Mutability::Imm);
+ rest_index = i;
+ break;
+ }
+ }
+ }
+ else if (pat->get_pattern_kind () == AST::Pattern::Kind::Rest)
{
rest_index = i;
- // ASTValidation verified there's only one Rest pattern
break;
}
}
@@ -375,7 +404,8 @@ ASTLoweringPattern::visit (AST::SlicePattern &pattern)
auto rest_it = sub_patterns.begin () + *rest_index;
items = std::make_unique<HIR::SlicePatternItemsHasRest> (
lower_pattern_seq (sub_patterns.begin (), rest_it),
- lower_pattern_seq (rest_it + 1, sub_patterns.end ()));
+ lower_pattern_seq (rest_it + 1, sub_patterns.end ()),
+ std::move (rest_bind));
}
else
{
@@ -383,7 +413,6 @@ ASTLoweringPattern::visit (AST::SlicePattern &pattern)
lower_pattern_seq (sub_patterns.begin (), sub_patterns.end ()));
}
- auto crate_num = mappings.get_current_crate ();
Analysis::NodeMapping mapping (crate_num, pattern.get_node_id (),
mappings.get_next_hir_id (crate_num),
UNKNOWN_LOCAL_DEFID);
diff --git a/gcc/rust/hir/rust-hir-dump.cc b/gcc/rust/hir/rust-hir-dump.cc
index 29b3ff92a..f21522b4d 100644
--- a/gcc/rust/hir/rust-hir-dump.cc
+++ b/gcc/rust/hir/rust-hir-dump.cc
@@ -2375,6 +2375,8 @@ Dump::visit (SlicePatternItemsHasRest &e)
{
begin ("SlicePatternItemsHasRest");
visit_collection ("lower_patterns", e.get_lower_patterns ());
+ if (e.has_rest_bind ())
+ visit_field ("rest_bind", e.get_rest_bind ());
visit_collection ("upper_patterns", e.get_upper_patterns ());
end ("SlicePatternItemsHasRest");
}
diff --git a/gcc/rust/hir/tree/rust-hir-pattern.h
b/gcc/rust/hir/tree/rust-hir-pattern.h
index 90f8f5792..a56379d4a 100644
--- a/gcc/rust/hir/tree/rust-hir-pattern.h
+++ b/gcc/rust/hir/tree/rust-hir-pattern.h
@@ -1437,16 +1437,22 @@ class SlicePatternItemsHasRest : public
SlicePatternItems
std::vector<std::unique_ptr<Pattern>> lower_patterns;
std::vector<std::unique_ptr<Pattern>> upper_patterns;
+ // c in [a, b, c @ ..]
+ tl::optional<IdentifierPattern> rest_bind;
+
public:
SlicePatternItemsHasRest (
std::vector<std::unique_ptr<Pattern>> lower_patterns,
- std::vector<std::unique_ptr<Pattern>> upper_patterns)
+ std::vector<std::unique_ptr<Pattern>> upper_patterns,
+ tl::optional<IdentifierPattern> rest_bind)
: lower_patterns (std::move (lower_patterns)),
- upper_patterns (std::move (upper_patterns))
+ upper_patterns (std::move (upper_patterns)),
+ rest_bind (std::move (rest_bind))
{}
// Copy constructor with vector clone
SlicePatternItemsHasRest (SlicePatternItemsHasRest const &other)
+ : rest_bind (other.rest_bind)
{
lower_patterns.reserve (other.lower_patterns.size ());
for (const auto &e : other.lower_patterns)
@@ -1470,6 +1476,8 @@ public:
for (const auto &e : other.upper_patterns)
upper_patterns.push_back (e->clone_pattern ());
+ rest_bind = other.rest_bind;
+
return *this;
}
@@ -1502,6 +1510,20 @@ public:
return upper_patterns;
}
+ bool has_rest_bind () const { return rest_bind.has_value (); }
+
+ IdentifierPattern &get_rest_bind ()
+ {
+ rust_assert (has_rest_bind ());
+ return *rest_bind;
+ }
+
+ const IdentifierPattern &get_rest_bind () const
+ {
+ rust_assert (has_rest_bind ());
+ return *rest_bind;
+ }
+
protected:
/* Use covariance to implement clone function as returning this object rather
* than base */
diff --git a/gcc/rust/hir/tree/rust-hir-visitor.cc
b/gcc/rust/hir/tree/rust-hir-visitor.cc
index 00b46e742..544c83db8 100644
--- a/gcc/rust/hir/tree/rust-hir-visitor.cc
+++ b/gcc/rust/hir/tree/rust-hir-visitor.cc
@@ -1077,6 +1077,8 @@ DefaultHIRVisitor::walk (SlicePatternItemsHasRest &items)
{
for (auto &lower : items.get_lower_patterns ())
lower->accept_vis (*this);
+ if (items.has_rest_bind ())
+ items.get_rest_bind ().accept_vis (*this);
for (auto &upper : items.get_upper_patterns ())
upper->accept_vis (*this);
}
diff --git a/gcc/rust/hir/tree/rust-hir.cc b/gcc/rust/hir/tree/rust-hir.cc
index 51b588a02..7d611ed5c 100644
--- a/gcc/rust/hir/tree/rust-hir.cc
+++ b/gcc/rust/hir/tree/rust-hir.cc
@@ -2449,6 +2449,12 @@ SlicePatternItemsHasRest::to_string () const
}
}
+ str += "\n Rest binding pattern: ";
+ if (rest_bind)
+ str += rest_bind->to_string ();
+ else
+ str += "none";
+
str += "\n Upper patterns: ";
if (upper_patterns.empty ())
{
diff --git a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
index 7d12bc7b4..83104833d 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check-pattern.cc
@@ -942,6 +942,10 @@ TypeCheckPattern::visit (HIR::SlicePattern &pattern)
{
auto &ref
= static_cast<HIR::SlicePatternItemsHasRest &> (pattern.get_items ());
+
+ // TODO: support rest_bind (c in [a, b, c @ ..])
+ rust_assert (!ref.has_rest_bind ());
+
for (const auto &pattern_member : ref.get_lower_patterns ())
{
TypeCheckPattern::Resolve (*pattern_member, parent_element_ty);
diff --git a/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs
b/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs
new file mode 100644
index 000000000..10316f750
--- /dev/null
+++ b/gcc/testsuite/rust/compile/slice_rest_pattern_2.rs
@@ -0,0 +1,11 @@
+// { dg-additional-options "-frust-compile-until=typecheck" }
+#![feature(no_core)]
+#![no_core]
+
+pub fn foo(x: &[u8]) -> i32 {
+ match x {
+ [] => 0,
+ [1, xs @ ..] => foo (xs),
+ [x, ..] => *x as i32
+ }
+}
base-commit: 84167f9bff1edb231d611e9b851f27bd4fe79b9e
--
2.54.0