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>
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);
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
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 ());
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 ());
}
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 ());
#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 {
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,
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 ())
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 ())
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
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
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)
{
for (auto &inner_pattern : items_no_range.get_patterns ())
{
- PatternDeclaration::go (inner_pattern.get (), type);
+ inner_pattern.get ()->accept_vis (*this);
}
}
break;
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;
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;
};
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
--- /dev/null
+fn f1(i: i32, i: i32) {}
+// { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+
+trait Foo {
+ fn f2(i: i32, i: i32) {}
+ // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+}
+
+trait Bar {
+ fn f3(i: i32, j: i32) {}
+}
+
+struct S;
+
+impl S {
+ fn f4(i: i32, i: i32) {}
+ // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+}
+
+impl Bar for S {
+ fn f3(i: i32, i: i32) {}
+ // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+}
+
+fn main() {
+ let _ = |i, i| {};
+ // { dg-error "identifier .i. is bound more than once in the same parameter list .E0415." "" { target *-*-* } .-1 }
+}
+