diff options
Diffstat (limited to 'gcc/rust/resolve')
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-base.cc | 4 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-base.h | 1 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-expr.cc | 11 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-expr.h | 1 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-path.cc | 8 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-type.cc | 3 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-ast-resolve-type.h | 4 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-default-resolver.cc | 8 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-default-resolver.h | 2 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-early-name-resolver-2.0.cc | 9 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-early-name-resolver-2.0.h | 16 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-forever-stack.h | 24 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-forever-stack.hxx | 44 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-late-name-resolver-2.0.cc | 153 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-late-name-resolver-2.0.h | 8 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-name-resolution-context.cc | 59 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-name-resolution-context.h | 145 | ||||
-rw-r--r-- | gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc | 5 |
18 files changed, 439 insertions, 66 deletions
diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc index 6c35a22..b781ce33 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.cc +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -328,6 +328,10 @@ ResolverBase::visit (AST::InlineAsm &) {} void +ResolverBase::visit (AST::LlvmInlineAsm &) +{} + +void ResolverBase::visit (AST::TypeParam &) {} diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h index ab74e84..5bb9e4f 100644 --- a/gcc/rust/resolve/rust-ast-resolve-base.h +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -110,6 +110,7 @@ public: void visit (AST::AwaitExpr &); void visit (AST::AsyncBlockExpr &); void visit (AST::InlineAsm &); + void visit (AST::LlvmInlineAsm &); void visit (AST::TypeParam &); diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc index 8070fc1..6242235 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.cc +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -368,6 +368,17 @@ ResolveExpr::visit (AST::InlineAsm &expr) { translate_operand (expr, prefix, canonical_prefix); } + +void +ResolveExpr::visit (AST::LlvmInlineAsm &expr) +{ + for (auto &output : expr.get_outputs ()) + ResolveExpr::go (*output.expr, prefix, canonical_prefix); + + for (auto &input : expr.get_inputs ()) + ResolveExpr::go (*input.expr, prefix, canonical_prefix); +} + void ResolveExpr::visit (AST::UnsafeBlockExpr &expr) { diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h index 562a3bd..b296d66 100644 --- a/gcc/rust/resolve/rust-ast-resolve-expr.h +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -57,6 +57,7 @@ public: void visit (AST::IfLetExprConseqElse &expr) override; void visit (AST::BlockExpr &expr) override; void visit (AST::InlineAsm &expr) override; + void visit (AST::LlvmInlineAsm &expr) override; void visit (AST::UnsafeBlockExpr &expr) override; void visit (AST::ArrayElemsValues &elems) override; void visit (AST::ArrayExpr &expr) override; diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc index 530926d..fb6715d 100644 --- a/gcc/rust/resolve/rust-ast-resolve-path.cc +++ b/gcc/rust/resolve/rust-ast-resolve-path.cc @@ -68,8 +68,7 @@ ResolvePath::resolve_path (AST::PathInExpression &expr) if (in_middle_of_path && segment.is_lower_self_seg ()) { rust_error_at (segment.get_locus (), ErrorCode::E0433, - "leading path segment %qs can only be used at the " - "beginning of a path", + "%qs in paths can only be used in start position", segment.as_string ().c_str ()); return UNKNOWN_NODEID; } @@ -372,8 +371,9 @@ ResolvePath::resolve_path (AST::SimplePath &expr) { if (!is_first_segment) { - rust_error_at (segment.get_locus (), - "%<super%> can only be used in start position"); + rust_error_at ( + segment.get_locus (), ErrorCode::E0433, + "%<super%> in paths can only be used in start position"); return UNKNOWN_NODEID; } if (module_scope_id == crate_scope_id) diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc index 606141c..8fd69c3 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.cc +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -176,8 +176,7 @@ ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id) if (in_middle_of_path && segment->is_lower_self_seg ()) { rust_error_at (segment->get_locus (), ErrorCode::E0433, - "leading path segment %qs can only be used at the " - "beginning of a path", + "%qs in paths can only be used in start position", segment->as_string ().c_str ()); return false; } diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h index 8379d0e..f1481fc 100644 --- a/gcc/rust/resolve/rust-ast-resolve-type.h +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -141,8 +141,8 @@ public: if (first_pass) ResolveType::go (param.get_type ()); else if (param.has_default_value ()) - ResolveExpr::go (param.get_default_value ().get_expression (), prefix, - canonical_prefix); + ResolveExpr::go (param.get_default_value_unchecked ().get_expression (), + prefix, canonical_prefix); } void visit (AST::TypeParam ¶m) override diff --git a/gcc/rust/resolve/rust-default-resolver.cc b/gcc/rust/resolve/rust-default-resolver.cc index 7528e79..480034c 100644 --- a/gcc/rust/resolve/rust-default-resolver.cc +++ b/gcc/rust/resolve/rust-default-resolver.cc @@ -179,5 +179,13 @@ DefaultResolver::visit (AST::StaticItem &item) ctx.scoped (Rib::Kind::ConstantItem, item.get_node_id (), expr_vis); } +void +DefaultResolver::visit (AST::TypeParam ¶m) +{ + auto expr_vis = [this, ¶m] () { AST::DefaultASTVisitor::visit (param); }; + + ctx.scoped (Rib::Kind::ForwardTypeParamBan, param.get_node_id (), expr_vis); +} + } // namespace Resolver2_0 } // namespace Rust diff --git a/gcc/rust/resolve/rust-default-resolver.h b/gcc/rust/resolve/rust-default-resolver.h index 587d7d4..2a987ef 100644 --- a/gcc/rust/resolve/rust-default-resolver.h +++ b/gcc/rust/resolve/rust-default-resolver.h @@ -50,6 +50,8 @@ public: void visit (AST::InherentImpl &) override; void visit (AST::TraitImpl &) override; + void visit (AST::TypeParam &) override; + // type dec nodes, which visit their fields or variants by default void visit (AST::StructStruct &) override; void visit (AST::TupleStruct &) override; diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc index 36456e1..3390f09 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.cc @@ -70,8 +70,7 @@ Early::go (AST::Crate &crate) bool Early::resolve_glob_import (NodeId use_dec_id, TopLevel::ImportKind &&glob) { - auto resolved - = ctx.resolve_path (glob.to_resolve.get_segments (), Namespace::Types); + auto resolved = ctx.resolve_path (glob.to_resolve, Namespace::Types); if (!resolved.has_value ()) return false; @@ -141,6 +140,10 @@ Early::build_import_mapping ( // be moved into the newly created import mappings auto path = import.to_resolve; + // used to skip the "unresolved import" error + // if we output other errors during resolution + size_t old_error_count = macro_resolve_errors.size (); + switch (import.kind) { case TopLevel::ImportKind::Kind::Glob: @@ -154,7 +157,7 @@ Early::build_import_mapping ( break; } - if (!found) + if (!found && old_error_count == macro_resolve_errors.size ()) collect_error (Error (path.get_final_segment ().get_locus (), ErrorCode::E0433, "unresolved import %qs", path.as_string ().c_str ())); diff --git a/gcc/rust/resolve/rust-early-name-resolver-2.0.h b/gcc/rust/resolve/rust-early-name-resolver-2.0.h index c4226fe..e78bec0 100644 --- a/gcc/rust/resolve/rust-early-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-early-name-resolver-2.0.h @@ -218,7 +218,6 @@ private: std::vector<std::pair<Rib::Definition, Namespace>> resolve_path_in_all_ns (const P &path) { - const auto &segments = path.get_segments (); std::vector<std::pair<Rib::Definition, Namespace>> resolved; // Pair a definition with the namespace it was found in @@ -229,13 +228,22 @@ private: }; }; - ctx.resolve_path (segments, Namespace::Values) + std::vector<Error> value_errors; + std::vector<Error> type_errors; + std::vector<Error> macro_errors; + + ctx.resolve_path (path, value_errors, Namespace::Values) .map (pair_with_ns (Namespace::Values)); - ctx.resolve_path (segments, Namespace::Types) + ctx.resolve_path (path, type_errors, Namespace::Types) .map (pair_with_ns (Namespace::Types)); - ctx.resolve_path (segments, Namespace::Macros) + ctx.resolve_path (path, macro_errors, Namespace::Macros) .map (pair_with_ns (Namespace::Macros)); + if (!value_errors.empty () && !type_errors.empty () + && !macro_errors.empty ()) + for (auto &ent : value_errors) + collect_error (std::move (ent)); + return resolved; } diff --git a/gcc/rust/resolve/rust-forever-stack.h b/gcc/rust/resolve/rust-forever-stack.h index cf02651..81468e5 100644 --- a/gcc/rust/resolve/rust-forever-stack.h +++ b/gcc/rust/resolve/rust-forever-stack.h @@ -673,7 +673,8 @@ public: template <typename S> tl::optional<Rib::Definition> resolve_path ( const std::vector<S> &segments, bool has_opening_scope_resolution, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); // FIXME: Documentation tl::optional<Resolver::CanonicalPath> to_canonical_path (NodeId id) const; @@ -792,13 +793,15 @@ private: tl::optional<SegIterator<S>> find_starting_point ( const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); template <typename S> tl::optional<Node &> resolve_segments ( Node &starting_point, const std::vector<S> &segments, SegIterator<S> iterator, - std::function<void (const S &, NodeId)> insert_segment_resolution); + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors); tl::optional<Rib::Definition> resolve_final_segment (Node &final_node, std::string &seg_name, @@ -828,6 +831,21 @@ private: tl::optional<Node &> dfs_node (Node &starting_point, NodeId to_find); tl::optional<const Node &> dfs_node (const Node &starting_point, NodeId to_find) const; + +public: + bool forward_declared (NodeId definition, NodeId usage) + { + if (peek ().kind != Rib::Kind::ForwardTypeParamBan) + return false; + + const auto &definition_rib = dfs_rib (cursor (), definition); + + if (!definition_rib) + return false; + + return (definition_rib + && definition_rib.value ().kind == Rib::Kind::ForwardTypeParamBan); + } }; } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-forever-stack.hxx b/gcc/rust/resolve/rust-forever-stack.hxx index 993e2d4..069111ee 100644 --- a/gcc/rust/resolve/rust-forever-stack.hxx +++ b/gcc/rust/resolve/rust-forever-stack.hxx @@ -398,12 +398,13 @@ ForeverStack<N>::find_closest_module (Node &starting_point) * segments */ template <typename S> static inline bool -check_leading_kw_at_start (const S &segment, bool condition) +check_leading_kw_at_start (std::vector<Error> &collect_errors, const S &segment, + bool condition) { if (condition) - rust_error_at ( + collect_errors.emplace_back ( segment.get_locus (), ErrorCode::E0433, - "leading path segment %qs can only be used at the beginning of a path", + "%qs in paths can only be used in start position", segment.as_string ().c_str ()); return condition; @@ -419,7 +420,8 @@ template <typename S> tl::optional<typename std::vector<S>::const_iterator> ForeverStack<N>::find_starting_point ( const std::vector<S> &segments, std::reference_wrapper<Node> &starting_point, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { auto iterator = segments.begin (); @@ -436,8 +438,9 @@ ForeverStack<N>::find_starting_point ( // if we're after the first path segment and meet `self` or `crate`, it's // an error - we should only be seeing `super` keywords at this point - if (check_leading_kw_at_start (seg, !is_start (iterator, segments) - && is_self_or_crate)) + if (check_leading_kw_at_start (collect_errors, seg, + !is_start (iterator, segments) + && is_self_or_crate)) return tl::nullopt; if (seg.is_crate_path_seg ()) @@ -460,8 +463,9 @@ ForeverStack<N>::find_starting_point ( starting_point = find_closest_module (starting_point); if (starting_point.get ().is_root ()) { - rust_error_at (seg.get_locus (), ErrorCode::E0433, - "too many leading %<super%> keywords"); + collect_errors.emplace_back ( + seg.get_locus (), ErrorCode::E0433, + "too many leading %<super%> keywords"); return tl::nullopt; } @@ -487,7 +491,8 @@ tl::optional<typename ForeverStack<N>::Node &> ForeverStack<N>::resolve_segments ( Node &starting_point, const std::vector<S> &segments, typename std::vector<S>::const_iterator iterator, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { Node *current_node = &starting_point; for (; !is_last (iterator, segments); iterator++) @@ -509,9 +514,10 @@ ForeverStack<N>::resolve_segments ( rust_debug ("[ARTHUR]: resolving segment part: %s", str.c_str ()); // check that we don't encounter *any* leading keywords afterwards - if (check_leading_kw_at_start (seg, seg.is_crate_path_seg () - || seg.is_super_path_seg () - || seg.is_lower_self_seg ())) + if (check_leading_kw_at_start (collect_errors, seg, + seg.is_crate_path_seg () + || seg.is_super_path_seg () + || seg.is_lower_self_seg ())) return tl::nullopt; tl::optional<typename ForeverStack<N>::Node &> child = tl::nullopt; @@ -620,7 +626,8 @@ template <typename S> tl::optional<Rib::Definition> ForeverStack<N>::resolve_path ( const std::vector<S> &segments, bool has_opening_scope_resolution, - std::function<void (const S &, NodeId)> insert_segment_resolution) + std::function<void (const S &, NodeId)> insert_segment_resolution, + std::vector<Error> &collect_errors) { // TODO: What to do if segments.empty() ? @@ -668,15 +675,16 @@ ForeverStack<N>::resolve_path ( std::reference_wrapper<Node> starting_point = cursor (); auto res - = find_starting_point (segments, starting_point, insert_segment_resolution) + = find_starting_point (segments, starting_point, insert_segment_resolution, + collect_errors) .and_then ( - [this, &segments, &starting_point, &insert_segment_resolution] ( - typename std::vector<S>::const_iterator iterator) { + [this, &segments, &starting_point, &insert_segment_resolution, + &collect_errors] (typename std::vector<S>::const_iterator iterator) { return resolve_segments (starting_point.get (), segments, iterator, - insert_segment_resolution); + insert_segment_resolution, collect_errors); }) .and_then ([this, &segments, &insert_segment_resolution] ( - Node final_node) -> tl::optional<Rib::Definition> { + Node &final_node) -> tl::optional<Rib::Definition> { // leave resolution within impl blocks to type checker if (final_node.rib.kind == Rib::Kind::TraitOrImpl) return tl::nullopt; 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 f743e1e..6ec0422 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.cc @@ -129,6 +129,54 @@ Late::new_label (Identifier name, NodeId id) } void +Late::visit (AST::ForLoopExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.enter (BindingSource::For); + + visit (expr.get_pattern ()); + + ctx.bindings.exit (); + + visit (expr.get_iterator_expr ()); + visit (expr.get_loop_label ()); + visit (expr.get_loop_block ()); +} + +void +Late::visit (AST::IfLetExpr &expr) +{ + visit_outer_attrs (expr); + + ctx.bindings.enter (BindingSource::Let); + + for (auto &pattern : expr.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + visit (expr.get_value_expr ()); + visit (expr.get_if_block ()); +} + +void +Late::visit (AST::MatchArm &arm) +{ + visit_outer_attrs (arm); + + ctx.bindings.enter (BindingSource::Match); + + for (auto &pattern : arm.get_patterns ()) + visit (pattern); + + ctx.bindings.exit (); + + if (arm.has_match_arm_guard ()) + visit (arm.get_guard_expr ()); +} + +void Late::visit (AST::LetStmt &let) { DefaultASTVisitor::visit_outer_attrs (let); @@ -138,8 +186,13 @@ Late::visit (AST::LetStmt &let) // this makes variable shadowing work properly if (let.has_init_expr ()) visit (let.get_init_expr ()); + + ctx.bindings.enter (BindingSource::Let); + visit (let.get_pattern ()); + ctx.bindings.exit (); + if (let.has_else_expr ()) visit (let.get_init_expr ()); @@ -167,9 +220,68 @@ 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.peek ().is_and_bound (identifier.get_ident ())) + { + 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", + identifier.as_string ().c_str ()); + else + rust_error_at ( + identifier.get_locus (), ErrorCode::E0416, + "identifier %qs is bound more than once in the same pattern", + identifier.as_string ().c_str ()); + return; + } + + ctx.bindings.peek ().insert_ident (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 (), + identifier.get_node_id ()); + } + else + { + // We do want to ignore duplicated data because some situations rely on + // it. + std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), + identifier.get_node_id ()); + } +} + +void +Late::visit (AST::AltPattern &pattern) +{ + ctx.bindings.peek ().push (Binding::Kind::Or); + for (auto &alt : pattern.get_alts ()) + { + ctx.bindings.peek ().push (Binding::Kind::Product); + visit (alt); + ctx.bindings.peek ().merge (); + } + ctx.bindings.peek ().merge (); +} + +void +Late::visit_function_params (AST::Function &function) +{ + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : function.get_function_params ()) + visit (param); + + ctx.bindings.exit (); +} + +void +Late::visit (AST::StructPatternFieldIdent &field) +{ // We do want to ignore duplicated data because some situations rely on it. - std::ignore = ctx.values.insert_shadowable (identifier.get_ident (), - identifier.get_node_id ()); + std::ignore = ctx.values.insert_shadowable (field.get_identifier (), + field.get_node_id ()); } void @@ -347,8 +459,8 @@ Late::visit (AST::PathInExpression &expr) if (!resolved) { if (!ctx.lookup (expr.get_segments ().front ().get_node_id ())) - rust_error_at (expr.get_locus (), - "could not resolve path expression: %qs", + rust_error_at (expr.get_locus (), ErrorCode::E0433, + "Cannot find path %qs in this scope", expr.as_simple_path ().as_string ().c_str ()); return; } @@ -393,6 +505,14 @@ Late::visit (AST::TypePath &type) return; } + if (ctx.types.forward_declared (resolved->get_node_id (), + type.get_node_id ())) + { + rust_error_at (type.get_locus (), ErrorCode::E0128, + "type parameters with a default cannot use forward " + "declared identifiers"); + } + ctx.map_usage (Usage (type.get_node_id ()), Definition (resolved->get_node_id ())); } @@ -509,14 +629,35 @@ void Late::visit (AST::ClosureExprInner &closure) { add_captures (closure, ctx); - DefaultResolver::visit (closure); + + visit_outer_attrs (closure); + + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.exit (); + + visit (closure.get_definition_expr ()); } void Late::visit (AST::ClosureExprInnerTyped &closure) { add_captures (closure, ctx); - DefaultResolver::visit (closure); + + visit_outer_attrs (closure); + + ctx.bindings.enter (BindingSource::Param); + + for (auto ¶m : closure.get_params ()) + visit (param); + + ctx.bindings.exit (); + + visit (closure.get_return_type ()); + visit (closure.get_definition_block ()); } } // namespace Resolver2_0 diff --git a/gcc/rust/resolve/rust-late-name-resolver-2.0.h b/gcc/rust/resolve/rust-late-name-resolver-2.0.h index 5703b15..171d9bf 100644 --- a/gcc/rust/resolve/rust-late-name-resolver-2.0.h +++ b/gcc/rust/resolve/rust-late-name-resolver-2.0.h @@ -37,12 +37,20 @@ public: void new_label (Identifier name, NodeId id); + // Specialized visit bits + void visit_function_params (AST::Function &function) override; + // some more label declarations void visit (AST::LetStmt &) override; // TODO: Do we need this? // void visit (AST::Method &) override; void visit (AST::IdentifierPattern &) override; + void visit (AST::StructPatternFieldIdent &) override; + void visit (AST::AltPattern &) override; void visit (AST::SelfParam &) override; + void visit (AST::MatchArm &) override; + void visit (AST::ForLoopExpr &) override; + void visit (AST::IfLetExpr &) override; // resolutions void visit (AST::IdentifierExpr &) override; diff --git a/gcc/rust/resolve/rust-name-resolution-context.cc b/gcc/rust/resolve/rust-name-resolution-context.cc index 92c4863..f098e48 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 84c0800..19ba750 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 { @@ -156,6 +157,62 @@ public: NodeId id; }; +struct Binding +{ + enum class Kind + { + Product, + Or, + } kind; + + std::unordered_set<Identifier> set; + + 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 BindingLayer +{ + BindingSource source; + std::vector<Binding> bindings; + + bool bind_test (Identifier ident, Binding::Kind kind); + +public: + void push (Binding::Kind kind); + + BindingLayer (BindingSource source); + + /** + * Identifies if the identifier has been used in a product binding context. + * eg. `let (a, a) = test();` + */ + bool is_and_bound (Identifier ident); + + /** + * 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 insert_ident (Identifier ident); + + void merge (); + + BindingSource get_source () const; +}; + // Now our resolver, which keeps track of all the `ForeverStack`s we could want class NameResolutionContext { @@ -212,6 +269,7 @@ public: ForeverStack<Namespace::Labels> labels; Analysis::Mappings &mappings; + StackedContexts<BindingLayer> bindings; // TODO: Rename // TODO: Use newtype pattern for Usage and Definition @@ -220,9 +278,10 @@ public: tl::optional<NodeId> lookup (NodeId usage) const; template <typename S> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, - Namespace ns) + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, + bool has_opening_scope_resolution, + std::vector<Error> &collect_errors, Namespace ns) { std::function<void (const S &, NodeId)> insert_segment_resolution = [this] (const S &seg, NodeId id) { @@ -234,60 +293,102 @@ public: { case Namespace::Values: return values.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Types: return types.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Macros: return macros.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); case Namespace::Labels: return labels.resolve_path (segments, has_opening_scope_resolution, - insert_segment_resolution); + insert_segment_resolution, collect_errors); default: rust_unreachable (); } } template <typename S, typename... Args> - tl::optional<Rib::Definition> resolve_path (const std::vector<S> &segments, - bool has_opening_scope_resolution, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const std::vector<S> &segments, + bool has_opening_scope_resolution, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { - std::initializer_list<Namespace> namespaces = {ns_args...}; + std::initializer_list<Namespace> namespaces = {ns_first, ns_args...}; for (auto ns : namespaces) { - if (auto ret - = resolve_path (segments, has_opening_scope_resolution, ns)) + std::vector<Error> collect_errors_inner; + if (auto ret = resolve_path (segments, has_opening_scope_resolution, + collect_errors_inner, ns)) return ret; + if (!collect_errors_inner.empty ()) + { + if (collect_errors.has_value ()) + { + std::move (collect_errors_inner.begin (), + collect_errors_inner.end (), + std::back_inserter (collect_errors.value ())); + } + else + { + for (auto &e : collect_errors_inner) + e.emit (); + } + return tl::nullopt; + } } return tl::nullopt; } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::SimplePath &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::SimplePath &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution (), ns_args...); + path.has_opening_scope_resolution (), collect_errors, + ns_first, ns_args...); } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::PathInExpression &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::PathInExpression &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), path.opening_scope_resolution (), - ns_args...); + collect_errors, ns_first, ns_args...); } template <typename... Args> - tl::optional<Rib::Definition> resolve_path (const AST::TypePath &path, - Args... ns_args) + tl::optional<Rib::Definition> + resolve_path (const AST::TypePath &path, + tl::optional<std::vector<Error> &> collect_errors, + Namespace ns_first, Args... ns_args) { return resolve_path (path.get_segments (), - path.has_opening_scope_resolution_op (), ns_args...); + path.has_opening_scope_resolution_op (), + collect_errors, ns_first, ns_args...); + } + + template <typename P, typename... Args> + tl::optional<Rib::Definition> resolve_path (const P &path, Namespace ns_first, + Args... ns_args) + { + return resolve_path (path, tl::nullopt, ns_first, ns_args...); + } + + template <typename P, typename... Args> + tl::optional<Rib::Definition> + resolve_path (const P &path_segments, bool has_opening_scope_resolution, + Namespace ns_first, Args... ns_args) + { + return resolve_path (path_segments, has_opening_scope_resolution, + tl::nullopt, ns_first, ns_args...); } private: diff --git a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc index ba37dee..2f036fe 100644 --- a/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc +++ b/gcc/rust/resolve/rust-toplevel-name-resolver-2.0.cc @@ -135,8 +135,7 @@ TopLevel::visit (AST::Module &module) void TopLevel::visit (AST::Trait &trait) { - insert_or_error_out (trait.get_identifier ().as_string (), trait, - Namespace::Types); + insert_or_error_out (trait.get_identifier (), trait, Namespace::Types); DefaultResolver::visit (trait); } @@ -548,6 +547,8 @@ flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths, { if (glob.has_path ()) paths.emplace_back (glob.get_path ()); + else + paths.emplace_back (AST::SimplePath ({}, false, glob.get_locus ())); } void |