diff options
author | Mahmoud Mohamed <mahadelr19@gmail.com> | 2023-03-13 17:18:11 +0300 |
---|---|---|
committer | Philip Herron <philip.herron@embecosm.com> | 2023-03-15 11:14:06 +0000 |
commit | bed6308e5e5201f409b041ca5e712d1ed8839195 (patch) | |
tree | 6942925354d10bc41582450b190be07b57a8e2bb /gcc/rust/resolve | |
parent | fc0addd1ffae33478cfc838f93e6685c0cbfa08c (diff) | |
download | gcc-bed6308e5e5201f409b041ca5e712d1ed8839195.zip gcc-bed6308e5e5201f409b041ca5e712d1ed8839195.tar.gz gcc-bed6308e5e5201f409b041ca5e712d1ed8839195.tar.bz2 |
resolve: Handle multiple bindings to the same identifier
https://github.com/rust-lang/rust/blob/master/compiler/rustc_resolve/src/late.rs#L3168
This commit follows rustc's implementation of handling multiple bindings
to the same identifier in parameters.
gcc/rust/ChangeLog:
* resolve/rust-ast-resolve-expr.cc (ResolveExpr::visit) :declare and
pass bindings to PatternDeclaration::go.
(ResolveExpr::resolve_closure_param): Likewise.
* resolve/rust-ast-resolve-expr.h: Likewise.
* resolve/rust-ast-resolve-item.cc (ResolveTraitItems::visit): Likewise.
(ResolveItem::visit): Likewise.
* resolve/rust-ast-resolve-pattern.cc (PatternDeclaration::go): Likewise.
(PatternDeclaration::visit): check for previous identifier bindings
before inserting the new one.
* resolve/rust-ast-resolve-pattern.h (enum PatternBoundCtx): New enum.
* resolve/rust-ast-resolve-stmt.h: pass bindings to PatterDeclaration::go.
gcc/testsuite/ChangeLog:
* rust/compile/multiple_bindings1.rs: New test.
Signed-off-by: Mahmoud Mohamed <mahadelr19@gmail.com>
Diffstat (limited to 'gcc/rust/resolve')
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-expr.cc | 30 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-expr.h | 4 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-item.cc | 28 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-pattern.cc | 74 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-pattern.h | 60 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-stmt.h | 5 |
6 files changed, 154 insertions, 47 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 4dfc083..ff9f7ef 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.cc +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -207,9 +207,14 @@ ResolveExpr::visit (AST::IfLetExpr &expr) resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + // FIXME: this declaration should be removed after refactoring + // parse_match_arm_patterns output into an AltPattern + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Or, std::set<Identifier> ())}; + for (auto &pattern : expr.get_patterns ()) { - PatternDeclaration::go (pattern.get (), Rib::ItemType::Var); + PatternDeclaration::go (pattern.get (), Rib::ItemType::Var, bindings); } ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix); @@ -517,10 +522,15 @@ ResolveExpr::visit (AST::MatchExpr &expr) ResolveExpr::go (arm.get_guard_expr ().get (), prefix, canonical_prefix); + // FIXME: this declaration should be removed after refactoring + // parse_match_arms_patterns output into a single AltPattern + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Or, std::set<Identifier> ())}; + // insert any possible new patterns for (auto &pattern : arm.get_patterns ()) { - PatternDeclaration::go (pattern.get (), Rib::ItemType::Var); + PatternDeclaration::go (pattern.get (), Rib::ItemType::Var, bindings); } // resolve the body @@ -576,9 +586,12 @@ ResolveExpr::visit (AST::ClosureExprInner &expr) resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; + for (auto &p : expr.get_params ()) { - resolve_closure_param (p); + resolve_closure_param (p, bindings); } resolver->push_closure_context (expr.get_node_id ()); @@ -604,9 +617,12 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr) resolver->push_new_type_rib (resolver->get_type_scope ().peek ()); resolver->push_new_label_rib (resolver->get_type_scope ().peek ()); + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; + for (auto &p : expr.get_params ()) { - resolve_closure_param (p); + resolve_closure_param (p, bindings); } ResolveType::go (expr.get_return_type ().get ()); @@ -624,9 +640,11 @@ ResolveExpr::visit (AST::ClosureExprInnerTyped &expr) } void -ResolveExpr::resolve_closure_param (AST::ClosureParam ¶m) +ResolveExpr::resolve_closure_param (AST::ClosureParam ¶m, + std::vector<PatternBinding> &bindings) { - PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param); + PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param, + bindings); if (param.has_type_given ()) ResolveType::go (param.get_type ().get ()); diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 9e3e775..07b029f 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -20,6 +20,7 @@ #define RUST_AST_RESOLVE_EXPR_H #include "rust-ast-resolve-base.h" +#include "rust-ast-resolve-pattern.h" #include "rust-ast-full.h" namespace Rust { @@ -79,7 +80,8 @@ public: void visit (AST::ClosureExprInnerTyped &expr) override; protected: - void resolve_closure_param (AST::ClosureParam ¶m); + void resolve_closure_param (AST::ClosureParam ¶m, + std::vector<PatternBinding> &bindings); private: ResolveExpr (const CanonicalPath &prefix, diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc index 0be9a02..958ae49 100644 --- a/gcc/rust/resolve/rust-ast-resolve-item.cc +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -77,13 +77,16 @@ ResolveTraitItems::visit (AST::TraitItemFunc &func) if (function.has_return_type ()) ResolveType::go (function.get_return_type ().get ()); + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; + // we make a new scope so the names of parameters are resolved and shadowed // correctly for (auto ¶m : function.get_function_params ()) { ResolveType::go (param.get_type ().get ()); - PatternDeclaration::go (param.get_pattern ().get (), - Rib::ItemType::Param); + PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param, + bindings); } if (function.has_where_clause ()) @@ -141,13 +144,16 @@ ResolveTraitItems::visit (AST::TraitItemMethod &func) ResolveType::go (&self_type_path); PatternDeclaration::go (&self_pattern, Rib::ItemType::Param); + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; + // we make a new scope so the names of parameters are resolved and shadowed // correctly for (auto ¶m : function.get_function_params ()) { ResolveType::go (param.get_type ().get ()); - PatternDeclaration::go (param.get_pattern ().get (), - Rib::ItemType::Param); + PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param, + bindings); } if (function.has_where_clause ()) @@ -496,13 +502,16 @@ ResolveItem::visit (AST::Function &function) if (function.has_return_type ()) ResolveType::go (function.get_return_type ().get ()); + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; + // we make a new scope so the names of parameters are resolved and shadowed // correctly for (auto ¶m : function.get_function_params ()) { ResolveType::go (param.get_type ().get ()); - PatternDeclaration::go (param.get_pattern ().get (), - Rib::ItemType::Param); + PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param, + bindings); } // resolve the function body @@ -633,13 +642,16 @@ ResolveItem::visit (AST::Method &method) ResolveType::go (&self_type_path); PatternDeclaration::go (&self_pattern, Rib::ItemType::Param); + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; + // we make a new scope so the names of parameters are resolved and shadowed // correctly for (auto ¶m : method.get_function_params ()) { ResolveType::go (param.get_type ().get ()); - PatternDeclaration::go (param.get_pattern ().get (), - Rib::ItemType::Param); + PatternDeclaration::go (param.get_pattern ().get (), Rib::ItemType::Param, + bindings); } // resolve any where clause items diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc index 10f4fd8..866745e 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.cc +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc @@ -24,6 +24,78 @@ namespace Rust { namespace Resolver { void +PatternDeclaration::go (AST::Pattern *pattern, Rib::ItemType type) +{ + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; + PatternDeclaration resolver (bindings, type); + pattern->accept_vis (resolver); +}; + +void +PatternDeclaration::go (AST::Pattern *pattern, Rib::ItemType type, + std::vector<PatternBinding> &bindings) +{ + PatternDeclaration resolver (bindings, type); + pattern->accept_vis (resolver); +} + +void +PatternDeclaration::visit (AST::IdentifierPattern &pattern) +{ + bool has_binding_ctx = bindings.size () > 0; + rust_assert (has_binding_ctx); + + auto &binding_idents = bindings.back ().idents; + + bool current_ctx_is_product + = bindings.back ().ctx == PatternBoundCtx::Product; + bool identifier_is_product_bound + = current_ctx_is_product + && binding_idents.find (pattern.get_ident ()) != binding_idents.end (); + + if (identifier_is_product_bound) + { + if (type == Rib::ItemType::Param) + { + rust_error_at (pattern.get_locus (), ErrorCode ("E0415"), + "identifier '%s' is bound more than once in the " + "same parameter list", + pattern.get_ident ().c_str ()); + } + else + { + rust_error_at ( + pattern.get_locus (), ErrorCode ("E0416"), + "identifier '%s' is bound more than once in the same pattern", + pattern.get_ident ().c_str ()); + } + + return; + } + + // if we have a duplicate id this then allows for shadowing correctly + // as new refs to this decl will match back here so it is ok to overwrite + resolver->get_name_scope ().insert ( + CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()), + pattern.get_node_id (), pattern.get_locus (), type); + + binding_idents.insert (pattern.get_ident ()); +} + +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); @@ -49,7 +121,7 @@ PatternDeclaration::visit (AST::TupleStructPattern &pattern) for (auto &inner_pattern : items_no_range.get_patterns ()) { - PatternDeclaration::go (inner_pattern.get (), type); + inner_pattern.get ()->accept_vis (*this); } } break; diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h index 12d2b59..0ff500a 100644 --- a/gcc/rust/resolve/rust-ast-resolve-pattern.h +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h @@ -25,6 +25,26 @@ namespace Rust { namespace Resolver { +// Specifies whether the set of already bound patterns are related by 'Or' or +// 'Product'. Used to check for multiple bindings to the same identifier. +enum PatternBoundCtx +{ + // A product pattern context (e.g. struct and tuple patterns) + Product, + // An or-pattern context (e.g. p_0 | p_1 | ...) + Or, +}; + +struct PatternBinding +{ + PatternBoundCtx ctx; + std::set<Identifier> idents; + + PatternBinding (PatternBoundCtx ctx, std::set<Identifier> idents) + : ctx (ctx), idents (idents) + {} +}; + class ResolvePattern : public ResolverBase { using Rust::Resolver::ResolverBase::visit; @@ -55,45 +75,25 @@ class PatternDeclaration : public ResolverBase using Rust::Resolver::ResolverBase::visit; public: - static void go (AST::Pattern *pattern, Rib::ItemType type) - { - PatternDeclaration resolver (type); - pattern->accept_vis (resolver); - }; + static void go (AST::Pattern *pattern, Rib::ItemType type); + static void go (AST::Pattern *pattern, Rib::ItemType type, + std::vector<PatternBinding> &bindings); - void visit (AST::IdentifierPattern &pattern) override - { - // if we have a duplicate id this then allows for shadowing correctly - // as new refs to this decl will match back here so it is ok to overwrite - resolver->get_name_scope ().insert ( - CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()), - pattern.get_node_id (), pattern.get_locus (), type); - } - - void visit (AST::GroupedPattern &pattern) override - { - pattern.get_pattern_in_parens ()->accept_vis (*this); - } - - void visit (AST::ReferencePattern &pattern) override - { - pattern.get_referenced_pattern ()->accept_vis (*this); - } - - // cases in a match expression + void visit (AST::IdentifierPattern &pattern) override; + void visit (AST::GroupedPattern &pattern) override; + void visit (AST::ReferencePattern &pattern) override; void visit (AST::PathInExpression &pattern) override; - void visit (AST::StructPattern &pattern) override; - void visit (AST::TupleStructPattern &pattern) override; - void visit (AST::TuplePattern &pattern) override; - void visit (AST::RangePattern &pattern) override; private: - PatternDeclaration (Rib::ItemType type) : ResolverBase (), type (type) {} + PatternDeclaration (std::vector<PatternBinding> &bindings, Rib::ItemType type) + : ResolverBase (), bindings (bindings), type (type) + {} + std::vector<PatternBinding> &bindings; Rib::ItemType type; }; diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h index 28c547f..1336402 100644 --- a/gcc/rust/resolve/rust-ast-resolve-stmt.h +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h @@ -344,13 +344,16 @@ public: if (function.has_return_type ()) ResolveType::go (function.get_return_type ().get ()); + std::vector<PatternBinding> bindings + = {PatternBinding (PatternBoundCtx::Product, std::set<Identifier> ())}; + // we make a new scope so the names of parameters are resolved and shadowed // correctly for (auto ¶m : function.get_function_params ()) { ResolveType::go (param.get_type ().get ()); PatternDeclaration::go (param.get_pattern ().get (), - Rib::ItemType::Param); + Rib::ItemType::Param, bindings); } // resolve the function body |