From: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com> Binding context may be stacked when a new binding group is introduced within a const expression.
gcc/rust/ChangeLog: * resolve/rust-name-resolution-context.h: Use BindingLayer instead. * resolve/rust-name-resolution-context.cc (BindingLayer::BindingLayer): Add new constructor for binding layer. (BindingLayer::bind_test): Add a function to test a binding constraint. (BindingLayer::push): Push a new binding group. (BindingLayer::and_binded): Add function to test and-binding constraint. (BindingLayer::or_binded): Add function to test or-binding constraints. (BindingLayer::insert_ident): Insert a new identifier in the current binding group. (BindingLayer::merge): Merge current binding group with it's parent. (BindingLayer::get_source): Get the source of the current binding group. * resolve/rust-late-name-resolver-2.0.cc: Use stacked context for binding group. * util/rust-stacked-contexts.h: Add mutable peek function. Signed-off-by: Pierre-Emmanuel Patry <pierre-emmanuel.pa...@embecosm.com> --- .../resolve/rust-late-name-resolver-2.0.cc | 44 ++++++------ .../resolve/rust-name-resolution-context.cc | 59 +++++++++++++++ .../resolve/rust-name-resolution-context.h | 72 +++++++------------ gcc/rust/util/rust-stacked-contexts.h | 9 ++- 4 files changed, 113 insertions(+), 71 deletions(-) diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc index 1ecf48152d8..e26e4187b28 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -133,11 +133,11 @@ Late::visit (AST::ForLoopExpr &expr) { visit_outer_attrs (expr); - ctx.bindings.new_binding (BindingSource::For); + ctx.bindings.enter (BindingSource::For); visit (expr.get_pattern ()); - ctx.bindings.clear (); + ctx.bindings.exit (); visit (expr.get_iterator_expr ()); visit (expr.get_loop_label ()); @@ -149,12 +149,12 @@ Late::visit (AST::IfLetExpr &expr) { visit_outer_attrs (expr); - ctx.bindings.new_binding (BindingSource::Let); + ctx.bindings.enter (BindingSource::Let); for (auto &pattern : expr.get_patterns ()) visit (pattern); - ctx.bindings.clear (); + ctx.bindings.exit (); visit (expr.get_value_expr ()); visit (expr.get_if_block ()); @@ -165,12 +165,12 @@ Late::visit (AST::MatchArm &arm) { visit_outer_attrs (arm); - ctx.bindings.new_binding (BindingSource::Match); + ctx.bindings.enter (BindingSource::Match); for (auto &pattern : arm.get_patterns ()) visit (pattern); - ctx.bindings.clear (); + ctx.bindings.exit (); if (arm.has_match_arm_guard ()) visit (arm.get_guard_expr ()); @@ -187,11 +187,11 @@ Late::visit (AST::LetStmt &let) if (let.has_init_expr ()) visit (let.get_init_expr ()); - ctx.bindings.new_binding (BindingSource::Let); + ctx.bindings.enter (BindingSource::Let); visit (let.get_pattern ()); - ctx.bindings.clear (); + ctx.bindings.exit (); if (let.has_else_expr ()) visit (let.get_init_expr ()); @@ -220,9 +220,9 @@ Late::visit (AST::IdentifierPattern &identifier) // but values does not allow shadowing... since functions cannot shadow // do we insert functions in labels as well? - if (ctx.bindings.and_binded (identifier.get_ident ())) + if (ctx.bindings.peek ().is_and_bound (identifier.get_ident ())) { - if (ctx.bindings.get_source () == BindingSource::Param) + if (ctx.bindings.peek ().get_source () == BindingSource::Param) rust_error_at ( identifier.get_locus (), ErrorCode::E0415, "identifier %qs is bound more than once in the same parameter list", @@ -235,9 +235,9 @@ Late::visit (AST::IdentifierPattern &identifier) return; } - ctx.bindings.insert_ident (identifier.get_ident ()); + ctx.bindings.peek ().insert_ident (identifier.get_ident ()); - if (ctx.bindings.or_binded (identifier.get_ident ())) + if (ctx.bindings.peek ().is_or_bound (identifier.get_ident ())) { // FIXME: map usage instead std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), @@ -255,14 +255,14 @@ Late::visit (AST::IdentifierPattern &identifier) void Late::visit (AST::AltPattern &pattern) { - ctx.bindings.push (Binding::Kind::Or); + ctx.bindings.peek ().push (Binding::Kind::Or); for (auto &alt : pattern.get_alts ()) { - ctx.bindings.push (Binding::Kind::Product); + ctx.bindings.peek ().push (Binding::Kind::Product); visit (alt); - ctx.bindings.merge (); + ctx.bindings.peek ().merge (); } - ctx.bindings.merge (); + ctx.bindings.peek ().merge (); } void @@ -276,12 +276,12 @@ Late::visit (AST::Function &function) visit (generic); // We only care about params - ctx.bindings.new_binding (BindingSource::Param); + ctx.bindings.enter (BindingSource::Param); for (auto ¶m : function.get_function_params ()) visit (param); - ctx.bindings.clear (); + ctx.bindings.exit (); // Back to regular visit @@ -652,12 +652,12 @@ Late::visit (AST::ClosureExprInner &closure) visit_outer_attrs (closure); - ctx.bindings.new_binding (BindingSource::Param); + ctx.bindings.enter (BindingSource::Param); for (auto ¶m : closure.get_params ()) visit (param); - ctx.bindings.clear (); + ctx.bindings.exit (); visit (closure.get_definition_expr ()); } @@ -669,12 +669,12 @@ Late::visit (AST::ClosureExprInnerTyped &closure) visit_outer_attrs (closure); - ctx.bindings.new_binding (BindingSource::Param); + ctx.bindings.enter (BindingSource::Param); for (auto ¶m : closure.get_params ()) visit (param); - ctx.bindings.clear (); + ctx.bindings.exit (); visit (closure.get_return_type ()); visit (closure.get_definition_block ()); diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 92c48633e56..f098e4880e5 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.cc +++ b/gcc/rust/resolve/rust-name-resolution-context.cc @@ -23,6 +23,65 @@ namespace Rust { namespace Resolver2_0 { +BindingLayer::BindingLayer (BindingSource source) : source (source) +{ + push (Binding::Kind::Product); +} + +bool +BindingLayer::bind_test (Identifier ident, Binding::Kind kind) +{ + for (auto &bind : bindings) + { + if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) + { + return true; + } + } + return false; +} + +void +BindingLayer::push (Binding::Kind kind) +{ + bindings.push_back (Binding (kind)); +} + +bool +BindingLayer::is_and_bound (Identifier ident) +{ + return bind_test (ident, Binding::Kind::Product); +} + +bool +BindingLayer::is_or_bound (Identifier ident) +{ + return bind_test (ident, Binding::Kind::Or); +} + +void +BindingLayer::insert_ident (Identifier ident) +{ + bindings.back ().set.insert (ident); +} + +void +BindingLayer::merge () +{ + auto last_binding = bindings.back (); + bindings.pop_back (); + for (auto &value : last_binding.set) + { + bindings.back ().set.insert (value); + } +} + +BindingSource +BindingLayer::get_source () const +{ + return source; +} + NameResolutionContext::NameResolutionContext () : mappings (Analysis::Mappings::get ()) {} diff --git a/gcc/rust/resolve/rust-name-resolution-context.h b/gcc/rust/resolve/rust-name-resolution-context.h index 657d1512fe8..19ba7507686 100644 --- a/gcc/rust/resolve/rust-name-resolution-context.h +++ b/gcc/rust/resolve/rust-name-resolution-context.h @@ -23,6 +23,7 @@ #include "rust-forever-stack.h" #include "rust-hir-map.h" #include "rust-rib.h" +#include "rust-stacked-contexts.h" namespace Rust { namespace Resolver2_0 { @@ -169,72 +170,47 @@ struct Binding Binding (Binding::Kind kind) : kind (kind) {} }; +/** + * Used to identify the source of a binding, and emit the correct error message. + */ enum class BindingSource { Match, Let, For, + /* Closure param or function param */ Param }; -class BindingContext +class BindingLayer { - // FIXME: Use std::vector<std::vector<Binding>> to handle nested patterns - std::vector<Binding> bindings; - BindingSource source; + std::vector<Binding> bindings; - bool bind_test (Identifier ident, Binding::Kind kind) - { - for (auto &bind : bindings) - { - if (bind.set.find (ident) != bind.set.cend () && bind.kind == kind) - { - return true; - } - } - return false; - } + bool bind_test (Identifier ident, Binding::Kind kind); public: - bool and_binded (Identifier ident) - { - return bind_test (ident, Binding::Kind::Product); - } + void push (Binding::Kind kind); - bool or_binded (Identifier ident) - { - return bind_test (ident, Binding::Kind::Or); - } + BindingLayer (BindingSource source); - void insert_ident (Identifier ident) { bindings.back ().set.insert (ident); } + /** + * Identifies if the identifier has been used in a product binding context. + * eg. `let (a, a) = test();` + */ + bool is_and_bound (Identifier ident); - void push (Binding::Kind kind) { bindings.push_back (Binding (kind)); } + /** + * Identifies if the identifier has been used in a or context. + * eg. `let (a, 1) | (a, 2) = test()` + */ + bool is_or_bound (Identifier ident); - void new_binding (BindingSource source) - { - rust_assert (bindings.size () == 0); - this->source = source; - push (Binding::Kind::Product); - } + void insert_ident (Identifier ident); - void clear () - { - rust_assert (bindings.size () == 1); - bindings.clear (); - } - - void merge () - { - auto last_binding = bindings.back (); - bindings.pop_back (); - for (auto &value : last_binding.set) - { - bindings.back ().set.insert (value); - } - } + void merge (); - BindingSource get_source () const { return source; } + BindingSource get_source () const; }; // Now our resolver, which keeps track of all the `ForeverStack`s we could want @@ -293,7 +269,7 @@ public: ForeverStack<Namespace::Labels> labels; Analysis::Mappings &mappings; - BindingContext bindings; + StackedContexts<BindingLayer> bindings; // TODO: Rename // TODO: Use newtype pattern for Usage and Definition diff --git a/gcc/rust/util/rust-stacked-contexts.h b/gcc/rust/util/rust-stacked-contexts.h index fe0bc8a291b..b263d75d2d5 100644 --- a/gcc/rust/util/rust-stacked-contexts.h +++ b/gcc/rust/util/rust-stacked-contexts.h @@ -71,7 +71,14 @@ public: return last; } - const T &peek () + const T &peek () const + { + rust_assert (!stack.empty ()); + + return stack.back (); + } + + T &peek () { rust_assert (!stack.empty ()); -- 2.49.0