aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/resolve/rust-ast-resolve-pattern.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/resolve/rust-ast-resolve-pattern.cc')
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-pattern.cc419
1 files changed, 0 insertions, 419 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc
deleted file mode 100644
index 3b80f9f..0000000
--- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc
+++ /dev/null
@@ -1,419 +0,0 @@
-// Copyright (C) 2020-2025 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-ast-resolve-pattern.h"
-#include "rust-ast-resolve-path.h"
-
-namespace Rust {
-namespace Resolver {
-
-void
-PatternDeclaration::go (AST::Pattern &pattern, Rib::ItemType type)
-{
- std::vector<PatternBinding> bindings
- = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())};
- PatternDeclaration::go (pattern, type, bindings);
-}
-
-void
-PatternDeclaration::go (AST::Pattern &pattern, Rib::ItemType type,
- std::vector<PatternBinding> &bindings)
-{
- PatternDeclaration resolver (bindings, type);
- pattern.accept_vis (resolver);
-
- for (auto &map_entry : resolver.missing_bindings)
- {
- auto ident = map_entry.first; // key
- auto info = map_entry.second; // value
-
- rust_error_at (info.get_locus (), ErrorCode::E0408,
- "variable '%s' is not bound in all patterns",
- ident.as_string ().c_str ());
- }
-
- for (auto &map_entry : resolver.inconsistent_bindings)
- {
- auto ident = map_entry.first; // key
- auto info = map_entry.second; // value
-
- rust_error_at (
- info.get_locus (), ErrorCode::E0409,
- "variable '%s' is bound inconsistently across pattern alternatives",
- ident.as_string ().c_str ());
- }
-}
-
-void
-PatternDeclaration::visit (AST::IdentifierPattern &pattern)
-{
- if (pattern.has_subpattern ())
- {
- pattern.get_subpattern ().accept_vis (*this);
- }
-
- Mutability mut = pattern.get_is_mut () ? Mutability::Mut : Mutability::Imm;
- add_new_binding (pattern.get_ident (), pattern.get_node_id (),
- BindingTypeInfo (mut, pattern.get_is_ref (),
- pattern.get_locus ()));
-}
-
-void
-PatternDeclaration::visit (AST::GroupedPattern &pattern)
-{
- pattern.get_pattern_in_parens ().accept_vis (*this);
-}
-
-void
-PatternDeclaration::visit (AST::ReferencePattern &pattern)
-{
- pattern.get_referenced_pattern ().accept_vis (*this);
-}
-
-void
-PatternDeclaration::visit (AST::PathInExpression &pattern)
-{
- ResolvePath::go (pattern);
-}
-
-void
-PatternDeclaration::visit (AST::TupleStructPattern &pattern)
-{
- ResolvePath::go (pattern.get_path ());
-
- AST::TupleStructItems &items = pattern.get_items ();
- switch (items.get_item_type ())
- {
- case AST::TupleStructItems::RANGE:
- {
- // TODO
- rust_unreachable ();
- }
- break;
-
- case AST::TupleStructItems::NO_RANGE:
- {
- auto &items_no_range
- = static_cast<AST::TupleStructItemsNoRange &> (items);
-
- for (auto &inner_pattern : items_no_range.get_patterns ())
- {
- inner_pattern->accept_vis (*this);
- }
- }
- break;
- }
-}
-
-void
-PatternDeclaration::visit (AST::StructPattern &pattern)
-{
- ResolvePath::go (pattern.get_path ());
-
- auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
- for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
- {
- switch (field->get_item_type ())
- {
- case AST::StructPatternField::ItemType::TUPLE_PAT:
- {
- AST::StructPatternFieldTuplePat &tuple
- = static_cast<AST::StructPatternFieldTuplePat &> (*field);
-
- tuple.get_index_pattern ().accept_vis (*this);
- }
- break;
-
- case AST::StructPatternField::ItemType::IDENT_PAT:
- {
- AST::StructPatternFieldIdentPat &ident
- = static_cast<AST::StructPatternFieldIdentPat &> (*field);
-
- ident.get_ident_pattern ().accept_vis (*this);
- }
- break;
-
- case AST::StructPatternField::ItemType::IDENT:
- {
- auto &ident = static_cast<AST::StructPatternFieldIdent &> (*field);
-
- Mutability mut
- = ident.is_mut () ? Mutability::Mut : Mutability::Imm;
-
- add_new_binding (ident.get_identifier (), ident.get_node_id (),
- BindingTypeInfo (mut, ident.is_ref (),
- ident.get_locus ()));
- }
- break;
- }
- }
-}
-
-void
-PatternDeclaration::visit (AST::TuplePattern &pattern)
-{
- auto &items = pattern.get_items ();
- switch (items.get_pattern_type ())
- {
- case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE:
- {
- auto &ref = static_cast<AST::TuplePatternItemsMultiple &> (
- pattern.get_items ());
-
- for (auto &p : ref.get_patterns ())
- p->accept_vis (*this);
- }
- break;
-
- case AST::TuplePatternItems::TuplePatternItemType::RANGED:
- {
- auto &ref
- = static_cast<AST::TuplePatternItemsRanged &> (pattern.get_items ());
-
- for (auto &p : ref.get_lower_patterns ())
- p->accept_vis (*this);
- for (auto &p : ref.get_upper_patterns ())
- p->accept_vis (*this);
- }
- break;
- }
-}
-
-void
-PatternDeclaration::visit (AST::AltPattern &pattern)
-{
- // push a new set of 'Or' bindings to the stack. Accounts for the
- // alternatives. e.g. in `p_0 | p_1`, bindings to the same identifier between
- // p_0 and p_1 shouldn't cause an error.
- bindings_with_ctx.push_back (
- PatternBinding (PatternBoundCtx::Or, std::set<Identifier> ()));
-
- // This is a hack to avoid creating a separate visitor class for the
- // consistency checks. We empty out the binding_info_map before each iteration
- // to separate between the alts' binding_maps. And right after the alt
- // visit...
- auto tmp_binding_map = binding_info_map;
- binding_info_map.clear ();
-
- std::vector<BindingMap> alts_binding_maps;
-
- for (auto &alt : pattern.get_alts ())
- {
- // before this visit, the binding_info_map is guaranteed to be empty
- rust_assert (binding_info_map.empty ());
-
- // push a new `Product` context to correctly reject multiple bindings
- // within this single alt.
- bindings_with_ctx.push_back (
- PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ()));
-
- alt->accept_vis (*this);
-
- // ...the binding_info_map is (potentially) populated. We copy it to the
- // vector, and empty it out to be ready for the next iteration. And after
- // all the iterations are finished...
- alts_binding_maps.push_back (binding_info_map);
- binding_info_map.clear ();
-
- // Remove the last (i.e. `Product`) context and add the bindings from the
- // visited alt to the one before last (i.e. `Or`). Now (after checking
- // with the alt internally), the bindings from this alt will reside in the
- // `Or` context.
- auto last_bound_idents = bindings_with_ctx.back ().idents;
- bindings_with_ctx.pop_back ();
-
- for (auto &ident : last_bound_idents)
- {
- bindings_with_ctx.back ().idents.insert (ident);
- }
- }
-
- // Now we can finally check for consistency.
- check_bindings_consistency (alts_binding_maps);
-
- // Now we remove the `Or` context we pushed earlier.
- // e.g. in `(a, (p_0 | p_1), c)`: after finishing up inside the alt pattern,
- // we return to the tuple (`Product`) context and push the new bindings.
- auto idents = bindings_with_ctx.back ().idents;
- bindings_with_ctx.pop_back ();
- for (auto &ident : idents)
- bindings_with_ctx.back ().idents.insert (ident.as_string ());
-
- // ...we repopulate the binding_info_map correctly (the initial bindings
- // stored in the tmp_binding_map + all the bindings from all the alts)
- binding_info_map = tmp_binding_map;
- for (auto &alt_map : alts_binding_maps)
- for (auto &map_entry : alt_map)
- binding_info_map.insert (map_entry);
-}
-
-void
-PatternDeclaration::add_new_binding (Identifier ident, NodeId node_id,
- BindingTypeInfo info)
-{
- bool has_binding_ctx = bindings_with_ctx.size () > 0;
- rust_assert (has_binding_ctx);
-
- bool identifier_or_bound = false, identifier_product_bound = false;
-
- for (auto binding : bindings_with_ctx)
- {
- bool identifier_bound_here
- = (binding.idents.find (ident) != binding.idents.end ());
- if (identifier_bound_here)
- {
- identifier_product_bound |= binding.ctx == PatternBoundCtx::Product;
- identifier_or_bound |= binding.ctx == PatternBoundCtx::Or;
- }
- }
-
- if (identifier_product_bound)
- {
- if (type == Rib::ItemType::Param)
- {
- rust_error_at (info.get_locus (), ErrorCode::E0415,
- "identifier '%s' is bound more than once in the "
- "same parameter list",
- ident.as_string ().c_str ());
- }
- else
- {
- rust_error_at (
- info.get_locus (), ErrorCode::E0416,
- "identifier '%s' is bound more than once in the same pattern",
- ident.as_string ().c_str ());
- }
-
- return;
- }
-
- if (!identifier_or_bound)
- {
- bindings_with_ctx.back ().idents.insert (ident);
- resolver->get_name_scope ().insert (
- CanonicalPath::new_seg (node_id, ident.as_string ()), node_id,
- info.get_locus (), type);
- }
-
- binding_info_map.insert ({ident, info});
-}
-
-// Verifies that all the alts in an AltPattern have the same set of bindings
-// with the same mutability and reference states.
-void
-PatternDeclaration::check_bindings_consistency (
- std::vector<BindingMap> &binding_maps)
-{
- for (size_t i = 0; i < binding_maps.size (); i++)
- {
- auto &outer_bindings_map = binding_maps[i];
-
- for (size_t j = 0; j < binding_maps.size (); j++)
- {
- // skip comparing the current outer map with itself.
- if (j == i)
- continue;
-
- auto &inner_bindings_map = binding_maps[j];
-
- // iterate over the inner map entries and check if they exist in outer
- // map
- for (auto map_entry : inner_bindings_map)
- {
- auto ident = map_entry.first; // key
- auto inner_info = map_entry.second; // value
- bool ident_is_outer_bound = outer_bindings_map.count (ident);
-
- if (!ident_is_outer_bound && !missing_bindings.count (ident))
- missing_bindings.insert ({ident, inner_info});
-
- else if (outer_bindings_map.count (ident)
- && outer_bindings_map[ident] != inner_info
- && !inconsistent_bindings.count (ident))
- inconsistent_bindings.insert ({ident, inner_info});
- }
- }
- }
-}
-
-static void
-resolve_range_pattern_bound (AST::RangePatternBound &bound)
-{
- switch (bound.get_bound_type ())
- {
- case AST::RangePatternBound::RangePatternBoundType::LITERAL:
- // Nothing to resolve for a literal.
- break;
-
- case AST::RangePatternBound::RangePatternBoundType::PATH:
- {
- auto &ref = static_cast<AST::RangePatternBoundPath &> (bound);
-
- ResolvePath::go (ref.get_path ());
- }
- break;
-
- case AST::RangePatternBound::RangePatternBoundType::QUALPATH:
- {
- auto &ref = static_cast<AST::RangePatternBoundQualPath &> (bound);
-
- ResolvePath::go (ref.get_qualified_path ());
- }
- break;
- }
-}
-
-void
-PatternDeclaration::visit (AST::RangePattern &pattern)
-{
- resolve_range_pattern_bound (pattern.get_upper_bound ());
- resolve_range_pattern_bound (pattern.get_lower_bound ());
-}
-
-void
-PatternDeclaration::visit (AST::SlicePattern &pattern)
-{
- auto &items = pattern.get_items ();
- switch (items.get_pattern_type ())
- {
- case AST::SlicePatternItems::SlicePatternItemType::NO_REST:
- {
- auto &ref
- = static_cast<AST::SlicePatternItemsNoRest &> (pattern.get_items ());
-
- for (auto &p : ref.get_patterns ())
- p->accept_vis (*this);
- }
- break;
-
- case AST::SlicePatternItems::SlicePatternItemType::HAS_REST:
- {
- auto &ref
- = static_cast<AST::SlicePatternItemsHasRest &> (pattern.get_items ());
-
- for (auto &p : ref.get_lower_patterns ())
- p->accept_vis (*this);
- for (auto &p : ref.get_upper_patterns ())
- p->accept_vis (*this);
- }
- break;
- }
-}
-
-} // namespace Resolver
-} // namespace Rust