aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMahmoud Mohamed <mahadelr19@gmail.com>2023-03-13 17:18:11 +0300
committerPhilip Herron <philip.herron@embecosm.com>2023-03-15 11:14:06 +0000
commitbed6308e5e5201f409b041ca5e712d1ed8839195 (patch)
tree6942925354d10bc41582450b190be07b57a8e2bb
parentfc0addd1ffae33478cfc838f93e6685c0cbfa08c (diff)
downloadgcc-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>
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.cc30
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-expr.h4
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-item.cc28
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-pattern.cc74
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-pattern.h60
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-stmt.h5
-rw-r--r--gcc/testsuite/rust/compile/multiple_bindings1.rs29
7 files changed, 183 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 &param)
+ResolveExpr::resolve_closure_param (AST::ClosureParam &param,
+ 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 &param);
+ void resolve_closure_param (AST::ClosureParam &param,
+ 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 &param : 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 &param : 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 &param : 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 &param : 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 &param : 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
diff --git a/gcc/testsuite/rust/compile/multiple_bindings1.rs b/gcc/testsuite/rust/compile/multiple_bindings1.rs
new file mode 100644
index 0000000..e73dc2a
--- /dev/null
+++ b/gcc/testsuite/rust/compile/multiple_bindings1.rs
@@ -0,0 +1,29 @@
+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 }
+}
+