new file mode 100644
@@ -0,0 +1,658 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-expr.h"
+#include "rust-ast-resolve-path.h"
+#include "rust-item.h"
+
+namespace Rust {
+namespace Resolver {
+
+bool
+ResolverBase::resolve_visibility (const AST::Visibility &vis)
+{
+ if (vis.has_path ())
+ {
+ auto path = vis.get_path ();
+ ResolvePath::go (&path);
+
+ // Do we need to lookup something here?
+ // Is it just about resolving the names correctly so we can look them up
+ // later?
+ }
+
+ return true;
+}
+
+// Default visitors implementations
+
+void
+ResolverBase::visit (AST::Token &)
+{}
+
+void
+ResolverBase::visit (AST::DelimTokenTree &)
+{}
+
+void
+ResolverBase::visit (AST::AttrInputMetaItemContainer &)
+{}
+
+void
+ResolverBase::visit (AST::IdentifierExpr &)
+{}
+
+void
+ResolverBase::visit (AST::Lifetime &)
+{}
+
+void
+ResolverBase::visit (AST::LifetimeParam &)
+{}
+
+void
+ResolverBase::visit (AST::ConstGenericParam &)
+{}
+
+void
+ResolverBase::visit (AST::PathInExpression &)
+{}
+
+void
+ResolverBase::visit (AST::TypePathSegment &)
+{}
+
+void
+ResolverBase::visit (AST::TypePathSegmentGeneric &)
+{}
+
+void
+ResolverBase::visit (AST::TypePathSegmentFunction &)
+{}
+
+void
+ResolverBase::visit (AST::TypePath &)
+{}
+
+void
+ResolverBase::visit (AST::QualifiedPathInExpression &)
+{}
+
+void
+ResolverBase::visit (AST::QualifiedPathInType &)
+{}
+
+void
+ResolverBase::visit (AST::LiteralExpr &)
+{}
+
+void
+ResolverBase::visit (AST::AttrInputLiteral &)
+{}
+
+void
+ResolverBase::visit (AST::MetaItemLitExpr &)
+{}
+
+void
+ResolverBase::visit (AST::MetaItemPathLit &)
+{}
+
+void
+ResolverBase::visit (AST::BorrowExpr &)
+{}
+
+void
+ResolverBase::visit (AST::DereferenceExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ErrorPropagationExpr &)
+{}
+
+void
+ResolverBase::visit (AST::NegationExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ArithmeticOrLogicalExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ComparisonExpr &)
+{}
+
+void
+ResolverBase::visit (AST::LazyBooleanExpr &)
+{}
+
+void
+ResolverBase::visit (AST::TypeCastExpr &)
+{}
+
+void
+ResolverBase::visit (AST::AssignmentExpr &)
+{}
+
+void
+ResolverBase::visit (AST::CompoundAssignmentExpr &)
+{}
+
+void
+ResolverBase::visit (AST::GroupedExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayElemsValues &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayElemsCopied &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayIndexExpr &)
+{}
+
+void
+ResolverBase::visit (AST::TupleExpr &)
+{}
+
+void
+ResolverBase::visit (AST::TupleIndexExpr &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprStruct &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprFieldIdentifier &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprFieldIdentifierValue &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprFieldIndexValue &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprStructFields &)
+{}
+
+void
+ResolverBase::visit (AST::StructExprStructBase &)
+{}
+
+void
+ResolverBase::visit (AST::CallExpr &)
+{}
+
+void
+ResolverBase::visit (AST::MethodCallExpr &)
+{}
+
+void
+ResolverBase::visit (AST::FieldAccessExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ClosureExprInner &)
+{}
+
+void
+ResolverBase::visit (AST::BlockExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ClosureExprInnerTyped &)
+{}
+
+void
+ResolverBase::visit (AST::ContinueExpr &)
+{}
+
+void
+ResolverBase::visit (AST::BreakExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeFromToExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeFromExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeToExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeFullExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeFromToInclExpr &)
+{}
+
+void
+ResolverBase::visit (AST::RangeToInclExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ReturnExpr &)
+{}
+
+void
+ResolverBase::visit (AST::UnsafeBlockExpr &)
+{}
+
+void
+ResolverBase::visit (AST::LoopExpr &)
+{}
+
+void
+ResolverBase::visit (AST::WhileLoopExpr &)
+{}
+
+void
+ResolverBase::visit (AST::WhileLetLoopExpr &)
+{}
+
+void
+ResolverBase::visit (AST::ForLoopExpr &)
+{}
+
+void
+ResolverBase::visit (AST::IfExpr &)
+{}
+
+void
+ResolverBase::visit (AST::IfExprConseqElse &)
+{}
+
+void
+ResolverBase::visit (AST::IfExprConseqIf &)
+{}
+
+void
+ResolverBase::visit (AST::IfExprConseqIfLet &)
+{}
+
+void
+ResolverBase::visit (AST::IfLetExpr &)
+{}
+
+void
+ResolverBase::visit (AST::IfLetExprConseqElse &)
+{}
+
+void
+ResolverBase::visit (AST::IfLetExprConseqIf &)
+{}
+
+void
+ResolverBase::visit (AST::IfLetExprConseqIfLet &)
+{}
+
+void
+ResolverBase::visit (AST::MatchExpr &)
+{}
+
+void
+ResolverBase::visit (AST::AwaitExpr &)
+{}
+
+void
+ResolverBase::visit (AST::AsyncBlockExpr &)
+{}
+
+void
+ResolverBase::visit (AST::TypeParam &)
+{}
+
+void
+ResolverBase::visit (AST::LifetimeWhereClauseItem &)
+{}
+
+void
+ResolverBase::visit (AST::TypeBoundWhereClauseItem &)
+{}
+
+void
+ResolverBase::visit (AST::Method &)
+{}
+
+void
+ResolverBase::visit (AST::Module &)
+{}
+
+void
+ResolverBase::visit (AST::ExternCrate &)
+{}
+
+void
+ResolverBase::visit (AST::UseTreeGlob &)
+{}
+
+void
+ResolverBase::visit (AST::UseTreeList &)
+{}
+
+void
+ResolverBase::visit (AST::UseTreeRebind &)
+{}
+
+void
+ResolverBase::visit (AST::UseDeclaration &)
+{}
+
+void
+ResolverBase::visit (AST::Function &)
+{}
+
+void
+ResolverBase::visit (AST::TypeAlias &)
+{}
+
+void
+ResolverBase::visit (AST::StructStruct &)
+{}
+
+void
+ResolverBase::visit (AST::TupleStruct &)
+{}
+
+void
+ResolverBase::visit (AST::EnumItem &)
+{}
+
+void
+ResolverBase::visit (AST::EnumItemTuple &)
+{}
+
+void
+ResolverBase::visit (AST::EnumItemStruct &)
+{}
+
+void
+ResolverBase::visit (AST::EnumItemDiscriminant &)
+{}
+
+void
+ResolverBase::visit (AST::Enum &)
+{}
+
+void
+ResolverBase::visit (AST::Union &)
+{}
+
+void
+ResolverBase::visit (AST::ConstantItem &)
+{}
+
+void
+ResolverBase::visit (AST::StaticItem &)
+{}
+
+void
+ResolverBase::visit (AST::TraitItemFunc &)
+{}
+
+void
+ResolverBase::visit (AST::TraitItemMethod &)
+{}
+
+void
+ResolverBase::visit (AST::TraitItemConst &)
+{}
+
+void
+ResolverBase::visit (AST::TraitItemType &)
+{}
+
+void
+ResolverBase::visit (AST::Trait &)
+{}
+
+void
+ResolverBase::visit (AST::InherentImpl &)
+{}
+
+void
+ResolverBase::visit (AST::TraitImpl &)
+{}
+
+void
+ResolverBase::visit (AST::ExternalStaticItem &)
+{}
+
+void
+ResolverBase::visit (AST::ExternalFunctionItem &)
+{}
+
+void
+ResolverBase::visit (AST::ExternBlock &)
+{}
+
+void
+ResolverBase::visit (AST::MacroMatchFragment &)
+{}
+
+void
+ResolverBase::visit (AST::MacroMatchRepetition &)
+{}
+
+void
+ResolverBase::visit (AST::MacroMatcher &)
+{}
+
+void
+ResolverBase::visit (AST::MacroRulesDefinition &)
+{}
+
+void
+ResolverBase::visit (AST::MacroInvocation &)
+{}
+
+void
+ResolverBase::visit (AST::MetaItemPath &)
+{}
+
+void
+ResolverBase::visit (AST::MetaItemSeq &)
+{}
+
+void
+ResolverBase::visit (AST::MetaWord &)
+{}
+
+void
+ResolverBase::visit (AST::MetaNameValueStr &)
+{}
+
+void
+ResolverBase::visit (AST::MetaListPaths &)
+{}
+
+void
+ResolverBase::visit (AST::MetaListNameValueStr &)
+{}
+
+void
+ResolverBase::visit (AST::LiteralPattern &)
+{}
+
+void
+ResolverBase::visit (AST::IdentifierPattern &)
+{}
+
+void
+ResolverBase::visit (AST::WildcardPattern &)
+{}
+
+void
+ResolverBase::visit (AST::RangePatternBoundLiteral &)
+{}
+
+void
+ResolverBase::visit (AST::RangePatternBoundPath &)
+{}
+
+void
+ResolverBase::visit (AST::RangePatternBoundQualPath &)
+{}
+
+void
+ResolverBase::visit (AST::RangePattern &)
+{}
+
+void
+ResolverBase::visit (AST::ReferencePattern &)
+{}
+
+void
+ResolverBase::visit (AST::StructPatternFieldTuplePat &)
+{}
+
+void
+ResolverBase::visit (AST::StructPatternFieldIdentPat &)
+{}
+
+void
+ResolverBase::visit (AST::StructPatternFieldIdent &)
+{}
+
+void
+ResolverBase::visit (AST::StructPattern &)
+{}
+
+void
+ResolverBase::visit (AST::TupleStructItemsNoRange &)
+{}
+
+void
+ResolverBase::visit (AST::TupleStructItemsRange &)
+{}
+
+void
+ResolverBase::visit (AST::TupleStructPattern &)
+{}
+
+void
+ResolverBase::visit (AST::TuplePatternItemsMultiple &)
+{}
+
+void
+ResolverBase::visit (AST::TuplePatternItemsRanged &)
+{}
+
+void
+ResolverBase::visit (AST::TuplePattern &)
+{}
+
+void
+ResolverBase::visit (AST::GroupedPattern &)
+{}
+
+void
+ResolverBase::visit (AST::SlicePattern &)
+{}
+
+void
+ResolverBase::visit (AST::EmptyStmt &)
+{}
+
+void
+ResolverBase::visit (AST::LetStmt &)
+{}
+
+void
+ResolverBase::visit (AST::ExprStmtWithoutBlock &)
+{}
+
+void
+ResolverBase::visit (AST::ExprStmtWithBlock &)
+{}
+
+void
+ResolverBase::visit (AST::TraitBound &)
+{}
+
+void
+ResolverBase::visit (AST::ImplTraitType &)
+{}
+
+void
+ResolverBase::visit (AST::TraitObjectType &)
+{}
+
+void
+ResolverBase::visit (AST::ParenthesisedType &)
+{}
+
+void
+ResolverBase::visit (AST::ImplTraitTypeOneBound &)
+{}
+
+void
+ResolverBase::visit (AST::TraitObjectTypeOneBound &)
+{}
+
+void
+ResolverBase::visit (AST::TupleType &)
+{}
+
+void
+ResolverBase::visit (AST::NeverType &)
+{}
+
+void
+ResolverBase::visit (AST::RawPointerType &)
+{}
+
+void
+ResolverBase::visit (AST::ReferenceType &)
+{}
+
+void
+ResolverBase::visit (AST::ArrayType &)
+{}
+
+void
+ResolverBase::visit (AST::SliceType &)
+{}
+
+void
+ResolverBase::visit (AST::InferredType &)
+{}
+
+void
+ResolverBase::visit (AST::BareFunctionType &)
+{}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,221 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_BASE_H
+#define RUST_AST_RESOLVE_BASE_H
+
+#include "rust-ast-visitor.h"
+#include "rust-name-resolver.h"
+#include "rust-diagnostics.h"
+#include "rust-location.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolverBase : public AST::ASTVisitor
+{
+public:
+ virtual ~ResolverBase () {}
+
+ void visit (AST::Token &);
+ void visit (AST::DelimTokenTree &);
+ void visit (AST::AttrInputMetaItemContainer &);
+ void visit (AST::IdentifierExpr &);
+ void visit (AST::Lifetime &);
+ void visit (AST::LifetimeParam &);
+ void visit (AST::ConstGenericParam &);
+ void visit (AST::PathInExpression &);
+ void visit (AST::TypePathSegment &);
+ void visit (AST::TypePathSegmentGeneric &);
+ void visit (AST::TypePathSegmentFunction &);
+ void visit (AST::TypePath &);
+ void visit (AST::QualifiedPathInExpression &);
+ void visit (AST::QualifiedPathInType &);
+ void visit (AST::LiteralExpr &);
+ void visit (AST::AttrInputLiteral &);
+ void visit (AST::MetaItemLitExpr &);
+ void visit (AST::MetaItemPathLit &);
+ void visit (AST::BorrowExpr &);
+ void visit (AST::DereferenceExpr &);
+ void visit (AST::ErrorPropagationExpr &);
+ void visit (AST::NegationExpr &);
+ void visit (AST::ArithmeticOrLogicalExpr &);
+ void visit (AST::ComparisonExpr &);
+ void visit (AST::LazyBooleanExpr &);
+ void visit (AST::TypeCastExpr &);
+ void visit (AST::AssignmentExpr &);
+ void visit (AST::CompoundAssignmentExpr &);
+ void visit (AST::GroupedExpr &);
+ void visit (AST::ArrayElemsValues &);
+ void visit (AST::ArrayElemsCopied &);
+ void visit (AST::ArrayExpr &);
+ void visit (AST::ArrayIndexExpr &);
+ void visit (AST::TupleExpr &);
+ void visit (AST::TupleIndexExpr &);
+ void visit (AST::StructExprStruct &);
+ void visit (AST::StructExprFieldIdentifier &);
+ void visit (AST::StructExprFieldIdentifierValue &);
+ void visit (AST::StructExprFieldIndexValue &);
+ void visit (AST::StructExprStructFields &);
+ void visit (AST::StructExprStructBase &);
+ void visit (AST::CallExpr &);
+ void visit (AST::MethodCallExpr &);
+ void visit (AST::FieldAccessExpr &);
+ void visit (AST::ClosureExprInner &);
+ void visit (AST::BlockExpr &);
+ void visit (AST::ClosureExprInnerTyped &);
+ void visit (AST::ContinueExpr &);
+ void visit (AST::BreakExpr &);
+ void visit (AST::RangeFromToExpr &);
+ void visit (AST::RangeFromExpr &);
+ void visit (AST::RangeToExpr &);
+ void visit (AST::RangeFullExpr &);
+ void visit (AST::RangeFromToInclExpr &);
+ void visit (AST::RangeToInclExpr &);
+ void visit (AST::ReturnExpr &);
+ void visit (AST::UnsafeBlockExpr &);
+ void visit (AST::LoopExpr &);
+ void visit (AST::WhileLoopExpr &);
+ void visit (AST::WhileLetLoopExpr &);
+ void visit (AST::ForLoopExpr &);
+ void visit (AST::IfExpr &);
+ void visit (AST::IfExprConseqElse &);
+ void visit (AST::IfExprConseqIf &);
+ void visit (AST::IfExprConseqIfLet &);
+ void visit (AST::IfLetExpr &);
+ void visit (AST::IfLetExprConseqElse &);
+ void visit (AST::IfLetExprConseqIf &);
+ void visit (AST::IfLetExprConseqIfLet &);
+
+ void visit (AST::MatchExpr &);
+ void visit (AST::AwaitExpr &);
+ void visit (AST::AsyncBlockExpr &);
+
+ void visit (AST::TypeParam &);
+
+ void visit (AST::LifetimeWhereClauseItem &);
+ void visit (AST::TypeBoundWhereClauseItem &);
+ void visit (AST::Method &);
+ void visit (AST::Module &);
+ void visit (AST::ExternCrate &);
+
+ void visit (AST::UseTreeGlob &);
+ void visit (AST::UseTreeList &);
+ void visit (AST::UseTreeRebind &);
+ void visit (AST::UseDeclaration &);
+ void visit (AST::Function &);
+ void visit (AST::TypeAlias &);
+ void visit (AST::StructStruct &);
+ void visit (AST::TupleStruct &);
+ void visit (AST::EnumItem &);
+ void visit (AST::EnumItemTuple &);
+ void visit (AST::EnumItemStruct &);
+ void visit (AST::EnumItemDiscriminant &);
+ void visit (AST::Enum &);
+ void visit (AST::Union &);
+ void visit (AST::ConstantItem &);
+ void visit (AST::StaticItem &);
+ void visit (AST::TraitItemFunc &);
+ void visit (AST::TraitItemMethod &);
+ void visit (AST::TraitItemConst &);
+ void visit (AST::TraitItemType &);
+ void visit (AST::Trait &);
+ void visit (AST::InherentImpl &);
+ void visit (AST::TraitImpl &);
+
+ void visit (AST::ExternalStaticItem &);
+ void visit (AST::ExternalFunctionItem &);
+ void visit (AST::ExternBlock &);
+
+ void visit (AST::MacroMatchFragment &);
+ void visit (AST::MacroMatchRepetition &);
+ void visit (AST::MacroMatcher &);
+ void visit (AST::MacroRulesDefinition &);
+ void visit (AST::MacroInvocation &);
+ void visit (AST::MetaItemPath &);
+ void visit (AST::MetaItemSeq &);
+ void visit (AST::MetaWord &);
+ void visit (AST::MetaNameValueStr &);
+ void visit (AST::MetaListPaths &);
+ void visit (AST::MetaListNameValueStr &);
+
+ void visit (AST::LiteralPattern &);
+ void visit (AST::IdentifierPattern &);
+ void visit (AST::WildcardPattern &);
+
+ void visit (AST::RangePatternBoundLiteral &);
+ void visit (AST::RangePatternBoundPath &);
+ void visit (AST::RangePatternBoundQualPath &);
+ void visit (AST::RangePattern &);
+ void visit (AST::ReferencePattern &);
+
+ void visit (AST::StructPatternFieldTuplePat &);
+ void visit (AST::StructPatternFieldIdentPat &);
+ void visit (AST::StructPatternFieldIdent &);
+ void visit (AST::StructPattern &);
+
+ void visit (AST::TupleStructItemsNoRange &);
+ void visit (AST::TupleStructItemsRange &);
+ void visit (AST::TupleStructPattern &);
+
+ void visit (AST::TuplePatternItemsMultiple &);
+ void visit (AST::TuplePatternItemsRanged &);
+ void visit (AST::TuplePattern &);
+ void visit (AST::GroupedPattern &);
+ void visit (AST::SlicePattern &);
+
+ void visit (AST::EmptyStmt &);
+ void visit (AST::LetStmt &);
+ void visit (AST::ExprStmtWithoutBlock &);
+ void visit (AST::ExprStmtWithBlock &);
+
+ void visit (AST::TraitBound &);
+ void visit (AST::ImplTraitType &);
+ void visit (AST::TraitObjectType &);
+ void visit (AST::ParenthesisedType &);
+ void visit (AST::ImplTraitTypeOneBound &);
+ void visit (AST::TraitObjectTypeOneBound &);
+ void visit (AST::TupleType &);
+ void visit (AST::NeverType &);
+ void visit (AST::RawPointerType &);
+ void visit (AST::ReferenceType &);
+ void visit (AST::ArrayType &);
+ void visit (AST::SliceType &);
+ void visit (AST::InferredType &);
+ void visit (AST::BareFunctionType &);
+
+protected:
+ ResolverBase ()
+ : resolver (Resolver::get ()), mappings (Analysis::Mappings::get ()),
+ resolved_node (UNKNOWN_NODEID)
+ {}
+
+ /**
+ * Resolve a visibility's path through the name resolver
+ */
+ bool resolve_visibility (const AST::Visibility &vis);
+
+ Resolver *resolver;
+ Analysis::Mappings *mappings;
+ NodeId resolved_node;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_BASE_H
new file mode 100644
@@ -0,0 +1,574 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-expr.h"
+#include "rust-ast-resolve-stmt.h"
+#include "rust-ast-resolve-struct-expr-field.h"
+#include "rust-ast-verify-assignee.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-pattern.h"
+#include "rust-ast-resolve-path.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+ResolveExpr::go (AST::Expr *expr, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ ResolveExpr resolver (prefix, canonical_prefix);
+ expr->accept_vis (resolver);
+}
+
+void
+ResolveExpr::visit (AST::TupleIndexExpr &expr)
+{
+ ResolveExpr::go (expr.get_tuple_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::TupleExpr &expr)
+{
+ if (expr.is_unit ())
+ return;
+
+ for (auto &elem : expr.get_tuple_elems ())
+ ResolveExpr::go (elem.get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::PathInExpression &expr)
+{
+ ResolvePath::go (&expr);
+}
+
+void
+ResolveExpr::visit (AST::QualifiedPathInExpression &expr)
+{
+ ResolvePath::go (&expr);
+}
+
+void
+ResolveExpr::visit (AST::ReturnExpr &expr)
+{
+ if (expr.has_returned_expr ())
+ ResolveExpr::go (expr.get_returned_expr ().get (), prefix,
+ canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::CallExpr &expr)
+{
+ ResolveExpr::go (expr.get_function_expr ().get (), prefix, canonical_prefix);
+ for (auto ¶m : expr.get_params ())
+ ResolveExpr::go (param.get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::MethodCallExpr &expr)
+{
+ ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix);
+
+ if (expr.get_method_name ().has_generic_args ())
+ {
+ AST::GenericArgs &args = expr.get_method_name ().get_generic_args ();
+ ResolveGenericArgs::go (args, prefix, canonical_prefix);
+ }
+
+ auto const &in_params = expr.get_params ();
+ for (auto ¶m : in_params)
+ ResolveExpr::go (param.get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::AssignmentExpr &expr)
+{
+ ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+
+ // need to verify the assignee
+ VerifyAsignee::go (expr.get_left_expr ().get (), expr.get_node_id ());
+}
+
+void
+ResolveExpr::visit (AST::IdentifierExpr &expr)
+{
+ if (resolver->get_name_scope ().lookup (
+ CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()),
+ &resolved_node))
+ {
+ resolver->insert_resolved_name (expr.get_node_id (), resolved_node);
+ }
+ else if (resolver->get_type_scope ().lookup (
+ CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()),
+ &resolved_node))
+ {
+ resolver->insert_resolved_type (expr.get_node_id (), resolved_node);
+ }
+ else
+ {
+ rust_error_at (expr.get_locus (), "failed to find name: %s",
+ expr.as_string ().c_str ());
+ }
+}
+
+void
+ResolveExpr::visit (AST::ArithmeticOrLogicalExpr &expr)
+{
+ ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::CompoundAssignmentExpr &expr)
+{
+ ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+
+ // need to verify the assignee
+ VerifyAsignee::go (expr.get_left_expr ().get (), expr.get_node_id ());
+}
+
+void
+ResolveExpr::visit (AST::ComparisonExpr &expr)
+{
+ ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::LazyBooleanExpr &expr)
+{
+ ResolveExpr::go (expr.get_left_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_right_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::NegationExpr &expr)
+{
+ ResolveExpr::go (expr.get_negated_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::TypeCastExpr &expr)
+{
+ ResolveType::go (expr.get_type_to_cast_to ().get ());
+ ResolveExpr::go (expr.get_casted_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::IfExpr &expr)
+{
+ ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::IfExprConseqElse &expr)
+{
+ ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_else_block ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::IfExprConseqIf &expr)
+{
+ ResolveExpr::go (expr.get_condition_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_conseq_if_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::IfLetExpr &expr)
+{
+ ResolveExpr::go (expr.get_value_expr ().get (), prefix, canonical_prefix);
+
+ NodeId scope_node_id = expr.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ for (auto &pattern : expr.get_patterns ())
+ {
+ PatternDeclaration::go (pattern.get ());
+ }
+
+ ResolveExpr::go (expr.get_if_block ().get (), prefix, canonical_prefix);
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveExpr::visit (AST::BlockExpr &expr)
+{
+ NodeId scope_node_id = expr.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ for (auto &s : expr.get_statements ())
+ {
+ if (s->is_item ())
+ ResolveStmt::go (s.get (), prefix, canonical_prefix,
+ CanonicalPath::create_empty ());
+ }
+
+ for (auto &s : expr.get_statements ())
+ {
+ if (!s->is_item ())
+ ResolveStmt::go (s.get (), prefix, canonical_prefix,
+ CanonicalPath::create_empty ());
+ }
+
+ if (expr.has_tail_expr ())
+ ResolveExpr::go (expr.get_tail_expr ().get (), prefix, canonical_prefix);
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveExpr::visit (AST::UnsafeBlockExpr &expr)
+{
+ expr.get_block_expr ()->accept_vis (*this);
+}
+
+void
+ResolveExpr::visit (AST::ArrayElemsValues &elems)
+{
+ for (auto &elem : elems.get_values ())
+ ResolveExpr::go (elem.get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::ArrayExpr &expr)
+{
+ expr.get_array_elems ()->accept_vis (*this);
+}
+
+void
+ResolveExpr::visit (AST::ArrayIndexExpr &expr)
+{
+ ResolveExpr::go (expr.get_array_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_index_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::ArrayElemsCopied &expr)
+{
+ ResolveExpr::go (expr.get_num_copies ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_elem_to_copy ().get (), prefix, canonical_prefix);
+}
+
+// this this an empty struct constructor like 'S {}'
+void
+ResolveExpr::visit (AST::StructExprStruct &struct_expr)
+{
+ ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix);
+}
+
+// this this a struct constructor with fields
+void
+ResolveExpr::visit (AST::StructExprStructFields &struct_expr)
+{
+ ResolveExpr::go (&struct_expr.get_struct_name (), prefix, canonical_prefix);
+
+ if (struct_expr.has_struct_base ())
+ {
+ AST::StructBase &base = struct_expr.get_struct_base ();
+ ResolveExpr::go (base.get_base_struct ().get (), prefix,
+ canonical_prefix);
+ }
+
+ auto const &struct_fields = struct_expr.get_fields ();
+ for (auto &struct_field : struct_fields)
+ {
+ ResolveStructExprField::go (struct_field.get (), prefix,
+ canonical_prefix);
+ }
+}
+
+void
+ResolveExpr::visit (AST::GroupedExpr &expr)
+{
+ ResolveExpr::go (expr.get_expr_in_parens ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::FieldAccessExpr &expr)
+{
+ ResolveExpr::go (expr.get_receiver_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::LoopExpr &expr)
+{
+ if (expr.has_loop_label ())
+ {
+ auto label = expr.get_loop_label ();
+ if (label.get_lifetime ().get_lifetime_type ()
+ != AST::Lifetime::LifetimeType::NAMED)
+ {
+ rust_error_at (label.get_locus (),
+ "Labels must be a named lifetime value");
+ return;
+ }
+
+ auto label_name = label.get_lifetime ().get_lifetime_name ();
+ auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
+ resolver->get_label_scope ().insert (
+ CanonicalPath::new_seg (expr.get_node_id (), label_name),
+ label_lifetime_node_id, label.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (locus, "was defined here");
+ });
+ }
+ ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::BreakExpr &expr)
+{
+ if (expr.has_label ())
+ {
+ auto label = expr.get_label ();
+ if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
+ {
+ rust_error_at (label.get_locus (),
+ "Labels must be a named lifetime value");
+ return;
+ }
+
+ NodeId resolved_node = UNKNOWN_NODEID;
+ if (!resolver->get_label_scope ().lookup (
+ CanonicalPath::new_seg (label.get_node_id (),
+ label.get_lifetime_name ()),
+ &resolved_node))
+ {
+ rust_error_at (expr.get_label ().get_locus (),
+ "failed to resolve label");
+ return;
+ }
+ resolver->insert_resolved_label (label.get_node_id (), resolved_node);
+ }
+
+ if (expr.has_break_expr ())
+ ResolveExpr::go (expr.get_break_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::WhileLoopExpr &expr)
+{
+ if (expr.has_loop_label ())
+ {
+ auto label = expr.get_loop_label ();
+ if (label.get_lifetime ().get_lifetime_type ()
+ != AST::Lifetime::LifetimeType::NAMED)
+ {
+ rust_error_at (label.get_locus (),
+ "Labels must be a named lifetime value");
+ return;
+ }
+
+ auto label_name = label.get_lifetime ().get_lifetime_name ();
+ auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
+ resolver->get_label_scope ().insert (
+ CanonicalPath::new_seg (label.get_node_id (), label_name),
+ label_lifetime_node_id, label.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (locus, "was defined here");
+ });
+ }
+
+ ResolveExpr::go (expr.get_predicate_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::ForLoopExpr &expr)
+{
+ if (expr.has_loop_label ())
+ {
+ auto label = expr.get_loop_label ();
+ if (label.get_lifetime ().get_lifetime_type ()
+ != AST::Lifetime::LifetimeType::NAMED)
+ {
+ rust_error_at (label.get_locus (),
+ "Labels must be a named lifetime value");
+ return;
+ }
+
+ auto label_name = label.get_lifetime ().get_lifetime_name ();
+ auto label_lifetime_node_id = label.get_lifetime ().get_node_id ();
+ resolver->get_label_scope ().insert (
+ CanonicalPath::new_seg (label.get_node_id (), label_name),
+ label_lifetime_node_id, label.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ rust_error_at (label.get_locus (), "label redefined multiple times");
+ rust_error_at (locus, "was defined here");
+ });
+ }
+
+ // this needs a new rib to contain the pattern
+ NodeId scope_node_id = expr.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ // resolve the expression
+ PatternDeclaration::go (expr.get_pattern ().get ());
+ ResolveExpr::go (expr.get_iterator_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_loop_block ().get (), prefix, canonical_prefix);
+
+ // done
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveExpr::visit (AST::ContinueExpr &expr)
+{
+ if (expr.has_label ())
+ {
+ auto label = expr.get_label ();
+ if (label.get_lifetime_type () != AST::Lifetime::LifetimeType::NAMED)
+ {
+ rust_error_at (label.get_locus (),
+ "Labels must be a named lifetime value");
+ return;
+ }
+
+ NodeId resolved_node = UNKNOWN_NODEID;
+ if (!resolver->get_label_scope ().lookup (
+ CanonicalPath::new_seg (label.get_node_id (),
+ label.get_lifetime_name ()),
+ &resolved_node))
+ {
+ rust_error_at (expr.get_label ().get_locus (),
+ "failed to resolve label");
+ return;
+ }
+ resolver->insert_resolved_label (label.get_node_id (), resolved_node);
+ }
+}
+
+void
+ResolveExpr::visit (AST::BorrowExpr &expr)
+{
+ ResolveExpr::go (expr.get_borrowed_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::DereferenceExpr &expr)
+{
+ ResolveExpr::go (expr.get_dereferenced_expr ().get (), prefix,
+ canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::MatchExpr &expr)
+{
+ ResolveExpr::go (expr.get_scrutinee_expr ().get (), prefix, canonical_prefix);
+ for (auto &match_case : expr.get_match_cases ())
+ {
+ // each arm is in its own scope
+ NodeId scope_node_id = match_case.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ // resolve
+ AST::MatchArm &arm = match_case.get_arm ();
+ if (arm.has_match_arm_guard ())
+ ResolveExpr::go (arm.get_guard_expr ().get (), prefix,
+ canonical_prefix);
+
+ // insert any possible new patterns
+ for (auto &pattern : arm.get_patterns ())
+ {
+ PatternDeclaration::go (pattern.get ());
+ }
+
+ // resolve the body
+ ResolveExpr::go (match_case.get_expr ().get (), prefix, canonical_prefix);
+
+ // done
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+ }
+}
+
+void
+ResolveExpr::visit (AST::RangeFromToExpr &expr)
+{
+ ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::RangeFromExpr &expr)
+{
+ ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::RangeToExpr &expr)
+{
+ ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveExpr::visit (AST::RangeFullExpr &expr)
+{
+ // nothing to do
+}
+
+void
+ResolveExpr::visit (AST::RangeFromToInclExpr &expr)
+{
+ ResolveExpr::go (expr.get_from_expr ().get (), prefix, canonical_prefix);
+ ResolveExpr::go (expr.get_to_expr ().get (), prefix, canonical_prefix);
+}
+
+ResolveExpr::ResolveExpr (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+{}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,133 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_EXPR_H
+#define RUST_AST_RESOLVE_EXPR_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveExpr : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::Expr *expr, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ void visit (AST::TupleIndexExpr &expr) override;
+
+ void visit (AST::TupleExpr &expr) override;
+
+ void visit (AST::PathInExpression &expr) override;
+
+ void visit (AST::QualifiedPathInExpression &expr) override;
+
+ void visit (AST::ReturnExpr &expr) override;
+
+ void visit (AST::CallExpr &expr) override;
+
+ void visit (AST::MethodCallExpr &expr) override;
+
+ void visit (AST::AssignmentExpr &expr) override;
+
+ void visit (AST::IdentifierExpr &expr) override;
+
+ void visit (AST::ArithmeticOrLogicalExpr &expr) override;
+
+ void visit (AST::CompoundAssignmentExpr &expr) override;
+
+ void visit (AST::ComparisonExpr &expr) override;
+
+ void visit (AST::LazyBooleanExpr &expr) override;
+
+ void visit (AST::NegationExpr &expr) override;
+
+ void visit (AST::TypeCastExpr &expr) override;
+
+ void visit (AST::IfExpr &expr) override;
+
+ void visit (AST::IfExprConseqElse &expr) override;
+
+ void visit (AST::IfExprConseqIf &expr) override;
+
+ void visit (AST::IfLetExpr &expr) override;
+
+ void visit (AST::BlockExpr &expr) override;
+
+ void visit (AST::UnsafeBlockExpr &expr) override;
+
+ void visit (AST::ArrayElemsValues &elems) override;
+
+ void visit (AST::ArrayExpr &expr) override;
+
+ void visit (AST::ArrayIndexExpr &expr) override;
+
+ void visit (AST::ArrayElemsCopied &elems) override;
+
+ // this this an empty struct constructor like 'S {}'
+ void visit (AST::StructExprStruct &struct_expr) override;
+
+ // this this a struct constructor with fields
+ void visit (AST::StructExprStructFields &struct_expr) override;
+
+ void visit (AST::GroupedExpr &expr) override;
+
+ void visit (AST::FieldAccessExpr &expr) override;
+
+ void visit (AST::LoopExpr &expr) override;
+
+ void visit (AST::BreakExpr &expr) override;
+
+ void visit (AST::WhileLoopExpr &expr) override;
+
+ void visit (AST::ForLoopExpr &expr) override;
+
+ void visit (AST::ContinueExpr &expr) override;
+
+ void visit (AST::BorrowExpr &expr) override;
+
+ void visit (AST::DereferenceExpr &expr) override;
+
+ void visit (AST::MatchExpr &expr) override;
+
+ void visit (AST::RangeFromToExpr &expr) override;
+
+ void visit (AST::RangeFromExpr &expr) override;
+
+ void visit (AST::RangeToExpr &expr) override;
+
+ void visit (AST::RangeFullExpr &expr) override;
+
+ void visit (AST::RangeFromToInclExpr &expr) override;
+
+private:
+ ResolveExpr (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_EXPR_H
new file mode 100644
@@ -0,0 +1,275 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_IMPLITEM_H
+#define RUST_AST_RESOLVE_IMPLITEM_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveToplevelImplItem : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::InherentImplItem *item, const CanonicalPath &prefix)
+ {
+ if (item->is_marked_for_strip ())
+ return;
+
+ ResolveToplevelImplItem resolver (prefix);
+ item->accept_vis (resolver);
+ }
+
+ static void go (AST::TraitImplItem *item, const CanonicalPath &prefix)
+ {
+ if (item->is_marked_for_strip ())
+ return;
+
+ ResolveToplevelImplItem resolver (prefix);
+ item->accept_vis (resolver);
+ }
+
+ void visit (AST::TypeAlias &type) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (type.get_node_id (), type.get_new_type_name ());
+ auto path = prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, type.get_node_id (), type.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (type.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+ }
+
+ void visit (AST::ConstantItem &constant) override
+ {
+ auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+ constant.get_identifier ());
+ auto path = prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, constant.get_node_id (), constant.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (constant.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+ }
+
+ void visit (AST::Function &function) override
+ {
+ auto decl = CanonicalPath::new_seg (function.get_node_id (),
+ function.get_function_name ());
+ auto path = prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, function.get_node_id (), function.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (function.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+ }
+
+ void visit (AST::Method &method) override
+ {
+ auto decl = CanonicalPath::new_seg (method.get_node_id (),
+ method.get_method_name ());
+ auto path = prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, method.get_node_id (), method.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (method.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+ }
+
+private:
+ ResolveToplevelImplItem (const CanonicalPath &prefix)
+ : ResolverBase (), prefix (prefix)
+ {
+ rust_assert (!prefix.is_empty ());
+ }
+
+ const CanonicalPath &prefix;
+};
+
+class ResolveTopLevelTraitItems : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::TraitItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ {
+ ResolveTopLevelTraitItems resolver (prefix, canonical_prefix);
+ item->accept_vis (resolver);
+ };
+
+ void visit (AST::TraitItemFunc &function) override
+ {
+ auto decl = CanonicalPath::new_seg (
+ function.get_node_id (),
+ function.get_trait_function_decl ().get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, function.get_node_id (), function.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (function.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ mappings->insert_canonical_path (function.get_node_id (), cpath);
+ }
+
+ void visit (AST::TraitItemMethod &method) override
+ {
+ auto decl = CanonicalPath::new_seg (
+ method.get_node_id (), method.get_trait_method_decl ().get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, method.get_node_id (), method.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (method.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ mappings->insert_canonical_path (method.get_node_id (), cpath);
+ }
+
+ void visit (AST::TraitItemConst &constant) override
+ {
+ auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+ constant.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, constant.get_node_id (), constant.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (constant.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ mappings->insert_canonical_path (constant.get_node_id (), cpath);
+ }
+
+ void visit (AST::TraitItemType &type) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (type.get_node_id (), type.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, type.get_node_id (), type.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (type.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ mappings->insert_canonical_path (type.get_node_id (), cpath);
+ }
+
+private:
+ ResolveTopLevelTraitItems (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+ {}
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+class ResolveToplevelExternItem : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::ExternalItem *item, const CanonicalPath &prefix)
+ {
+ ResolveToplevelExternItem resolver (prefix);
+ item->accept_vis (resolver);
+ };
+
+ void visit (AST::ExternalFunctionItem &function) override
+ {
+ auto decl = CanonicalPath::new_seg (function.get_node_id (),
+ function.get_identifier ());
+ auto path = prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, function.get_node_id (), function.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (function.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ }
+
+ void visit (AST::ExternalStaticItem &item) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ }
+
+private:
+ ResolveToplevelExternItem (const CanonicalPath &prefix)
+ : ResolverBase (), prefix (prefix)
+ {}
+
+ const CanonicalPath &prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_IMPLITEM_H
new file mode 100644
@@ -0,0 +1,1237 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-item.h"
+#include "rust-ast-resolve-path.h"
+#include "selftest.h"
+
+namespace Rust {
+namespace Resolver {
+
+ResolveTraitItems::ResolveTraitItems (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+{}
+
+void
+ResolveTraitItems::go (AST::TraitItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ if (item->is_marked_for_strip ())
+ return;
+
+ ResolveTraitItems resolver (prefix, canonical_prefix);
+ item->accept_vis (resolver);
+}
+
+void
+ResolveTraitItems::visit (AST::TraitItemType &type)
+{
+ auto decl
+ = CanonicalPath::new_seg (type.get_node_id (), type.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (type.get_node_id (), cpath);
+
+ for (auto &bound : type.get_type_param_bounds ())
+ ResolveTypeBound::go (bound.get ());
+}
+
+void
+ResolveTraitItems::visit (AST::TraitItemFunc &func)
+{
+ auto decl = CanonicalPath::new_seg (
+ func.get_node_id (), func.get_trait_function_decl ().get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (func.get_node_id (), cpath);
+
+ NodeId scope_node_id = func.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ AST::TraitFunctionDecl &function = func.get_trait_function_decl ();
+ if (function.has_generics ())
+ for (auto &generic : function.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ if (function.has_return_type ())
+ ResolveType::go (function.get_return_type ().get ());
+
+ // 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 ());
+ }
+
+ if (function.has_where_clause ())
+ ResolveWhereClause::Resolve (function.get_where_clause ());
+
+ // trait items have an optional body
+ if (func.has_definition ())
+ ResolveExpr::go (func.get_definition ().get (), path, cpath);
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveTraitItems::visit (AST::TraitItemMethod &func)
+{
+ auto decl
+ = CanonicalPath::new_seg (func.get_node_id (),
+ func.get_trait_method_decl ().get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (func.get_node_id (), cpath);
+
+ NodeId scope_node_id = func.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ AST::TraitMethodDecl &function = func.get_trait_method_decl ();
+ if (function.has_generics ())
+ for (auto &generic : function.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ if (function.has_return_type ())
+ ResolveType::go (function.get_return_type ().get ());
+
+ // self turns into (self: Self) as a function param
+ AST::SelfParam &self_param = function.get_self_param ();
+ AST::IdentifierPattern self_pattern (self_param.get_node_id (), "self",
+ self_param.get_locus (),
+ self_param.get_has_ref (),
+ self_param.get_is_mut (),
+ std::unique_ptr<AST::Pattern> (nullptr));
+
+ std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
+ segments.push_back (std::unique_ptr<AST::TypePathSegment> (
+ new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
+
+ AST::TypePath self_type_path (std::move (segments), self_param.get_locus ());
+
+ ResolveType::go (&self_type_path);
+ PatternDeclaration::go (&self_pattern);
+
+ // 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 ());
+ }
+
+ if (function.has_where_clause ())
+ ResolveWhereClause::Resolve (function.get_where_clause ());
+
+ // trait items have an optional body
+ if (func.has_definition ())
+ ResolveExpr::go (func.get_definition ().get (), path, cpath);
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveTraitItems::visit (AST::TraitItemConst &constant)
+{
+ auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+ constant.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (constant.get_node_id (), cpath);
+
+ ResolveType::go (constant.get_type ().get ());
+
+ if (constant.has_expr ())
+ ResolveExpr::go (constant.get_expr ().get (), path, cpath);
+}
+
+ResolveItem::ResolveItem (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+{}
+
+void
+ResolveItem::go (AST::Item *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ ResolveItem resolver (prefix, canonical_prefix);
+ item->accept_vis (resolver);
+}
+
+void
+ResolveItem::visit (AST::TypeAlias &alias)
+{
+ auto talias
+ = CanonicalPath::new_seg (alias.get_node_id (), alias.get_new_type_name ());
+ auto path = prefix.append (talias);
+ auto cpath = canonical_prefix.append (talias);
+ mappings->insert_canonical_path (alias.get_node_id (), cpath);
+
+ NodeId scope_node_id = alias.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (alias.has_generics ())
+ for (auto &generic : alias.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ if (alias.has_where_clause ())
+ ResolveWhereClause::Resolve (alias.get_where_clause ());
+
+ ResolveType::go (alias.get_type_aliased ().get ());
+
+ resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Module &module)
+{
+ auto mod = CanonicalPath::new_seg (module.get_node_id (), module.get_name ());
+ auto path = prefix.append (mod);
+ auto cpath = canonical_prefix.append (mod);
+ mappings->insert_canonical_path (module.get_node_id (), cpath);
+
+ resolve_visibility (module.get_visibility ());
+
+ NodeId scope_node_id = module.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ // FIXME: Should we reinsert a child here? Any reason we ResolveTopLevel::go
+ // in ResolveTopLevel::visit (AST::Module) as well as here?
+ for (auto &item : module.get_items ())
+ ResolveTopLevel::go (item.get (), CanonicalPath::create_empty (), cpath);
+
+ resolver->push_new_module_scope (module.get_node_id ());
+ for (auto &item : module.get_items ())
+ ResolveItem::go (item.get (), path, cpath);
+
+ resolver->pop_module_scope ();
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::TupleStruct &struct_decl)
+{
+ auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+ struct_decl.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+
+ resolve_visibility (struct_decl.get_visibility ());
+
+ NodeId scope_node_id = struct_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (struct_decl.has_generics ())
+ for (auto &generic : struct_decl.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ if (struct_decl.has_where_clause ())
+ ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
+
+ for (AST::TupleField &field : struct_decl.get_fields ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ resolve_visibility (field.get_visibility ());
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+
+ resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Enum &enum_decl)
+{
+ auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (),
+ enum_decl.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (enum_decl.get_node_id (), cpath);
+
+ resolve_visibility (enum_decl.get_visibility ());
+
+ NodeId scope_node_id = enum_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (enum_decl.has_generics ())
+ for (auto &generic : enum_decl.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, cpath);
+
+ if (enum_decl.has_where_clause ())
+ ResolveWhereClause::Resolve (enum_decl.get_where_clause ());
+
+ /* The actual fields are inside the variants. */
+ for (auto &variant : enum_decl.get_variants ())
+ ResolveItem::go (variant.get (), path, cpath);
+
+ resolver->get_type_scope ().pop ();
+}
+
+/* EnumItem doesn't need to be handled, no fields. */
+void
+ResolveItem::visit (AST::EnumItem &item)
+{
+ // Since at this point we cannot have visibilities on enum items anymore, we
+ // can skip handling them
+
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+}
+
+void
+ResolveItem::visit (AST::EnumItemTuple &item)
+{
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+ for (auto &field : item.get_tuple_fields ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+}
+
+void
+ResolveItem::visit (AST::EnumItemStruct &item)
+{
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+ for (auto &field : item.get_struct_fields ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+}
+
+void
+ResolveItem::visit (AST::EnumItemDiscriminant &item)
+{
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+}
+
+void
+ResolveItem::visit (AST::StructStruct &struct_decl)
+{
+ auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+ struct_decl.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+
+ resolve_visibility (struct_decl.get_visibility ());
+
+ NodeId scope_node_id = struct_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (struct_decl.has_generics ())
+ for (auto &generic : struct_decl.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ if (struct_decl.has_where_clause ())
+ ResolveWhereClause::Resolve (struct_decl.get_where_clause ());
+
+ for (AST::StructField &field : struct_decl.get_fields ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ resolve_visibility (field.get_visibility ());
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+
+ resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Union &union_decl)
+{
+ auto decl = CanonicalPath::new_seg (union_decl.get_node_id (),
+ union_decl.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (union_decl.get_node_id (), cpath);
+
+ resolve_visibility (union_decl.get_visibility ());
+
+ NodeId scope_node_id = union_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (union_decl.has_generics ())
+ for (auto &generic : union_decl.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ if (union_decl.has_where_clause ())
+ ResolveWhereClause::Resolve (union_decl.get_where_clause ());
+
+ for (AST::StructField &field : union_decl.get_variants ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+
+ resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::StaticItem &var)
+{
+ auto decl
+ = CanonicalPath::new_seg (var.get_node_id (), var.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (var.get_node_id (), cpath);
+
+ ResolveType::go (var.get_type ().get ());
+ ResolveExpr::go (var.get_expr ().get (), path, cpath);
+}
+
+void
+ResolveItem::visit (AST::ConstantItem &constant)
+{
+ auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+ constant.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (constant.get_node_id (), cpath);
+
+ resolve_visibility (constant.get_visibility ());
+
+ ResolveType::go (constant.get_type ().get ());
+ ResolveExpr::go (constant.get_expr ().get (), path, cpath);
+}
+
+void
+ResolveItem::visit (AST::Function &function)
+{
+ auto decl = CanonicalPath::new_seg (function.get_node_id (),
+ function.get_function_name ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ mappings->insert_canonical_path (function.get_node_id (), cpath);
+
+ resolve_visibility (function.get_visibility ());
+
+ NodeId scope_node_id = function.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ if (function.has_generics ())
+ for (auto &generic : function.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ // resolve any where clause items
+ if (function.has_where_clause ())
+ ResolveWhereClause::Resolve (function.get_where_clause ());
+
+ if (function.has_return_type ())
+ ResolveType::go (function.get_return_type ().get ());
+
+ // 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 ());
+
+ // the mutability checker needs to verify for immutable decls the number
+ // of assignments are <1. This marks an implicit assignment
+ }
+
+ // resolve the function body
+ ResolveExpr::go (function.get_definition ().get (), path, cpath);
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::InherentImpl &impl_block)
+{
+ NodeId scope_node_id = impl_block.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+
+ resolve_visibility (impl_block.get_visibility ());
+
+ if (impl_block.has_generics ())
+ for (auto &generic : impl_block.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ // resolve any where clause items
+ if (impl_block.has_where_clause ())
+ ResolveWhereClause::Resolve (impl_block.get_where_clause ());
+
+ // FIXME this needs to be protected behind nominal type-checks see:
+ // rustc --explain E0118
+ ResolveType::go (impl_block.get_type ().get ());
+
+ // Setup paths
+ CanonicalPath self_cpath = CanonicalPath::create_empty ();
+ bool ok = ResolveTypeToCanonicalPath::go (impl_block.get_type ().get (),
+ self_cpath);
+ rust_assert (ok);
+ rust_debug ("AST::InherentImpl resolve Self: {%s}",
+ self_cpath.get ().c_str ());
+
+ CanonicalPath impl_type = self_cpath;
+ CanonicalPath impl_prefix = prefix.append (impl_type);
+
+ // see https://godbolt.org/z/a3vMbsT6W
+ CanonicalPath cpath = CanonicalPath::create_empty ();
+ if (canonical_prefix.size () <= 1)
+ {
+ cpath = self_cpath;
+ }
+ else
+ {
+ std::string seg_buf = "<impl " + self_cpath.get () + ">";
+ CanonicalPath seg
+ = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf);
+ cpath = canonical_prefix.append (seg);
+ }
+
+ // done setup paths
+
+ auto Self
+ = CanonicalPath::get_big_self (impl_block.get_type ()->get_node_id ());
+
+ resolver->get_type_scope ().insert (Self,
+ impl_block.get_type ()->get_node_id (),
+ impl_block.get_type ()->get_locus ());
+
+ for (auto &impl_item : impl_block.get_impl_items ())
+ {
+ rust_debug (
+ "AST::InherentImpl resolve_impl_item: impl_prefix={%s} cpath={%s}",
+ impl_prefix.get ().c_str (), cpath.get ().c_str ());
+ resolve_impl_item (impl_item.get (), impl_prefix, cpath);
+ }
+
+ resolver->get_type_scope ().peek ()->clear_name (
+ Self, impl_block.get_type ()->get_node_id ());
+
+ resolver->get_type_scope ().pop ();
+ resolver->get_name_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Method &method)
+{
+ auto decl
+ = CanonicalPath::new_seg (method.get_node_id (), method.get_method_name ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (method.get_node_id (), cpath);
+
+ NodeId scope_node_id = method.get_node_id ();
+
+ resolve_visibility (method.get_visibility ());
+
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ if (method.has_generics ())
+ for (auto &generic : method.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ // resolve any where clause items
+ if (method.has_where_clause ())
+ ResolveWhereClause::Resolve (method.get_where_clause ());
+
+ if (method.has_return_type ())
+ ResolveType::go (method.get_return_type ().get ());
+
+ // self turns into (self: Self) as a function param
+ AST::SelfParam &self_param = method.get_self_param ();
+ AST::IdentifierPattern self_pattern (self_param.get_node_id (), "self",
+ self_param.get_locus (),
+ self_param.get_has_ref (),
+ self_param.get_is_mut (),
+ std::unique_ptr<AST::Pattern> (nullptr));
+
+ std::vector<std::unique_ptr<AST::TypePathSegment>> segments;
+ segments.push_back (std::unique_ptr<AST::TypePathSegment> (
+ new AST::TypePathSegment ("Self", false, self_param.get_locus ())));
+
+ AST::TypePath self_type_path (std::move (segments), self_param.get_locus ());
+
+ ResolveType::go (&self_type_path);
+ PatternDeclaration::go (&self_pattern);
+
+ // 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 ());
+ }
+
+ // resolve any where clause items
+ if (method.has_where_clause ())
+ ResolveWhereClause::Resolve (method.get_where_clause ());
+
+ // resolve the function body
+ ResolveExpr::go (method.get_definition ().get (), path, cpath);
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::TraitImpl &impl_block)
+{
+ NodeId scope_node_id = impl_block.get_node_id ();
+
+ resolve_visibility (impl_block.get_visibility ());
+
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+
+ if (impl_block.has_generics ())
+ for (auto &generic : impl_block.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ // resolve any where clause items
+ if (impl_block.has_where_clause ())
+ ResolveWhereClause::Resolve (impl_block.get_where_clause ());
+
+ // CanonicalPath canonical_trait_type = CanonicalPath::create_empty ();
+ NodeId trait_resolved_node = ResolveType::go (&impl_block.get_trait_path ());
+ if (trait_resolved_node == UNKNOWN_NODEID)
+ {
+ resolver->get_type_scope ().pop ();
+ resolver->get_name_scope ().pop ();
+ return;
+ }
+
+ // CanonicalPath canonical_impl_type = CanonicalPath::create_empty ();
+ NodeId type_resolved_node = ResolveType::go (impl_block.get_type ().get ());
+ if (type_resolved_node == UNKNOWN_NODEID)
+ {
+ resolver->get_type_scope ().pop ();
+ resolver->get_name_scope ().pop ();
+ return;
+ }
+
+ bool ok;
+ // setup paths
+ CanonicalPath canonical_trait_type = CanonicalPath::create_empty ();
+ ok = ResolveTypeToCanonicalPath::go (&impl_block.get_trait_path (),
+ canonical_trait_type);
+ rust_assert (ok);
+
+ rust_debug ("AST::TraitImpl resolve trait type: {%s}",
+ canonical_trait_type.get ().c_str ());
+
+ CanonicalPath canonical_impl_type = CanonicalPath::create_empty ();
+ ok = ResolveTypeToCanonicalPath::go (impl_block.get_type ().get (),
+ canonical_impl_type);
+ rust_assert (ok);
+
+ rust_debug ("AST::TraitImpl resolve self: {%s}",
+ canonical_impl_type.get ().c_str ());
+
+ // raw paths
+ CanonicalPath impl_type_seg = canonical_impl_type;
+ CanonicalPath trait_type_seg = canonical_trait_type;
+ CanonicalPath projection
+ = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (),
+ trait_type_seg, impl_type_seg);
+ CanonicalPath impl_prefix = prefix.append (projection);
+
+ // setup canonical-path
+ CanonicalPath canonical_projection
+ = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (),
+ canonical_trait_type,
+ canonical_impl_type);
+ CanonicalPath cpath = CanonicalPath::create_empty ();
+ if (canonical_prefix.size () <= 1)
+ {
+ cpath = canonical_projection;
+ }
+ else
+ {
+ std::string projection_str = canonical_projection.get ();
+ std::string seg_buf
+ = "<impl " + projection_str.substr (1, projection_str.size () - 2)
+ + ">";
+ CanonicalPath seg
+ = CanonicalPath::new_seg (impl_block.get_node_id (), seg_buf);
+ cpath = canonical_prefix.append (seg);
+ }
+
+ // DONE setup canonical-path
+
+ auto Self
+ = CanonicalPath::get_big_self (impl_block.get_type ()->get_node_id ());
+
+ resolver->get_type_scope ().insert (Self,
+ impl_block.get_type ()->get_node_id (),
+ impl_block.get_type ()->get_locus ());
+
+ for (auto &impl_item : impl_block.get_impl_items ())
+ {
+ rust_debug (
+ "AST::TraitImpl resolve_impl_item: impl_prefix={%s} cpath={%s}",
+ impl_prefix.get ().c_str (), cpath.get ().c_str ());
+ resolve_impl_item (impl_item.get (), impl_prefix, cpath);
+ }
+
+ resolver->get_type_scope ().peek ()->clear_name (
+ Self, impl_block.get_type ()->get_node_id ());
+ resolver->get_type_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::Trait &trait)
+{
+ NodeId scope_node_id = trait.get_node_id ();
+
+ resolve_visibility (trait.get_visibility ());
+
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+
+ // we need to inject an implicit self TypeParam here
+ AST::TypeParam *implicit_self
+ = new AST::TypeParam ("Self", trait.get_locus ());
+ trait.insert_implict_self (
+ std::unique_ptr<AST::GenericParam> (implicit_self));
+ CanonicalPath Self = CanonicalPath::get_big_self (trait.get_node_id ());
+
+ for (auto &generic : trait.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ // Self is an implicit TypeParam so lets mark it as such
+ resolver->get_type_scope ().append_reference_for_def (
+ Self.get_node_id (), implicit_self->get_node_id ());
+
+ if (trait.has_type_param_bounds ())
+ {
+ for (auto &bound : trait.get_type_param_bounds ())
+ {
+ ResolveTypeBound::go (bound.get ());
+ }
+ }
+
+ // resolve any where clause items
+ if (trait.has_where_clause ())
+ ResolveWhereClause::Resolve (trait.get_where_clause ());
+
+ // resolve the paths
+ CanonicalPath path = CanonicalPath::create_empty ();
+ CanonicalPath cpath = CanonicalPath::create_empty ();
+ //
+
+ for (auto &item : trait.get_trait_items ())
+ {
+ ResolveTraitItems::go (item.get (), path, cpath);
+ }
+
+ resolver->get_type_scope ().pop ();
+ resolver->get_name_scope ().pop ();
+}
+
+void
+ResolveItem::visit (AST::ExternBlock &extern_block)
+{
+ resolve_visibility (extern_block.get_visibility ());
+
+ for (auto &item : extern_block.get_extern_items ())
+ {
+ resolve_extern_item (item.get ());
+ }
+}
+
+void
+ResolveItem::resolve_impl_item (AST::TraitImplItem *item,
+ const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ ResolveImplItems::go (item, prefix, canonical_prefix);
+}
+
+void
+ResolveItem::resolve_impl_item (AST::InherentImplItem *item,
+ const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ ResolveImplItems::go (item, prefix, canonical_prefix);
+}
+
+void
+ResolveItem::resolve_extern_item (AST::ExternalItem *item)
+{
+ ResolveExternItem::go (item, prefix, canonical_prefix);
+}
+
+static void
+flatten_glob (const AST::UseTreeGlob &glob,
+ std::vector<AST::SimplePath> &paths);
+static void
+flatten_rebind (const AST::UseTreeRebind &glob,
+ std::vector<AST::SimplePath> &paths);
+static void
+flatten_list (const AST::UseTreeList &glob,
+ std::vector<AST::SimplePath> &paths);
+
+static void
+flatten (const AST::UseTree *tree, std::vector<AST::SimplePath> &paths)
+{
+ switch (tree->get_kind ())
+ {
+ case AST::UseTree::Glob: {
+ auto glob = static_cast<const AST::UseTreeGlob *> (tree);
+ flatten_glob (*glob, paths);
+ break;
+ }
+ case AST::UseTree::Rebind: {
+ auto rebind = static_cast<const AST::UseTreeRebind *> (tree);
+ flatten_rebind (*rebind, paths);
+ break;
+ }
+ case AST::UseTree::List: {
+ auto list = static_cast<const AST::UseTreeList *> (tree);
+ flatten_list (*list, paths);
+ break;
+ }
+ break;
+ }
+}
+
+static void
+flatten_glob (const AST::UseTreeGlob &glob, std::vector<AST::SimplePath> &paths)
+{
+ if (glob.has_path ())
+ paths.emplace_back (glob.get_path ());
+}
+
+static void
+flatten_rebind (const AST::UseTreeRebind &rebind,
+ std::vector<AST::SimplePath> &paths)
+{
+ auto path = rebind.get_path ();
+ if (rebind.has_path ())
+ paths.emplace_back (path);
+
+ // FIXME: Do we want to emplace the rebind here as well?
+ if (rebind.has_identifier ())
+ {
+ auto rebind_path = path;
+ auto new_seg = rebind.get_identifier ();
+
+ // Add the identifier as a new path
+ rebind_path.get_segments ().back ()
+ = AST::SimplePathSegment (new_seg, Location ());
+
+ paths.emplace_back (rebind_path);
+ }
+}
+
+static void
+flatten_list (const AST::UseTreeList &list, std::vector<AST::SimplePath> &paths)
+{
+ auto prefix = AST::SimplePath::create_empty ();
+ if (list.has_path ())
+ prefix = list.get_path ();
+
+ for (const auto &tree : list.get_trees ())
+ {
+ auto sub_paths = std::vector<AST::SimplePath> ();
+ flatten (tree.get (), sub_paths);
+
+ for (auto &sub_path : sub_paths)
+ {
+ auto new_path = prefix;
+ std::copy (sub_path.get_segments ().begin (),
+ sub_path.get_segments ().end (),
+ std::back_inserter (new_path.get_segments ()));
+
+ paths.emplace_back (new_path);
+ }
+ }
+}
+
+/**
+ * Flatten a UseDeclaration's UseTree into multiple simple paths to resolve.
+ *
+ * Given the following use declarations:
+ * ```
+ * use some::path::to_resolve; #1
+ * use some::path::to_glob::*; #2
+ * use some::path::{one, two}; #2
+ * ```
+ *
+ * In the first case, we simply want to return a vector with a single
+ * SimplePath:
+ * [some::path::to_resolve]
+ *
+ * In the second case, we want to resolve the glob's "origin path":
+ * [some::path::to_glob]
+ *
+ * Finally in the third case, we want to create two SimplePaths to resolve:
+ * [some::path::one, some::path::two]
+ */
+static std::vector<AST::SimplePath>
+flatten_use_dec_to_paths (const AST::UseDeclaration &use_item)
+{
+ auto paths = std::vector<AST::SimplePath> ();
+
+ const auto &tree = use_item.get_tree ();
+ flatten (tree.get (), paths);
+
+ return paths;
+}
+
+void
+ResolveItem::visit (AST::UseDeclaration &use_item)
+{
+ auto to_resolve = flatten_use_dec_to_paths (use_item);
+
+ for (auto &path : to_resolve)
+ ResolvePath::go (&path);
+}
+
+ResolveImplItems::ResolveImplItems (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolveItem (prefix, canonical_prefix)
+{}
+
+void
+ResolveImplItems::go (AST::InherentImplItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ if (item->is_marked_for_strip ())
+ return;
+
+ ResolveImplItems resolver (prefix, canonical_prefix);
+ item->accept_vis (resolver);
+}
+
+void
+ResolveImplItems::go (AST::TraitImplItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ if (item->is_marked_for_strip ())
+ return;
+
+ ResolveImplItems resolver (prefix, canonical_prefix);
+ item->accept_vis (resolver);
+}
+
+void
+ResolveImplItems::visit (AST::TypeAlias &alias)
+{
+ ResolveItem::visit (alias);
+
+ resolve_visibility (alias.get_visibility ());
+
+ // FIXME this stops the erronious unused decls which will be fixed later on
+ resolver->get_type_scope ().append_reference_for_def (alias.get_node_id (),
+ alias.get_node_id ());
+}
+
+void
+ResolveExternItem::go (AST::ExternalItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ ResolveExternItem resolver (prefix, canonical_prefix);
+ item->accept_vis (resolver);
+}
+
+void
+ResolveExternItem::visit (AST::ExternalFunctionItem &function)
+{
+ NodeId scope_node_id = function.get_node_id ();
+ auto decl = CanonicalPath::new_seg (function.get_node_id (),
+ function.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ mappings->insert_canonical_path (function.get_node_id (), cpath);
+
+ resolve_visibility (function.get_visibility ());
+
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ // resolve the generics
+ if (function.has_generics ())
+ for (auto &generic : function.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ if (function.has_return_type ())
+ ResolveType::go (function.get_return_type ().get ());
+
+ // 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 ());
+ }
+
+ // done
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+}
+
+void
+ResolveExternItem::visit (AST::ExternalStaticItem &item)
+{
+ resolve_visibility (item.get_visibility ());
+
+ ResolveType::go (item.get_type ().get ());
+}
+
+} // namespace Resolver
+} // namespace Rust
+
+#if CHECKING_P
+
+namespace selftest {
+
+static void
+rust_flatten_nested_glob (void)
+{
+ auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+ auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+ auto foobar = Rust::AST::SimplePath ({foo, bar});
+
+ auto glob
+ = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
+ foobar, Location ());
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_glob (glob, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 1);
+ ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+}
+
+static void
+rust_flatten_glob (void)
+{
+ auto frob = Rust::AST::SimplePath::from_str ("frobulator", Location ());
+
+ auto glob
+ = Rust::AST::UseTreeGlob (Rust::AST::UseTreeGlob::PathType::PATH_PREFIXED,
+ frob, Location ());
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_glob (glob, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 1);
+ ASSERT_EQ (paths[0], "frobulator");
+}
+
+static void
+rust_flatten_rebind_none (void)
+{
+ auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+ auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+ auto foobar = Rust::AST::SimplePath ({foo, bar});
+
+ auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE,
+ foobar, Location ());
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_rebind (rebind, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 1);
+ ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+}
+
+static void
+rust_flatten_rebind (void)
+{
+ auto frob = Rust::AST::SimplePath::from_str ("frobulator", Location ());
+
+ auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
+ frob, Location (), "saindoux");
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_rebind (rebind, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 2);
+ ASSERT_EQ (paths[0], "frobulator");
+ ASSERT_EQ (paths[1], "saindoux");
+}
+
+static void
+rust_flatten_rebind_nested (void)
+{
+ auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+ auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+ auto baz = Rust::AST::SimplePathSegment ("baz", Location ());
+
+ auto foo_bar_baz = Rust::AST::SimplePath ({foo, bar, baz});
+
+ auto rebind = Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::IDENTIFIER,
+ foo_bar_baz, Location (), "saindoux");
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_rebind (rebind, paths);
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 2);
+ ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+ ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
+ ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
+ ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "saindoux");
+}
+
+static void
+rust_flatten_list (void)
+{
+ auto foo = Rust::AST::SimplePathSegment ("foo", Location ());
+ auto bar = Rust::AST::SimplePathSegment ("bar", Location ());
+ auto foo_bar = Rust::AST::SimplePath ({foo, bar});
+
+ auto baz = Rust::AST::SimplePath::from_str ("baz", Location ());
+ auto bul = Rust::AST::SimplePath::from_str ("bul", Location ());
+
+ // use foo::bar::{baz, bul};
+
+ auto use0 = std::unique_ptr<Rust::AST::UseTree> (
+ new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, baz,
+ Location ()));
+ auto use1 = std::unique_ptr<Rust::AST::UseTree> (
+ new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, bul,
+ Location ()));
+
+ auto uses = std::vector<std::unique_ptr<Rust::AST::UseTree>> ();
+ uses.emplace_back (std::move (use0));
+ uses.emplace_back (std::move (use1));
+
+ auto list = Rust::AST::UseTreeList (Rust::AST::UseTreeList::PATH_PREFIXED,
+ foo_bar, std::move (uses), Location ());
+
+ auto paths = std::vector<Rust::AST::SimplePath> ();
+ Rust::Resolver::flatten_list (list, paths);
+
+ for (auto &path : paths)
+ fprintf (stderr, "%s\n", path.as_string ().c_str ());
+
+ ASSERT_TRUE (!paths.empty ());
+ ASSERT_EQ (paths.size (), 2);
+ ASSERT_EQ (paths[0].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[0].get_segments ()[1].as_string (), "bar");
+ ASSERT_EQ (paths[0].get_segments ()[2].as_string (), "baz");
+ ASSERT_EQ (paths[1].get_segments ()[0].as_string (), "foo");
+ ASSERT_EQ (paths[1].get_segments ()[1].as_string (), "bar");
+ ASSERT_EQ (paths[1].get_segments ()[2].as_string (), "bul");
+}
+
+static void
+rust_use_dec_flattening (void)
+{
+ rust_flatten_glob ();
+ rust_flatten_nested_glob ();
+ rust_flatten_rebind_none ();
+ rust_flatten_rebind ();
+ rust_flatten_rebind_nested ();
+ rust_flatten_list ();
+}
+
+void
+rust_simple_path_resolve_test (void)
+{
+ rust_use_dec_flattening ();
+}
+
+} // namespace selftest
+
+#endif // CHECKING_P
new file mode 100644
@@ -0,0 +1,149 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_ITEM_H
+#define RUST_AST_RESOLVE_ITEM_H
+
+#include "rust-ast-full-decls.h"
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+#include "rust-ast-resolve-toplevel.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-pattern.h"
+#include "rust-ast-resolve-stmt.h"
+#include "config.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveTraitItems : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::TraitItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ void visit (AST::TraitItemType &type) override;
+ void visit (AST::TraitItemFunc &func) override;
+ void visit (AST::TraitItemMethod &func) override;
+ void visit (AST::TraitItemConst &constant) override;
+
+private:
+ ResolveTraitItems (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+class ResolveItem : public ResolverBase
+{
+public:
+ using Rust::Resolver::ResolverBase::visit;
+
+ static void go (AST::Item *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ void visit (AST::TypeAlias &alias) override;
+ void visit (AST::Module &module) override;
+ void visit (AST::TupleStruct &struct_decl) override;
+ void visit (AST::Enum &enum_decl) override;
+ /* EnumItem doesn't need to be handled, no fields. */
+ void visit (AST::EnumItem &item) override;
+ void visit (AST::EnumItemTuple &item) override;
+ void visit (AST::EnumItemStruct &item) override;
+ void visit (AST::EnumItemDiscriminant &item) override;
+ void visit (AST::StructStruct &struct_decl) override;
+ void visit (AST::Union &union_decl) override;
+ void visit (AST::StaticItem &var) override;
+ void visit (AST::ConstantItem &constant) override;
+ void visit (AST::Function &function) override;
+ void visit (AST::InherentImpl &impl_block) override;
+ void visit (AST::Method &method) override;
+ void visit (AST::TraitImpl &impl_block) override;
+ void visit (AST::Trait &trait) override;
+ void visit (AST::ExternBlock &extern_block) override;
+ void visit (AST::UseDeclaration &) override;
+
+protected:
+ void resolve_impl_item (AST::TraitImplItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+ void resolve_impl_item (AST::InherentImplItem *item,
+ const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+ void resolve_extern_item (AST::ExternalItem *item);
+
+ ResolveItem (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+class ResolveImplItems : public ResolveItem
+{
+ using Rust::Resolver::ResolveItem::visit;
+
+public:
+ static void go (AST::InherentImplItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+ static void go (AST::TraitImplItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ void visit (AST::TypeAlias &alias) override;
+
+private:
+ ResolveImplItems (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+};
+
+class ResolveExternItem : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::ExternalItem *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ void visit (AST::ExternalFunctionItem &function) override;
+ void visit (AST::ExternalStaticItem &item) override;
+
+private:
+ ResolveExternItem (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+ {}
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#if CHECKING_P
+
+namespace selftest {
+extern void
+rust_simple_path_resolve_test (void);
+} // namespace selftest
+
+#endif // CHECKING_P
+
+#endif // RUST_AST_RESOLVE_ITEM_H
new file mode 100644
@@ -0,0 +1,384 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-path.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-path.h"
+
+namespace Rust {
+namespace Resolver {
+
+ResolvePath::ResolvePath () : ResolverBase () {}
+
+void
+ResolvePath::go (AST::PathInExpression *expr)
+{
+ ResolvePath resolver;
+ resolver.resolve_path (expr);
+}
+
+void
+ResolvePath::go (AST::QualifiedPathInExpression *expr)
+{
+ ResolvePath resolver;
+ resolver.resolve_path (expr);
+}
+
+void
+ResolvePath::go (AST::SimplePath *expr)
+{
+ ResolvePath resolver;
+ resolver.resolve_path (expr);
+}
+
+void
+ResolvePath::resolve_path (AST::PathInExpression *expr)
+{
+ NodeId resolved_node_id = UNKNOWN_NODEID;
+ NodeId module_scope_id = resolver->peek_current_module_scope ();
+ NodeId previous_resolved_node_id = module_scope_id;
+ for (size_t i = 0; i < expr->get_segments ().size (); i++)
+ {
+ auto &segment = expr->get_segments ().at (i);
+ const AST::PathIdentSegment &ident_seg = segment.get_ident_segment ();
+ bool is_first_segment = i == 0;
+ resolved_node_id = UNKNOWN_NODEID;
+
+ bool in_middle_of_path = i > 0;
+ if (in_middle_of_path && segment.is_lower_self_seg ())
+ {
+ // error[E0433]: failed to resolve: `self` in paths can only be used
+ // in start position
+ rust_error_at (segment.get_locus (),
+ "failed to resolve: %<%s%> in paths can only be used "
+ "in start position",
+ segment.as_string ().c_str ());
+ return;
+ }
+
+ NodeId crate_scope_id = resolver->peek_crate_module_scope ();
+ if (segment.is_crate_path_seg ())
+ {
+ // what is the current crate scope node id?
+ module_scope_id = crate_scope_id;
+ previous_resolved_node_id = module_scope_id;
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
+ continue;
+ }
+ else if (segment.is_super_path_seg ())
+ {
+ if (module_scope_id == crate_scope_id)
+ {
+ rust_error_at (segment.get_locus (),
+ "cannot use %<super%> at the crate scope");
+ return;
+ }
+
+ module_scope_id = resolver->peek_parent_module_scope ();
+ previous_resolved_node_id = module_scope_id;
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
+ continue;
+ }
+
+ // resolve any generic args
+ if (segment.has_generic_args ())
+ ResolveGenericArgs::go (segment.get_generic_args ());
+
+ // logic is awkward here there are a few cases
+ //
+ // T::Default
+ // mod::foo::impl_item
+ // super::super::module::item
+ // self
+ // self::foo
+ // self::foo::baz
+ //
+ // T::Default we can only resolve the T and cant do anything about Default
+ // its dependant on associated types
+ //
+ // mod::foo::impl_item
+ // we can resolve mod::foo but nothing about impl_item but we need to
+ // _always resolve generic arguments
+ //
+ // self is a simple single lookup
+ //
+ // we have module_scope_id for the next module_scope to lookup
+ // resolved_node_id is the thing we have resolve this segment to
+ //
+ // new algo?
+ // we can only use module resolution when the previous segment is either
+ // unknown or equal to this module_scope_id
+ //
+ // can only use old resolution when previous segment is unkown
+
+ if (is_first_segment)
+ {
+ // name scope first
+ NodeId resolved_node = UNKNOWN_NODEID;
+ const CanonicalPath path
+ = CanonicalPath::new_seg (segment.get_node_id (),
+ ident_seg.as_string ());
+ if (resolver->get_name_scope ().lookup (path, &resolved_node))
+ {
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
+ resolved_node_id = resolved_node;
+ }
+ // check the type scope
+ else if (resolver->get_type_scope ().lookup (path, &resolved_node))
+ {
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
+ resolved_node_id = resolved_node;
+ }
+ else if (segment.is_lower_self_seg ())
+ {
+ module_scope_id = crate_scope_id;
+ previous_resolved_node_id = module_scope_id;
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
+ continue;
+ }
+ else
+ {
+ // no error handling here since we might be able to resolve via
+ // the module hierarchy and handle errors at the end
+ }
+ }
+
+ if (resolved_node_id == UNKNOWN_NODEID
+ && previous_resolved_node_id == module_scope_id)
+ {
+ Optional<CanonicalPath &> resolved_child
+ = mappings->lookup_module_child (module_scope_id,
+ ident_seg.as_string ());
+ if (resolved_child.is_some ())
+ {
+ NodeId resolved_node = resolved_child->get_node_id ();
+ if (resolver->get_name_scope ().decl_was_declared_here (
+ resolved_node))
+ {
+ resolved_node_id = resolved_node;
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
+ }
+ else if (resolver->get_type_scope ().decl_was_declared_here (
+ resolved_node))
+ {
+ resolved_node_id = resolved_node;
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
+ }
+ else
+ {
+ rust_error_at (segment.get_locus (),
+ "Cannot find path %<%s%> in this scope",
+ segment.as_string ().c_str ());
+ return;
+ }
+ }
+ }
+
+ bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID;
+ if (did_resolve_segment)
+ {
+ if (mappings->node_is_module (resolved_node_id)
+ || mappings->node_is_crate (resolved_node_id))
+ {
+ module_scope_id = resolved_node_id;
+ }
+ previous_resolved_node_id = resolved_node_id;
+ }
+ else if (is_first_segment)
+ {
+ rust_error_at (segment.get_locus (),
+ "Cannot find path %<%s%> in this scope",
+ segment.as_string ().c_str ());
+ return;
+ }
+ }
+
+ resolved_node = resolved_node_id;
+ if (resolved_node_id != UNKNOWN_NODEID)
+ {
+ // name scope first
+ if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
+ {
+ resolver->insert_resolved_name (expr->get_node_id (),
+ resolved_node_id);
+ }
+ // check the type scope
+ else if (resolver->get_type_scope ().decl_was_declared_here (
+ resolved_node_id))
+ {
+ resolver->insert_resolved_type (expr->get_node_id (),
+ resolved_node_id);
+ }
+ else
+ {
+ gcc_unreachable ();
+ }
+ }
+}
+
+void
+ResolvePath::resolve_path (AST::QualifiedPathInExpression *expr)
+{
+ AST::QualifiedPathType &root_segment = expr->get_qualified_path_type ();
+ ResolveType::go (root_segment.get_type ().get ());
+ if (root_segment.has_as_clause ())
+ ResolveType::go (&root_segment.get_as_type_path ());
+
+ for (auto &segment : expr->get_segments ())
+ {
+ // we cant actually do anything with the segment itself since this is all
+ // the job of the type system to figure it out but we can resolve any
+ // generic arguments used
+ if (segment.has_generic_args ())
+ ResolveGenericArgs::go (segment.get_generic_args ());
+ }
+}
+
+void
+ResolvePath::resolve_path (AST::SimplePath *expr)
+{
+ NodeId crate_scope_id = resolver->peek_crate_module_scope ();
+ NodeId module_scope_id = resolver->peek_current_module_scope ();
+
+ NodeId resolved_node_id = UNKNOWN_NODEID;
+ for (size_t i = 0; i < expr->get_segments ().size (); i++)
+ {
+ auto &segment = expr->get_segments ().at (i);
+ bool is_first_segment = i == 0;
+ resolved_node_id = UNKNOWN_NODEID;
+
+ if (segment.is_crate_path_seg ())
+ {
+ // what is the current crate scope node id?
+ module_scope_id = crate_scope_id;
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
+ continue;
+ }
+ else if (segment.is_super_path_seg ())
+ {
+ if (module_scope_id == crate_scope_id)
+ {
+ rust_error_at (segment.get_locus (),
+ "cannot use %<super%> at the crate scope");
+ return;
+ }
+
+ module_scope_id = resolver->peek_parent_module_scope ();
+ resolver->insert_resolved_name (segment.get_node_id (),
+ module_scope_id);
+ continue;
+ }
+
+ Optional<CanonicalPath &> resolved_child
+ = mappings->lookup_module_child (module_scope_id,
+ segment.get_segment_name ());
+ if (resolved_child.is_some ())
+ {
+ NodeId resolved_node = resolved_child->get_node_id ();
+ if (resolver->get_name_scope ().decl_was_declared_here (
+ resolved_node))
+ {
+ resolved_node_id = resolved_node;
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
+ }
+ else if (resolver->get_type_scope ().decl_was_declared_here (
+ resolved_node))
+ {
+ resolved_node_id = resolved_node;
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
+ }
+ else
+ {
+ rust_error_at (segment.get_locus (),
+ "Cannot find path %<%s%> in this scope",
+ segment.as_string ().c_str ());
+ return;
+ }
+ }
+
+ if (resolved_node_id == UNKNOWN_NODEID && is_first_segment)
+ {
+ // name scope first
+ NodeId resolved_node = UNKNOWN_NODEID;
+ const CanonicalPath path
+ = CanonicalPath::new_seg (segment.get_node_id (),
+ segment.get_segment_name ());
+ if (resolver->get_name_scope ().lookup (path, &resolved_node))
+ {
+ resolved_node_id = resolved_node;
+ resolver->insert_resolved_name (segment.get_node_id (),
+ resolved_node);
+ }
+ // check the type scope
+ else if (resolver->get_type_scope ().lookup (path, &resolved_node))
+ {
+ resolved_node_id = resolved_node;
+ resolver->insert_resolved_type (segment.get_node_id (),
+ resolved_node);
+ }
+ }
+
+ if (resolved_node_id == UNKNOWN_NODEID)
+ {
+ rust_error_at (segment.get_locus (),
+ "cannot find simple path segment %<%s%> in this scope",
+ segment.as_string ().c_str ());
+ return;
+ }
+
+ if (mappings->node_is_module (resolved_node_id))
+ {
+ module_scope_id = resolved_node_id;
+ }
+ }
+
+ resolved_node = resolved_node_id;
+ if (resolved_node_id != UNKNOWN_NODEID)
+ {
+ // name scope first
+ if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
+ {
+ resolver->insert_resolved_name (expr->get_node_id (),
+ resolved_node_id);
+ }
+ // check the type scope
+ else if (resolver->get_type_scope ().decl_was_declared_here (
+ resolved_node_id))
+ {
+ resolver->insert_resolved_type (expr->get_node_id (),
+ resolved_node_id);
+ }
+ else
+ {
+ gcc_unreachable ();
+ }
+ }
+}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,52 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_PATH_H
+#define RUST_AST_RESOLVE_PATH_H
+
+#include "rust-ast-resolve-base.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolvePath : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::PathInExpression *expr);
+ static void go (AST::QualifiedPathInExpression *expr);
+ static void go (AST::SimplePath *expr);
+
+private:
+ ResolvePath ();
+
+ void resolve_path (AST::PathInExpression *expr);
+ void resolve_path (AST::QualifiedPathInExpression *expr);
+ void resolve_path (AST::SimplePath *expr);
+
+ void
+ resolve_simple_path_segments (CanonicalPath prefix, size_t offs,
+ const std::vector<AST::SimplePathSegment> &segs,
+ NodeId expr_node_id, Location expr_locus);
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // !RUST_AST_RESOLVE_PATH_H
new file mode 100644
@@ -0,0 +1,163 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-pattern.h"
+#include "rust-ast-resolve-path.h"
+#include "rust-ast-resolve-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+PatternDeclaration::visit (AST::PathInExpression &pattern)
+{
+ ResolvePath::go (&pattern);
+}
+
+void
+PatternDeclaration::visit (AST::TupleStructPattern &pattern)
+{
+ ResolvePath::go (&pattern.get_path ());
+
+ std::unique_ptr<AST::TupleStructItems> &items = pattern.get_items ();
+ switch (items->get_item_type ())
+ {
+ case AST::TupleStructItems::RANGE: {
+ // TODO
+ gcc_unreachable ();
+ }
+ break;
+
+ case AST::TupleStructItems::NO_RANGE: {
+ AST::TupleStructItemsNoRange &items_no_range
+ = static_cast<AST::TupleStructItemsNoRange &> (*items.get ());
+
+ for (auto &inner_pattern : items_no_range.get_patterns ())
+ {
+ PatternDeclaration::go (inner_pattern.get ());
+ }
+ }
+ break;
+ }
+}
+
+void
+PatternDeclaration::visit (AST::StructPattern &pattern)
+{
+ ResolvePath::go (&pattern.get_path ());
+
+ auto &struct_pattern_elems = pattern.get_struct_pattern_elems ();
+ for (auto &field : struct_pattern_elems.get_struct_pattern_fields ())
+ {
+ switch (field->get_item_type ())
+ {
+ case AST::StructPatternField::ItemType::TUPLE_PAT: {
+ // TODO
+ gcc_unreachable ();
+ }
+ break;
+
+ case AST::StructPatternField::ItemType::IDENT_PAT: {
+ // TODO
+ gcc_unreachable ();
+ }
+ break;
+
+ case AST::StructPatternField::ItemType::IDENT: {
+ AST::StructPatternFieldIdent &ident
+ = static_cast<AST::StructPatternFieldIdent &> (*field.get ());
+
+ resolver->get_name_scope ().insert (
+ CanonicalPath::new_seg (ident.get_node_id (),
+ ident.get_identifier ()),
+ ident.get_node_id (), ident.get_locus ());
+ }
+ break;
+ }
+ }
+
+ // TODO
+ rust_assert (!struct_pattern_elems.has_etc ());
+}
+
+void
+PatternDeclaration::visit (AST::TuplePattern &pattern)
+{
+ std::unique_ptr<AST::TuplePatternItems> &items = pattern.get_items ();
+ switch (items->get_pattern_type ())
+ {
+ case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: {
+ AST::TuplePatternItemsMultiple &ref
+ = *static_cast<AST::TuplePatternItemsMultiple *> (
+ pattern.get_items ().get ());
+
+ for (auto &p : ref.get_patterns ())
+ p->accept_vis (*this);
+ }
+ break;
+
+ case AST::TuplePatternItems::TuplePatternItemType::RANGED: {
+ AST::TuplePatternItemsRanged &ref
+ = *static_cast<AST::TuplePatternItemsRanged *> (
+ pattern.get_items ().get ());
+
+ for (auto &p : ref.get_lower_patterns ())
+ p->accept_vis (*this);
+ for (auto &p : ref.get_upper_patterns ())
+ p->accept_vis (*this);
+ }
+ break;
+ }
+}
+
+static void
+resolve_range_pattern_bound (AST::RangePatternBound *bound)
+{
+ switch (bound->get_bound_type ())
+ {
+ case AST::RangePatternBound::RangePatternBoundType::LITERAL:
+ // Nothing to resolve for a literal.
+ break;
+
+ case AST::RangePatternBound::RangePatternBoundType::PATH: {
+ AST::RangePatternBoundPath &ref
+ = *static_cast<AST::RangePatternBoundPath *> (bound);
+
+ ResolvePath::go (&ref.get_path ());
+ }
+ break;
+
+ case AST::RangePatternBound::RangePatternBoundType::QUALPATH: {
+ AST::RangePatternBoundQualPath &ref
+ = *static_cast<AST::RangePatternBoundQualPath *> (bound);
+
+ ResolvePath::go (&ref.get_qualified_path ());
+ }
+ break;
+ }
+}
+
+void
+PatternDeclaration::visit (AST::RangePattern &pattern)
+{
+ resolve_range_pattern_bound (pattern.get_upper_bound ().get ());
+ resolve_range_pattern_bound (pattern.get_lower_bound ().get ());
+}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,98 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_PATTERN_H
+#define RUST_AST_RESOLVE_PATTERN_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolvePattern : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::Pattern *pattern)
+ {
+ ResolvePattern resolver;
+ pattern->accept_vis (resolver);
+ }
+
+ void visit (AST::IdentifierPattern &pattern) override
+ {
+ if (resolver->get_name_scope ().lookup (
+ CanonicalPath::new_seg (pattern.get_node_id (), pattern.get_ident ()),
+ &resolved_node))
+ {
+ resolver->insert_resolved_name (pattern.get_node_id (), resolved_node);
+ }
+ }
+
+private:
+ ResolvePattern () : ResolverBase () {}
+};
+
+class PatternDeclaration : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::Pattern *pattern)
+ {
+ PatternDeclaration resolver;
+ pattern->accept_vis (resolver);
+ };
+
+ 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 ());
+ }
+
+ void visit (AST::WildcardPattern &pattern) override
+ {
+ resolver->get_name_scope ().insert (
+ CanonicalPath::new_seg (pattern.get_node_id (), "_"),
+ pattern.get_node_id (), pattern.get_locus ());
+ }
+
+ // cases in a match expression
+ 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 () : ResolverBase () {}
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_PATTERN_H
new file mode 100644
@@ -0,0 +1,38 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-item.h"
+#include "rust-ast-resolve-stmt.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+ResolveStmt::visit (AST::ExternBlock &extern_block)
+{
+ resolve_visibility (extern_block.get_visibility ());
+ for (auto &item : extern_block.get_extern_items ())
+ {
+ ResolveToplevelExternItem::go (item.get (),
+ CanonicalPath::create_empty ());
+ ResolveExternItem::go (item.get (), prefix, canonical_prefix);
+ }
+}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,378 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_STMT_H
+#define RUST_AST_RESOLVE_STMT_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-pattern.h"
+#include "rust-ast-resolve-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveStmt : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::Stmt *stmt, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix,
+ const CanonicalPath &enum_prefix)
+ {
+ if (stmt->is_marked_for_strip ())
+ return;
+
+ ResolveStmt resolver (prefix, canonical_prefix, enum_prefix);
+ stmt->accept_vis (resolver);
+ }
+
+ void visit (AST::ExprStmtWithBlock &stmt) override
+ {
+ ResolveExpr::go (stmt.get_expr ().get (), prefix, canonical_prefix);
+ }
+
+ void visit (AST::ExprStmtWithoutBlock &stmt) override
+ {
+ ResolveExpr::go (stmt.get_expr ().get (), prefix, canonical_prefix);
+ }
+
+ void visit (AST::ConstantItem &constant) override
+ {
+ auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+ constant.get_identifier ());
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (constant.get_node_id (), cpath);
+
+ resolver->get_name_scope ().insert (
+ path, constant.get_node_id (), constant.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (constant.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ ResolveType::go (constant.get_type ().get ());
+ ResolveExpr::go (constant.get_expr ().get (), prefix, canonical_prefix);
+ }
+
+ void visit (AST::LetStmt &stmt) override
+ {
+ if (stmt.has_init_expr ())
+ {
+ ResolveExpr::go (stmt.get_init_expr ().get (), prefix,
+ canonical_prefix);
+ }
+
+ PatternDeclaration::go (stmt.get_pattern ().get ());
+ if (stmt.has_type ())
+ ResolveType::go (stmt.get_type ().get ());
+ }
+
+ void visit (AST::TupleStruct &struct_decl) override
+ {
+ auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+ struct_decl.get_identifier ());
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+
+ resolver->get_type_scope ().insert (
+ path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (struct_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId scope_node_id = struct_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (struct_decl.has_generics ())
+ {
+ for (auto &generic : struct_decl.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+ }
+
+ for (AST::TupleField &field : struct_decl.get_fields ())
+ ResolveType::go (field.get_field_type ().get ());
+
+ resolver->get_type_scope ().pop ();
+ }
+
+ void visit (AST::Enum &enum_decl) override
+ {
+ auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (),
+ enum_decl.get_identifier ());
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (enum_decl.get_node_id (), cpath);
+
+ resolver->get_type_scope ().insert (
+ path, enum_decl.get_node_id (), enum_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (enum_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId scope_node_id = enum_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (enum_decl.has_generics ())
+ {
+ for (auto &generic : enum_decl.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+ }
+
+ for (auto &variant : enum_decl.get_variants ())
+ ResolveStmt::go (variant.get (), path, canonical_prefix, path);
+
+ resolver->get_type_scope ().pop ();
+ }
+
+ void visit (AST::EnumItem &item) override
+ {
+ auto decl = enum_prefix.append (
+ CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+ resolver->get_type_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ // Done, no fields.
+ }
+
+ void visit (AST::EnumItemTuple &item) override
+ {
+ auto decl = enum_prefix.append (
+ CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+ resolver->get_type_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ for (auto &field : item.get_tuple_fields ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+ }
+
+ void visit (AST::EnumItemStruct &item) override
+ {
+ auto decl = enum_prefix.append (
+ CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+ resolver->get_type_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ for (auto &field : item.get_struct_fields ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+ }
+
+ void visit (AST::EnumItemDiscriminant &item) override
+ {
+ auto decl = enum_prefix.append (
+ CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ()));
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+
+ resolver->get_type_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ // Done, no fields.
+ }
+
+ void visit (AST::StructStruct &struct_decl) override
+ {
+ auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+ struct_decl.get_identifier ());
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+
+ resolver->get_type_scope ().insert (
+ path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (struct_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId scope_node_id = struct_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (struct_decl.has_generics ())
+ {
+ for (auto &generic : struct_decl.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+ }
+
+ for (AST::StructField &field : struct_decl.get_fields ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+
+ resolver->get_type_scope ().pop ();
+ }
+
+ void visit (AST::Union &union_decl) override
+ {
+ auto decl = CanonicalPath::new_seg (union_decl.get_node_id (),
+ union_decl.get_identifier ());
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (union_decl.get_node_id (), cpath);
+
+ resolver->get_type_scope ().insert (
+ path, union_decl.get_node_id (), union_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (union_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId scope_node_id = union_decl.get_node_id ();
+ resolver->get_type_scope ().push (scope_node_id);
+
+ if (union_decl.has_generics ())
+ for (auto &generic : union_decl.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ for (AST::StructField &field : union_decl.get_variants ())
+ {
+ if (field.get_field_type ()->is_marked_for_strip ())
+ continue;
+
+ ResolveType::go (field.get_field_type ().get ());
+ }
+
+ resolver->get_type_scope ().pop ();
+ }
+
+ void visit (AST::Function &function) override
+ {
+ auto decl = CanonicalPath::new_seg (function.get_node_id (),
+ function.get_function_name ());
+ auto path = decl; // this ensures we have the correct relative resolution
+ auto cpath = canonical_prefix.append (decl);
+ mappings->insert_canonical_path (function.get_node_id (), cpath);
+
+ resolver->get_name_scope ().insert (
+ path, function.get_node_id (), function.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (function.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId scope_node_id = function.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ if (function.has_generics ())
+ for (auto &generic : function.get_generic_params ())
+ ResolveGenericParam::go (generic.get (), prefix, canonical_prefix);
+
+ if (function.has_return_type ())
+ ResolveType::go (function.get_return_type ().get ());
+
+ // 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 ());
+ }
+
+ // resolve the function body
+ ResolveExpr::go (function.get_definition ().get (), path, cpath);
+
+ resolver->get_name_scope ().pop ();
+ resolver->get_type_scope ().pop ();
+ resolver->get_label_scope ().pop ();
+ }
+
+ void visit (AST::ExternBlock &extern_block) override;
+
+private:
+ ResolveStmt (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix,
+ const CanonicalPath &enum_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix),
+ enum_prefix (enum_prefix)
+ {}
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+
+ /* item declaration statements are not given a canonical path, but enum items
+ * (variants) do inherit the enum path/identifier name. */
+ const CanonicalPath &enum_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_STMT_H
new file mode 100644
@@ -0,0 +1,61 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-struct-expr-field.h"
+#include "rust-ast-resolve-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+void
+ResolveStructExprField::go (AST::StructExprField *field,
+ const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ ResolveStructExprField resolver (prefix, canonical_prefix);
+ field->accept_vis (resolver);
+}
+
+ResolveStructExprField::ResolveStructExprField (
+ const CanonicalPath &prefix, const CanonicalPath &canonical_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+{}
+
+void
+ResolveStructExprField::visit (AST::StructExprFieldIdentifierValue &field)
+{
+ ResolveExpr::go (field.get_value ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveStructExprField::visit (AST::StructExprFieldIndexValue &field)
+{
+ ResolveExpr::go (field.get_value ().get (), prefix, canonical_prefix);
+}
+
+void
+ResolveStructExprField::visit (AST::StructExprFieldIdentifier &field)
+{
+ AST::IdentifierExpr expr (field.get_field_name (), {}, field.get_locus ());
+ expr.set_node_id (field.get_node_id ());
+
+ ResolveExpr::go (&expr, prefix, canonical_prefix);
+}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,55 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_STRUCT_EXPR_FIELD
+#define RUST_AST_RESOLVE_STRUCT_EXPR_FIELD
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+// this resolves values being assigned not that the field actually exists yet.
+
+class ResolveStructExprField : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::StructExprField *field, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ void visit (AST::StructExprFieldIdentifierValue &field) override;
+
+ void visit (AST::StructExprFieldIndexValue &field) override;
+
+ void visit (AST::StructExprFieldIdentifier &field) override;
+
+private:
+ ResolveStructExprField (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_STRUCT_EXPR_FIELD
new file mode 100644
@@ -0,0 +1,460 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_TOPLEVEL_H
+#define RUST_AST_RESOLVE_TOPLEVEL_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-implitem.h"
+#include "rust-ast-full.h"
+#include "rust-name-resolver.h"
+#include "rust-session-manager.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveTopLevel : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::Item *item, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ {
+ if (item->is_marked_for_strip ())
+ return;
+
+ ResolveTopLevel resolver (prefix, canonical_prefix);
+ item->accept_vis (resolver);
+
+ NodeId current_module = resolver.resolver->peek_current_module_scope ();
+ resolver.mappings->insert_child_item_to_parent_module_mapping (
+ item->get_node_id (), current_module);
+ }
+
+ void visit (AST::Module &module) override
+ {
+ auto mod
+ = CanonicalPath::new_seg (module.get_node_id (), module.get_name ());
+ auto path = prefix.append (mod);
+ auto cpath = canonical_prefix.append (mod);
+
+ resolver->get_name_scope ().insert (
+ path, module.get_node_id (), module.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (module.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, mod);
+ mappings->insert_module_child (current_module, module.get_node_id ());
+
+ resolver->push_new_module_scope (module.get_node_id ());
+ for (auto &item : module.get_items ())
+ ResolveTopLevel::go (item.get (), path, cpath);
+
+ resolver->pop_module_scope ();
+
+ mappings->insert_canonical_path (module.get_node_id (), cpath);
+ }
+
+ void visit (AST::TypeAlias &alias) override
+ {
+ auto talias = CanonicalPath::new_seg (alias.get_node_id (),
+ alias.get_new_type_name ());
+ auto path = prefix.append (talias);
+ auto cpath = canonical_prefix.append (talias);
+
+ resolver->get_type_scope ().insert (
+ path, alias.get_node_id (), alias.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (alias.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, talias);
+ mappings->insert_canonical_path (alias.get_node_id (), cpath);
+ }
+
+ void visit (AST::TupleStruct &struct_decl) override
+ {
+ auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+ struct_decl.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (struct_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+ }
+
+ void visit (AST::Enum &enum_decl) override
+ {
+ auto decl = CanonicalPath::new_seg (enum_decl.get_node_id (),
+ enum_decl.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, enum_decl.get_node_id (), enum_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (enum_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ for (auto &variant : enum_decl.get_variants ())
+ ResolveTopLevel::go (variant.get (), path, cpath);
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ mappings->insert_canonical_path (enum_decl.get_node_id (), cpath);
+ }
+
+ void visit (AST::EnumItem &item) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+ }
+
+ void visit (AST::EnumItemTuple &item) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+ }
+
+ void visit (AST::EnumItemStruct &item) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+ }
+
+ void visit (AST::EnumItemDiscriminant &item) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (item.get_node_id (), item.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, item.get_node_id (), item.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (item.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ mappings->insert_canonical_path (item.get_node_id (), cpath);
+ }
+
+ void visit (AST::StructStruct &struct_decl) override
+ {
+ auto decl = CanonicalPath::new_seg (struct_decl.get_node_id (),
+ struct_decl.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, struct_decl.get_node_id (), struct_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (struct_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ mappings->insert_canonical_path (struct_decl.get_node_id (), cpath);
+ }
+
+ void visit (AST::Union &union_decl) override
+ {
+ auto decl = CanonicalPath::new_seg (union_decl.get_node_id (),
+ union_decl.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, union_decl.get_node_id (), union_decl.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (union_decl.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ mappings->insert_canonical_path (union_decl.get_node_id (), cpath);
+ }
+
+ void visit (AST::StaticItem &var) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (var.get_node_id (), var.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, var.get_node_id (), var.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (var.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ mappings->insert_canonical_path (var.get_node_id (), cpath);
+ }
+
+ void visit (AST::ConstantItem &constant) override
+ {
+ auto decl = CanonicalPath::new_seg (constant.get_node_id (),
+ constant.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, constant.get_node_id (), constant.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (constant.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ mappings->insert_canonical_path (constant.get_node_id (), cpath);
+ }
+
+ void visit (AST::Function &function) override
+ {
+ auto decl = CanonicalPath::new_seg (function.get_node_id (),
+ function.get_function_name ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_name_scope ().insert (
+ path, function.get_node_id (), function.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (function.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ mappings->insert_canonical_path (function.get_node_id (), cpath);
+ }
+
+ void visit (AST::InherentImpl &impl_block) override
+ {
+ std::string raw_impl_type_path = impl_block.get_type ()->as_string ();
+ CanonicalPath impl_type
+ = CanonicalPath::new_seg (impl_block.get_type ()->get_node_id (),
+ raw_impl_type_path);
+ CanonicalPath impl_prefix = prefix.append (impl_type);
+
+ for (auto &impl_item : impl_block.get_impl_items ())
+ ResolveToplevelImplItem::go (impl_item.get (), impl_prefix);
+ }
+
+ void visit (AST::TraitImpl &impl_block) override
+ {
+ std::string raw_impl_type_path = impl_block.get_type ()->as_string ();
+ CanonicalPath impl_type_seg
+ = CanonicalPath::new_seg (impl_block.get_type ()->get_node_id (),
+ raw_impl_type_path);
+
+ std::string raw_trait_type_path = impl_block.get_trait_path ().as_string ();
+ CanonicalPath trait_type_seg
+ = CanonicalPath::new_seg (impl_block.get_trait_path ().get_node_id (),
+ raw_trait_type_path);
+
+ CanonicalPath projection
+ = CanonicalPath::trait_impl_projection_seg (impl_block.get_node_id (),
+ trait_type_seg,
+ impl_type_seg);
+ CanonicalPath impl_prefix = prefix.append (projection);
+
+ resolver->get_name_scope ().insert (
+ impl_prefix, impl_block.get_node_id (), impl_block.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (impl_block.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ for (auto &impl_item : impl_block.get_impl_items ())
+ ResolveToplevelImplItem::go (impl_item.get (), impl_prefix);
+ }
+
+ void visit (AST::Trait &trait) override
+ {
+ auto decl
+ = CanonicalPath::new_seg (trait.get_node_id (), trait.get_identifier ());
+ auto path = prefix.append (decl);
+ auto cpath = canonical_prefix.append (decl);
+
+ resolver->get_type_scope ().insert (
+ path, trait.get_node_id (), trait.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (trait.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+
+ for (auto &item : trait.get_trait_items ())
+ ResolveTopLevelTraitItems::go (item.get (), path, cpath);
+
+ NodeId current_module = resolver->peek_current_module_scope ();
+ mappings->insert_module_child_item (current_module, decl);
+ mappings->insert_canonical_path (trait.get_node_id (), cpath);
+ }
+
+ void visit (AST::ExternBlock &extern_block) override
+ {
+ for (auto &item : extern_block.get_extern_items ())
+ {
+ ResolveToplevelExternItem::go (item.get (), prefix);
+ }
+ }
+
+ void visit (AST::ExternCrate &extern_crate) override
+ {
+ if (extern_crate.is_marked_for_strip ())
+ return;
+
+ NodeId resolved_crate = UNKNOWN_NODEID;
+ if (extern_crate.references_self ())
+ {
+ CrateNum crate_num = mappings->get_current_crate ();
+ bool ok = mappings->crate_num_to_nodeid (crate_num, resolved_crate);
+ rust_assert (ok);
+ }
+ else
+ {
+ CrateNum found_crate_num = UNKNOWN_CREATENUM;
+ bool found
+ = mappings->lookup_crate_name (extern_crate.get_referenced_crate (),
+ found_crate_num);
+ if (!found)
+ {
+ rust_error_at (extern_crate.get_locus (), "unknown crate %<%s%>",
+ extern_crate.get_referenced_crate ().c_str ());
+ return;
+ }
+
+ bool ok
+ = mappings->crate_num_to_nodeid (found_crate_num, resolved_crate);
+ if (!ok)
+ {
+ rust_internal_error_at (extern_crate.get_locus (),
+ "failed to resolve crate to nodeid");
+ return;
+ }
+ }
+
+ if (resolved_crate == UNKNOWN_NODEID)
+ {
+ rust_error_at (extern_crate.get_locus (), "failed to resolve crate");
+ return;
+ }
+
+ // mark the node as resolved
+ resolver->insert_resolved_name (extern_crate.get_node_id (),
+ resolved_crate);
+ CanonicalPath decl
+ = extern_crate.has_as_clause ()
+ ? CanonicalPath::new_seg (extern_crate.get_node_id (),
+ extern_crate.get_as_clause ())
+ : CanonicalPath::new_seg (extern_crate.get_node_id (),
+ extern_crate.get_referenced_crate ());
+
+ resolver->get_type_scope ().insert (
+ decl, resolved_crate, extern_crate.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ RichLocation r (extern_crate.get_locus ());
+ r.add_range (locus);
+ rust_error_at (r, "redefined multiple times");
+ });
+ }
+
+private:
+ ResolveTopLevel (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+ {}
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_TOPLEVEL_H
new file mode 100644
@@ -0,0 +1,582 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve-type.h"
+#include "rust-ast-resolve-expr.h"
+
+namespace Rust {
+namespace Resolver {
+
+// rust-ast-resolve-type.h
+
+void
+ResolveType::visit (AST::ArrayType &type)
+{
+ type.get_elem_type ()->accept_vis (*this);
+ ResolveExpr::go (type.get_size_expr ().get (), CanonicalPath::create_empty (),
+ CanonicalPath::create_empty ());
+}
+
+void
+ResolveType::visit (AST::TraitObjectTypeOneBound &type)
+{
+ ResolveTypeBound::go (&type.get_trait_bound ());
+}
+
+void
+ResolveType::visit (AST::TraitObjectType &type)
+{
+ for (auto &bound : type.get_type_param_bounds ())
+ {
+ /* NodeId bound_resolved_id = */
+ ResolveTypeBound::go (bound.get ());
+ }
+}
+
+void
+ResolveType::visit (AST::ReferenceType &type)
+{
+ resolved_node = ResolveType::go (type.get_type_referenced ().get ());
+}
+
+void
+ResolveType::visit (AST::RawPointerType &type)
+{
+ resolved_node = ResolveType::go (type.get_type_pointed_to ().get ());
+}
+
+void
+ResolveType::visit (AST::InferredType &type)
+{
+ // FIXME
+}
+
+void
+ResolveType::visit (AST::NeverType &type)
+{
+ // FIXME
+}
+
+void
+ResolveType::visit (AST::SliceType &type)
+{
+ resolved_node = ResolveType::go (type.get_elem_type ().get ());
+}
+
+// resolve relative type-paths
+
+bool
+ResolveRelativeTypePath::go (AST::TypePath &path, NodeId &resolved_node_id)
+{
+ auto resolver = Resolver::get ();
+ auto mappings = Analysis::Mappings::get ();
+
+ NodeId module_scope_id = resolver->peek_current_module_scope ();
+ NodeId previous_resolved_node_id = module_scope_id;
+ for (size_t i = 0; i < path.get_segments ().size (); i++)
+ {
+ auto &segment = path.get_segments ().at (i);
+ const AST::PathIdentSegment &ident_seg = segment->get_ident_segment ();
+ bool is_first_segment = i == 0;
+ resolved_node_id = UNKNOWN_NODEID;
+
+ bool in_middle_of_path = i > 0;
+ if (in_middle_of_path && segment->is_lower_self_seg ())
+ {
+ // error[E0433]: failed to resolve: `self` in paths can only be used
+ // in start position
+ rust_error_at (segment->get_locus (),
+ "failed to resolve: %<%s%> in paths can only be used "
+ "in start position",
+ segment->as_string ().c_str ());
+ return false;
+ }
+
+ NodeId crate_scope_id = resolver->peek_crate_module_scope ();
+ if (segment->is_crate_path_seg ())
+ {
+ // what is the current crate scope node id?
+ module_scope_id = crate_scope_id;
+ previous_resolved_node_id = module_scope_id;
+ resolver->insert_resolved_name (segment->get_node_id (),
+ module_scope_id);
+
+ continue;
+ }
+ else if (segment->is_super_path_seg ())
+ {
+ if (module_scope_id == crate_scope_id)
+ {
+ rust_error_at (segment->get_locus (),
+ "cannot use super at the crate scope");
+ return false;
+ }
+
+ module_scope_id = resolver->peek_parent_module_scope ();
+ previous_resolved_node_id = module_scope_id;
+ resolver->insert_resolved_name (segment->get_node_id (),
+ module_scope_id);
+ continue;
+ }
+
+ switch (segment->get_type ())
+ {
+ case AST::TypePathSegment::SegmentType::GENERIC: {
+ AST::TypePathSegmentGeneric *s
+ = static_cast<AST::TypePathSegmentGeneric *> (segment.get ());
+ if (s->has_generic_args ())
+ ResolveGenericArgs::go (s->get_generic_args ());
+ }
+ break;
+
+ case AST::TypePathSegment::SegmentType::REG:
+ // nothing to do
+ break;
+
+ case AST::TypePathSegment::SegmentType::FUNCTION:
+ gcc_unreachable ();
+ break;
+ }
+
+ if (is_first_segment)
+ {
+ // name scope first
+ NodeId resolved_node = UNKNOWN_NODEID;
+ const CanonicalPath path
+ = CanonicalPath::new_seg (segment->get_node_id (),
+ ident_seg.as_string ());
+ if (resolver->get_type_scope ().lookup (path, &resolved_node))
+ {
+ resolver->insert_resolved_type (segment->get_node_id (),
+ resolved_node);
+ resolved_node_id = resolved_node;
+ }
+ else if (resolver->get_name_scope ().lookup (path, &resolved_node))
+ {
+ resolver->insert_resolved_name (segment->get_node_id (),
+ resolved_node);
+ resolved_node_id = resolved_node;
+ }
+ else if (segment->is_lower_self_seg ())
+ {
+ // what is the current crate scope node id?
+ module_scope_id = crate_scope_id;
+ previous_resolved_node_id = module_scope_id;
+ resolver->insert_resolved_name (segment->get_node_id (),
+ module_scope_id);
+
+ continue;
+ }
+ }
+
+ if (resolved_node_id == UNKNOWN_NODEID
+ && previous_resolved_node_id == module_scope_id)
+ {
+ Optional<CanonicalPath &> resolved_child
+ = mappings->lookup_module_child (module_scope_id,
+ ident_seg.as_string ());
+ if (resolved_child.is_some ())
+ {
+ NodeId resolved_node = resolved_child->get_node_id ();
+ if (resolver->get_name_scope ().decl_was_declared_here (
+ resolved_node))
+ {
+ resolved_node_id = resolved_node;
+ resolver->insert_resolved_name (segment->get_node_id (),
+ resolved_node);
+ }
+ else if (resolver->get_type_scope ().decl_was_declared_here (
+ resolved_node))
+ {
+ resolved_node_id = resolved_node;
+ resolver->insert_resolved_type (segment->get_node_id (),
+ resolved_node);
+ }
+ else
+ {
+ rust_error_at (segment->get_locus (),
+ "Cannot find path %<%s%> in this scope",
+ segment->as_string ().c_str ());
+ return false;
+ }
+ }
+ }
+
+ bool did_resolve_segment = resolved_node_id != UNKNOWN_NODEID;
+ if (did_resolve_segment)
+ {
+ if (mappings->node_is_module (resolved_node_id)
+ || mappings->node_is_crate (resolved_node_id))
+ {
+ module_scope_id = resolved_node_id;
+ }
+ previous_resolved_node_id = resolved_node_id;
+ }
+ else if (is_first_segment)
+ {
+ rust_error_at (segment->get_locus (),
+ "failed to resolve TypePath: %s in this scope",
+ segment->as_string ().c_str ());
+ return false;
+ }
+ }
+
+ if (resolved_node_id != UNKNOWN_NODEID)
+ {
+ // name scope first
+ if (resolver->get_name_scope ().decl_was_declared_here (resolved_node_id))
+ {
+ resolver->insert_resolved_name (path.get_node_id (),
+ resolved_node_id);
+ }
+ // check the type scope
+ else if (resolver->get_type_scope ().decl_was_declared_here (
+ resolved_node_id))
+ {
+ resolver->insert_resolved_type (path.get_node_id (),
+ resolved_node_id);
+ }
+ else
+ {
+ gcc_unreachable ();
+ }
+ }
+
+ return true;
+}
+
+// qualified type paths
+
+ResolveRelativeQualTypePath::ResolveRelativeQualTypePath ()
+ : failure_flag (false)
+{}
+
+bool
+ResolveRelativeQualTypePath::go (AST::QualifiedPathInType &path)
+{
+ ResolveRelativeQualTypePath o;
+
+ // resolve the type and trait path
+ auto &qualified_path = path.get_qualified_path_type ();
+ if (!o.resolve_qual_seg (qualified_path))
+ return false;
+
+ // qualified types are similar to other paths in that we cannot guarantee
+ // that we can resolve the path at name resolution. We must look up
+ // associated types and type information to figure this out properly
+
+ std::unique_ptr<AST::TypePathSegment> &associated
+ = path.get_associated_segment ();
+
+ associated->accept_vis (o);
+ if (o.failure_flag)
+ return false;
+
+ for (auto &seg : path.get_segments ())
+ {
+ seg->accept_vis (o);
+ if (o.failure_flag)
+ return false;
+ }
+
+ return true;
+}
+
+bool
+ResolveRelativeQualTypePath::resolve_qual_seg (AST::QualifiedPathType &seg)
+{
+ if (seg.is_error ())
+ {
+ rust_error_at (seg.get_locus (), "segment has error: %s",
+ seg.as_string ().c_str ());
+ return false;
+ }
+
+ auto type = seg.get_type ().get ();
+ NodeId type_resolved_node = ResolveType::go (type);
+ if (type_resolved_node == UNKNOWN_NODEID)
+ return false;
+
+ if (!seg.has_as_clause ())
+ return true;
+
+ NodeId trait_resolved_node = ResolveType::go (&seg.get_as_type_path ());
+ if (trait_resolved_node == UNKNOWN_NODEID)
+ return false;
+
+ return true;
+}
+
+void
+ResolveRelativeQualTypePath::visit (AST::TypePathSegmentGeneric &seg)
+{
+ if (seg.is_error ())
+ {
+ failure_flag = true;
+ rust_error_at (seg.get_locus (), "segment has error: %s",
+ seg.as_string ().c_str ());
+ return;
+ }
+
+ ResolveGenericArgs::go (seg.get_generic_args ());
+}
+
+void
+ResolveRelativeQualTypePath::visit (AST::TypePathSegment &seg)
+{
+ if (seg.is_error ())
+ {
+ failure_flag = true;
+ rust_error_at (seg.get_locus (), "segment has error: %s",
+ seg.as_string ().c_str ());
+ return;
+ }
+}
+
+// resolve to canonical path
+
+bool
+ResolveTypeToCanonicalPath::go (AST::Type *type, CanonicalPath &result)
+{
+ ResolveTypeToCanonicalPath resolver;
+ type->accept_vis (resolver);
+ result = resolver.result;
+ return !resolver.result.is_empty ();
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::TypePath &path)
+{
+ NodeId resolved_node = UNKNOWN_NODEID;
+ if (!resolver->lookup_resolved_name (path.get_node_id (), &resolved_node))
+ {
+ resolver->lookup_resolved_type (path.get_node_id (), &resolved_node);
+ }
+
+ if (resolved_node == UNKNOWN_NODEID)
+ return;
+
+ const CanonicalPath *type_path = nullptr;
+ if (mappings->lookup_canonical_path (resolved_node, &type_path))
+ {
+ auto &final_seg = path.get_segments ().back ();
+ switch (final_seg->get_type ())
+ {
+ case AST::TypePathSegment::SegmentType::GENERIC: {
+ AST::TypePathSegmentGeneric *s
+ = static_cast<AST::TypePathSegmentGeneric *> (final_seg.get ());
+
+ std::vector<CanonicalPath> args;
+ if (s->has_generic_args ())
+ {
+ ResolveGenericArgs::go (s->get_generic_args ());
+ for (auto &generic : s->get_generic_args ().get_generic_args ())
+ {
+ // FIXME: What do we want to do here in case there is a
+ // constant or an ambiguous const generic?
+ // TODO: At that point, will all generics have been
+ // disambiguated? Can we thus canonical resolve types and
+ // const and `gcc_unreachable` on ambiguous types?
+ // This is probably fine as we just want to canonicalize
+ // types, right?
+ if (generic.get_kind () == AST::GenericArg::Kind::Type)
+ {
+ CanonicalPath arg = CanonicalPath::create_empty ();
+ bool ok = ResolveTypeToCanonicalPath::go (
+ generic.get_type ().get (), arg);
+ if (ok)
+ args.push_back (std::move (arg));
+ }
+ }
+ }
+
+ result = *type_path;
+ if (!args.empty ())
+ {
+ // append this onto the path
+ std::string buf;
+ for (size_t i = 0; i < args.size (); i++)
+ {
+ bool has_next = (i + 1) < args.size ();
+ const auto &arg = args.at (i);
+
+ buf += arg.get ();
+ if (has_next)
+ buf += ", ";
+ }
+
+ std::string arg_seg = "<" + buf + ">";
+ CanonicalPath argument_seg
+ = CanonicalPath::new_seg (s->get_node_id (), arg_seg);
+ result = result.append (argument_seg);
+ }
+ }
+ break;
+
+ default:
+ result = *type_path;
+ break;
+ }
+ }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::ReferenceType &type)
+{
+ CanonicalPath path = CanonicalPath::create_empty ();
+ bool ok
+ = ResolveTypeToCanonicalPath::go (type.get_type_referenced ().get (), path);
+ if (ok)
+ {
+ std::string ref_type_str = type.is_mut () ? "mut" : "";
+ std::string ref_path = "&" + ref_type_str + " " + path.get ();
+ result = CanonicalPath::new_seg (type.get_node_id (), ref_path);
+ }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::RawPointerType &type)
+{
+ CanonicalPath path = CanonicalPath::create_empty ();
+ bool ok
+ = ResolveTypeToCanonicalPath::go (type.get_type_pointed_to ().get (), path);
+ if (ok)
+ {
+ std::string ptr_type_str
+ = type.get_pointer_type () == AST::RawPointerType::CONST ? "const"
+ : "mut";
+ std::string ptr_path = "*" + ptr_type_str + " " + path.get ();
+ result = CanonicalPath::new_seg (type.get_node_id (), ptr_path);
+ }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::SliceType &type)
+{
+ CanonicalPath path = CanonicalPath::create_empty ();
+ bool ok = ResolveTypeToCanonicalPath::go (type.get_elem_type ().get (), path);
+ if (ok)
+ {
+ std::string slice_path = "[" + path.get () + "]";
+ result = CanonicalPath::new_seg (type.get_node_id (), slice_path);
+ }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::TraitObjectTypeOneBound &type)
+{
+ CanonicalPath path = CanonicalPath::create_empty ();
+ bool ok
+ = ResolveTypeToCanonicalPath::go (&type.get_trait_bound ().get_type_path (),
+ path);
+ if (ok)
+ {
+ std::string slice_path = "<dyn " + path.get () + ">";
+ result = CanonicalPath::new_seg (type.get_node_id (), slice_path);
+ }
+}
+
+void
+ResolveTypeToCanonicalPath::visit (AST::TraitObjectType &type)
+{
+ // FIXME is this actually allowed? dyn A+B
+ gcc_unreachable ();
+}
+
+ResolveTypeToCanonicalPath::ResolveTypeToCanonicalPath ()
+ : ResolverBase (), result (CanonicalPath::create_empty ())
+{}
+
+bool
+ResolveGenericArgs::is_const_value_name (const CanonicalPath &path)
+{
+ NodeId resolved;
+ auto found = resolver->get_name_scope ().lookup (path, &resolved);
+
+ return found;
+}
+
+bool
+ResolveGenericArgs::is_type_name (const CanonicalPath &path)
+{
+ NodeId resolved;
+ auto found = resolver->get_type_scope ().lookup (path, &resolved);
+
+ return found;
+}
+
+void
+ResolveGenericArgs::disambiguate (AST::GenericArg &arg)
+{
+ auto path = canonical_prefix.append (
+ CanonicalPath::new_seg (UNKNOWN_NODEID, arg.get_path ()));
+
+ auto is_type = is_type_name (path);
+ auto is_value = is_const_value_name (path);
+
+ // In case we cannot find anything, we resolve the ambiguity to a type.
+ // This causes the typechecker to error out properly and when necessary.
+ // But types also take priority over const values in the case of
+ // ambiguities, hence the weird control flow
+ if (is_type || (!is_type && !is_value))
+ arg = arg.disambiguate_to_type ();
+ else if (is_value)
+ arg = arg.disambiguate_to_const ();
+}
+
+void
+ResolveGenericArgs::resolve_disambiguated_generic (AST::GenericArg &arg)
+{
+ switch (arg.get_kind ())
+ {
+ case AST::GenericArg::Kind::Const:
+ ResolveExpr::go (arg.get_expression ().get (), prefix, canonical_prefix);
+ break;
+ case AST::GenericArg::Kind::Type:
+ ResolveType::go (arg.get_type ().get ());
+ break;
+ default:
+ gcc_unreachable ();
+ }
+}
+void
+ResolveGenericArgs::go (AST::GenericArgs &generic_args)
+{
+ auto empty = CanonicalPath::create_empty ();
+
+ go (generic_args, empty, empty);
+}
+
+void
+ResolveGenericArgs::go (AST::GenericArgs &generic_args,
+ const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+{
+ auto resolver = ResolveGenericArgs (prefix, canonical_prefix);
+
+ for (auto &arg : generic_args.get_generic_args ())
+ {
+ if (arg.get_kind () == AST::GenericArg::Kind::Either)
+ resolver.disambiguate (arg);
+
+ resolver.resolve_disambiguated_generic (arg);
+ }
+}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,290 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_TYPE_H
+#define RUST_AST_RESOLVE_TYPE_H
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-resolve-expr.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class ResolveRelativeTypePath
+{
+public:
+ static bool go (AST::TypePath &path, NodeId &resolved_node_id);
+};
+
+class ResolveRelativeQualTypePath : public ResolverBase
+{
+ using ResolverBase::visit;
+
+public:
+ static bool go (AST::QualifiedPathInType &path);
+
+ void visit (AST::TypePathSegmentGeneric &seg) override;
+
+ void visit (AST::TypePathSegment &seg) override;
+
+protected:
+ bool resolve_qual_seg (AST::QualifiedPathType &seg);
+
+private:
+ ResolveRelativeQualTypePath ();
+
+ bool failure_flag;
+};
+
+class ResolveType : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static NodeId go (AST::Type *type)
+ {
+ ResolveType resolver;
+ type->accept_vis (resolver);
+ return resolver.resolved_node;
+ }
+
+ void visit (AST::BareFunctionType &fntype) override
+ {
+ for (auto ¶m : fntype.get_function_params ())
+ ResolveType::go (param.get_type ().get ());
+
+ if (fntype.has_return_type ())
+ ResolveType::go (fntype.get_return_type ().get ());
+ }
+
+ void visit (AST::TupleType &tuple) override
+ {
+ if (tuple.is_unit_type ())
+ {
+ resolved_node = resolver->get_unit_type_node_id ();
+ return;
+ }
+
+ for (auto &elem : tuple.get_elems ())
+ ResolveType::go (elem.get ());
+ }
+
+ void visit (AST::TypePath &path) override
+ {
+ ResolveRelativeTypePath::go (path, resolved_node);
+ }
+
+ void visit (AST::QualifiedPathInType &path) override
+ {
+ ResolveRelativeQualTypePath::go (path);
+ }
+
+ void visit (AST::ArrayType &type) override;
+
+ void visit (AST::ReferenceType &type) override;
+
+ void visit (AST::InferredType &type) override;
+
+ void visit (AST::NeverType &type) override;
+
+ void visit (AST::RawPointerType &type) override;
+
+ void visit (AST::TraitObjectTypeOneBound &type) override;
+
+ void visit (AST::TraitObjectType &type) override;
+
+ void visit (AST::SliceType &type) override;
+
+private:
+ ResolveType () : ResolverBase () {}
+};
+
+class ResolveTypeBound : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static NodeId go (AST::TypeParamBound *type)
+ {
+ ResolveTypeBound resolver;
+ type->accept_vis (resolver);
+ return resolver.resolved_node;
+ };
+
+ void visit (AST::TraitBound &bound) override
+ {
+ resolved_node = ResolveType::go (&bound.get_type_path ());
+ }
+
+private:
+ ResolveTypeBound () : ResolverBase () {}
+};
+
+class ResolveGenericParam : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static NodeId go (AST::GenericParam *param, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ {
+ ResolveGenericParam resolver (prefix, canonical_prefix);
+ param->accept_vis (resolver);
+ return resolver.resolved_node;
+ }
+
+ void visit (AST::ConstGenericParam ¶m) override
+ {
+ ResolveType::go (param.get_type ().get ());
+
+ if (param.has_default_value ())
+ ResolveExpr::go (param.get_default_value ().get_expression ().get (),
+ prefix, canonical_prefix);
+
+ ok = true;
+ }
+
+ void visit (AST::TypeParam ¶m) override
+ {
+ // if it has a type lets resolve it
+ if (param.has_type ())
+ ResolveType::go (param.get_type ().get ());
+
+ if (param.has_type_param_bounds ())
+ {
+ for (auto &bound : param.get_type_param_bounds ())
+ {
+ ResolveTypeBound::go (bound.get ());
+ }
+ }
+
+ auto seg = CanonicalPath::new_seg (param.get_node_id (),
+ param.get_type_representation ());
+ resolver->get_type_scope ().insert (
+ seg, param.get_node_id (), param.get_locus (), false,
+ [&] (const CanonicalPath &, NodeId, Location locus) -> void {
+ rust_error_at (param.get_locus (),
+ "generic param redefined multiple times");
+ rust_error_at (locus, "was defined here");
+ });
+
+ mappings->insert_canonical_path (param.get_node_id (), seg);
+ }
+
+private:
+ ResolveGenericParam (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), ok (false), prefix (prefix),
+ canonical_prefix (canonical_prefix)
+ {}
+
+ bool ok;
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+class ResolveWhereClause : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void Resolve (AST::WhereClause &where_clause)
+ {
+ ResolveWhereClause r;
+ for (auto &clause : where_clause.get_items ())
+ clause->accept_vis (r);
+ }
+
+ void visit (AST::TypeBoundWhereClauseItem &item) override
+ {
+ ResolveType::go (item.get_type ().get ());
+ if (item.has_type_param_bounds ())
+ {
+ for (auto &bound : item.get_type_param_bounds ())
+ {
+ ResolveTypeBound::go (bound.get ());
+ }
+ }
+ }
+
+private:
+ ResolveWhereClause () : ResolverBase () {}
+};
+
+class ResolveTypeToCanonicalPath : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static bool go (AST::Type *type, CanonicalPath &result);
+
+ void visit (AST::TypePath &path) override;
+
+ void visit (AST::ReferenceType &type) override;
+
+ void visit (AST::RawPointerType &type) override;
+
+ void visit (AST::SliceType &type) override;
+
+ void visit (AST::TraitObjectTypeOneBound &type) override;
+
+ void visit (AST::TraitObjectType &type) override;
+
+private:
+ ResolveTypeToCanonicalPath ();
+
+ CanonicalPath result;
+};
+
+class ResolveGenericArgs : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static void go (AST::GenericArgs &generic_args);
+ static void go (AST::GenericArgs &generic_args, const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix);
+
+private:
+ ResolveGenericArgs (const CanonicalPath &prefix,
+ const CanonicalPath &canonical_prefix)
+ : ResolverBase (), prefix (prefix), canonical_prefix (canonical_prefix)
+ {}
+
+ bool is_type_name (const CanonicalPath &path);
+ bool is_const_value_name (const CanonicalPath &path);
+
+ /**
+ * Resolve a disambiguated generic arg
+ */
+ void disambiguate (AST::GenericArg &arg);
+
+ /**
+ * Resolve a disambiguated generic arg
+ */
+ void resolve_disambiguated_generic (AST::GenericArg &arg);
+
+ const CanonicalPath &prefix;
+ const CanonicalPath &canonical_prefix;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_TYPE_H
new file mode 100644
@@ -0,0 +1,115 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-ast-resolve.h"
+#include "rust-ast-full.h"
+#include "rust-tyty.h"
+#include "rust-ast-resolve-toplevel.h"
+#include "rust-ast-resolve-item.h"
+#include "rust-ast-resolve-expr.h"
+#include "rust-ast-resolve-struct-expr-field.h"
+
+extern bool
+saw_errors (void);
+
+namespace Rust {
+namespace Resolver {
+
+// NameResolution
+
+NameResolution *
+NameResolution::get ()
+{
+ static NameResolution *instance;
+ if (instance == nullptr)
+ instance = new NameResolution ();
+
+ return instance;
+}
+
+NameResolution::NameResolution ()
+ : resolver (Resolver::get ()), mappings (Analysis::Mappings::get ())
+{
+ // these are global
+ resolver->get_type_scope ().push (mappings->get_next_node_id ());
+ resolver->insert_builtin_types (resolver->get_type_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+}
+
+void
+NameResolution::Resolve (AST::Crate &crate)
+{
+ auto resolver = get ();
+ resolver->go (crate);
+}
+
+void
+NameResolution::go (AST::Crate &crate)
+{
+ // lookup current crate name
+ CrateNum cnum = mappings->get_current_crate ();
+ std::string crate_name;
+ bool ok = mappings->get_crate_name (cnum, crate_name);
+ rust_assert (ok);
+
+ // setup the ribs
+ NodeId scope_node_id = crate.get_node_id ();
+ resolver->get_name_scope ().push (scope_node_id);
+ resolver->get_type_scope ().push (scope_node_id);
+ resolver->get_label_scope ().push (scope_node_id);
+ resolver->push_new_name_rib (resolver->get_name_scope ().peek ());
+ resolver->push_new_type_rib (resolver->get_type_scope ().peek ());
+ resolver->push_new_label_rib (resolver->get_type_scope ().peek ());
+
+ // get the root segment
+ CanonicalPath crate_prefix
+ = CanonicalPath::new_seg (scope_node_id, crate_name);
+ crate_prefix.set_crate_num (cnum);
+
+ // setup a dummy crate node
+ resolver->get_name_scope ().insert (
+ CanonicalPath::new_seg (crate.get_node_id (), "__$$crate__"),
+ crate.get_node_id (), Location ());
+
+ // setup the root scope
+ resolver->push_new_module_scope (scope_node_id);
+
+ // first gather the top-level namespace names then we drill down so this
+ // allows for resolving forward declarations since an impl block might have
+ // a Self type Foo which is defined after the impl block for example.
+ for (auto it = crate.items.begin (); it != crate.items.end (); it++)
+ ResolveTopLevel::go (it->get (), CanonicalPath::create_empty (),
+ crate_prefix);
+
+ // FIXME remove this
+ if (saw_errors ())
+ {
+ resolver->pop_module_scope ();
+ return;
+ }
+
+ // next we can drill down into the items and their scopes
+ for (auto it = crate.items.begin (); it != crate.items.end (); it++)
+ ResolveItem::go (it->get (), CanonicalPath::create_empty (), crate_prefix);
+
+ // done
+ resolver->pop_module_scope ();
+}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,50 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_RESOLVE_H
+#define RUST_AST_RESOLVE_H
+
+#include "rust-name-resolver.h"
+#include "rust-ast-full.h"
+#include "rust-hir-map.h"
+
+namespace Rust {
+namespace Resolver {
+
+class NameResolution
+{
+public:
+ static void Resolve (AST::Crate &crate);
+
+ static NameResolution *get ();
+
+ ~NameResolution () {}
+
+private:
+ void go (AST::Crate &crate);
+
+ NameResolution ();
+
+ Resolver *resolver;
+ Analysis::Mappings *mappings;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_RESOLVE_H
new file mode 100644
@@ -0,0 +1,84 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AST_VERIFY_ASSIGNEE
+#define RUST_AST_VERIFY_ASSIGNEE
+
+#include "rust-ast-resolve-base.h"
+#include "rust-ast-full.h"
+
+namespace Rust {
+namespace Resolver {
+
+class VerifyAsignee : public ResolverBase
+{
+ using Rust::Resolver::ResolverBase::visit;
+
+public:
+ static bool go (AST::Expr *assignee, NodeId parent)
+ {
+ VerifyAsignee checker (parent);
+ assignee->accept_vis (checker);
+ if (!checker.ok)
+ rust_error_at (assignee->get_locus (),
+ "invalid left-hand side of assignment");
+ return checker.ok;
+ }
+
+ void visit (AST::ArrayIndexExpr &expr) override
+ {
+ expr.get_array_expr ()->accept_vis (*this);
+ }
+
+ void visit (AST::FieldAccessExpr &expr) override
+ {
+ expr.get_receiver_expr ()->accept_vis (*this);
+ }
+
+ void visit (AST::TupleIndexExpr &expr) override
+ {
+ expr.get_tuple_expr ()->accept_vis (*this);
+ }
+
+ void visit (AST::IdentifierExpr &expr) override
+ {
+ if (!resolver->get_name_scope ().lookup (
+ CanonicalPath::new_seg (expr.get_node_id (), expr.as_string ()),
+ &resolved_node))
+ return;
+
+ ok = true;
+ }
+
+ void visit (AST::DereferenceExpr &expr) override
+ {
+ expr.get_dereferenced_expr ()->accept_vis (*this);
+ }
+
+ void visit (AST::PathInExpression &expr) override { ok = true; }
+
+private:
+ VerifyAsignee (NodeId parent) : ResolverBase (), ok (false) {}
+
+ bool ok;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AST_VERIFY_ASSIGNEE
new file mode 100644
@@ -0,0 +1,503 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-name-resolver.h"
+#include "rust-ast-full.h"
+
+#define MKBUILTIN_TYPE(_X, _R, _TY) \
+ do \
+ { \
+ AST::PathIdentSegment seg (_X, Linemap::predeclared_location ()); \
+ auto typePath = ::std::unique_ptr<AST::TypePathSegment> ( \
+ new AST::TypePathSegment (::std::move (seg), false, \
+ Linemap::predeclared_location ())); \
+ ::std::vector< ::std::unique_ptr<AST::TypePathSegment> > segs; \
+ segs.push_back (::std::move (typePath)); \
+ auto builtin_type \
+ = new AST::TypePath (::std::move (segs), \
+ Linemap::predeclared_location (), false); \
+ _R.push_back (builtin_type); \
+ tyctx->insert_builtin (_TY->get_ref (), builtin_type->get_node_id (), \
+ _TY); \
+ mappings->insert_node_to_hir (builtin_type->get_node_id (), \
+ _TY->get_ref ()); \
+ mappings->insert_canonical_path ( \
+ builtin_type->get_node_id (), \
+ CanonicalPath::new_seg (builtin_type->get_node_id (), _X)); \
+ } \
+ while (0)
+
+namespace Rust {
+namespace Resolver {
+
+Rib::Rib (CrateNum crateNum, NodeId node_id)
+ : crate_num (crateNum), node_id (node_id),
+ mappings (Analysis::Mappings::get ())
+{}
+
+void
+Rib::insert_name (
+ const CanonicalPath &path, NodeId id, Location locus, bool shadow,
+ std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb)
+{
+ auto it = path_mappings.find (path);
+ bool path_already_exists = it != path_mappings.end ();
+ if (path_already_exists && !shadow)
+ {
+ const auto &decl = decls_within_rib.find (it->second);
+ if (decl != decls_within_rib.end ())
+ dup_cb (path, it->second, decl->second);
+ else
+ dup_cb (path, it->second, locus);
+
+ return;
+ }
+
+ path_mappings[path] = id;
+ reverse_path_mappings.insert (std::pair<NodeId, CanonicalPath> (id, path));
+ decls_within_rib.insert (std::pair<NodeId, Location> (id, locus));
+ references[id] = {};
+}
+
+bool
+Rib::lookup_name (const CanonicalPath &ident, NodeId *id)
+{
+ auto it = path_mappings.find (ident);
+ if (it == path_mappings.end ())
+ return false;
+
+ *id = it->second;
+ return true;
+}
+
+void
+Rib::clear_name (const CanonicalPath &ident, NodeId id)
+{
+ auto ii = path_mappings.find (ident);
+ if (ii != path_mappings.end ())
+ path_mappings.erase (ii);
+
+ auto ij = reverse_path_mappings.find (id);
+ if (ij != reverse_path_mappings.end ())
+ reverse_path_mappings.erase (ij);
+
+ auto ik = decls_within_rib.find (id);
+ if (ik != decls_within_rib.end ())
+ decls_within_rib.erase (ik);
+}
+
+void
+Rib::append_reference_for_def (NodeId def, NodeId ref)
+{
+ references[def].insert (ref);
+}
+
+bool
+Rib::have_references_for_node (NodeId def) const
+{
+ auto it = references.find (def);
+ if (it == references.end ())
+ return false;
+
+ return !it->second.empty ();
+}
+
+bool
+Rib::decl_was_declared_here (NodeId def) const
+{
+ for (auto &it : decls_within_rib)
+ {
+ if (it.first == def)
+ return true;
+ }
+ return false;
+}
+
+void
+Rib::debug () const
+{
+ fprintf (stderr, "%s\n", debug_str ().c_str ());
+}
+
+std::string
+Rib::debug_str () const
+{
+ std::string buffer;
+ for (const auto &it : path_mappings)
+ {
+ buffer += it.first.get () + "=" + std::to_string (it.second);
+ buffer += ",";
+ }
+ return "{" + buffer + "}";
+}
+
+Scope::Scope (CrateNum crate_num) : crate_num (crate_num) {}
+
+void
+Scope::insert (
+ const CanonicalPath &ident, NodeId id, Location locus, bool shadow,
+ std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb)
+{
+ peek ()->insert_name (ident, id, locus, shadow, dup_cb);
+}
+
+void
+Scope::insert (const CanonicalPath &ident, NodeId id, Location locus)
+{
+ peek ()->insert_name (ident, id, locus, true,
+ [] (const CanonicalPath &, NodeId, Location) -> void {
+ });
+}
+
+bool
+Scope::lookup (const CanonicalPath &ident, NodeId *id)
+{
+ NodeId lookup = UNKNOWN_NODEID;
+ iterate ([&] (Rib *r) mutable -> bool {
+ if (r->lookup_name (ident, &lookup))
+ return false;
+ return true;
+ });
+
+ *id = lookup;
+ return lookup != UNKNOWN_NODEID;
+}
+
+void
+Scope::iterate (std::function<bool (Rib *)> cb)
+{
+ for (auto it = stack.rbegin (); it != stack.rend (); ++it)
+ {
+ if (!cb (*it))
+ return;
+ }
+}
+
+void
+Scope::iterate (std::function<bool (const Rib *)> cb) const
+{
+ for (auto it = stack.rbegin (); it != stack.rend (); ++it)
+ {
+ if (!cb (*it))
+ return;
+ }
+}
+
+Rib *
+Scope::peek ()
+{
+ return stack.back ();
+}
+
+void
+Scope::push (NodeId id)
+{
+ stack.push_back (new Rib (get_crate_num (), id));
+}
+
+Rib *
+Scope::pop ()
+{
+ Rib *r = peek ();
+ stack.pop_back ();
+ return r;
+}
+
+void
+Scope::append_reference_for_def (NodeId refId, NodeId defId)
+{
+ bool ok = false;
+ iterate ([&] (Rib *r) mutable -> bool {
+ if (r->decl_was_declared_here (defId))
+ {
+ ok = true;
+ r->append_reference_for_def (defId, refId);
+ }
+ return true;
+ });
+ rust_assert (ok);
+}
+
+bool
+Scope::decl_was_declared_here (NodeId def) const
+{
+ bool found = false;
+ iterate ([&] (const Rib *r) -> bool {
+ if (r->decl_was_declared_here (def))
+ {
+ found = true;
+ return false;
+ }
+ return true;
+ });
+ return found;
+}
+
+Resolver::Resolver ()
+ : mappings (Analysis::Mappings::get ()), tyctx (TypeCheckContext::get ()),
+ name_scope (Scope (mappings->get_current_crate ())),
+ type_scope (Scope (mappings->get_current_crate ())),
+ label_scope (Scope (mappings->get_current_crate ())),
+ macro_scope (Scope (mappings->get_current_crate ())),
+ global_type_node_id (UNKNOWN_NODEID), unit_ty_node_id (UNKNOWN_NODEID)
+{
+ generate_builtins ();
+}
+
+Resolver *
+Resolver::get ()
+{
+ static Resolver *instance;
+ if (instance == nullptr)
+ instance = new Resolver ();
+
+ return instance;
+}
+
+void
+Resolver::push_new_name_rib (Rib *r)
+{
+ rust_assert (name_ribs.find (r->get_node_id ()) == name_ribs.end ());
+ name_ribs[r->get_node_id ()] = r;
+}
+
+void
+Resolver::push_new_type_rib (Rib *r)
+{
+ if (type_ribs.size () == 0)
+ global_type_node_id = r->get_node_id ();
+
+ rust_assert (type_ribs.find (r->get_node_id ()) == type_ribs.end ());
+ type_ribs[r->get_node_id ()] = r;
+}
+
+void
+Resolver::push_new_label_rib (Rib *r)
+{
+ rust_assert (label_ribs.find (r->get_node_id ()) == label_ribs.end ());
+ label_ribs[r->get_node_id ()] = r;
+}
+
+void
+Resolver::push_new_macro_rib (Rib *r)
+{
+ rust_assert (label_ribs.find (r->get_node_id ()) == label_ribs.end ());
+ macro_ribs[r->get_node_id ()] = r;
+}
+
+bool
+Resolver::find_name_rib (NodeId id, Rib **rib)
+{
+ auto it = name_ribs.find (id);
+ if (it == name_ribs.end ())
+ return false;
+
+ *rib = it->second;
+ return true;
+}
+
+bool
+Resolver::find_type_rib (NodeId id, Rib **rib)
+{
+ auto it = type_ribs.find (id);
+ if (it == type_ribs.end ())
+ return false;
+
+ *rib = it->second;
+ return true;
+}
+
+bool
+Resolver::find_macro_rib (NodeId id, Rib **rib)
+{
+ auto it = macro_ribs.find (id);
+ if (it == macro_ribs.end ())
+ return false;
+
+ *rib = it->second;
+ return true;
+}
+
+void
+Resolver::insert_builtin_types (Rib *r)
+{
+ auto builtins = get_builtin_types ();
+ for (auto &builtin : builtins)
+ {
+ CanonicalPath builtin_path
+ = CanonicalPath::new_seg (builtin->get_node_id (),
+ builtin->as_string ());
+ r->insert_name (builtin_path, builtin->get_node_id (),
+ Linemap::predeclared_location (), false,
+ [] (const CanonicalPath &, NodeId, Location) -> void {});
+ }
+}
+
+std::vector<AST::Type *> &
+Resolver::get_builtin_types ()
+{
+ return builtins;
+}
+
+void
+Resolver::generate_builtins ()
+{
+ auto u8
+ = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U8);
+ auto u16
+ = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U16);
+ auto u32
+ = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U32);
+ auto u64
+ = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U64);
+ auto u128
+ = new TyTy::UintType (mappings->get_next_hir_id (), TyTy::UintType::U128);
+ auto i8 = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I8);
+ auto i16
+ = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I16);
+ auto i32
+ = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I32);
+ auto i64
+ = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I64);
+ auto i128
+ = new TyTy::IntType (mappings->get_next_hir_id (), TyTy::IntType::I128);
+ auto rbool = new TyTy::BoolType (mappings->get_next_hir_id ());
+ auto f32
+ = new TyTy::FloatType (mappings->get_next_hir_id (), TyTy::FloatType::F32);
+ auto f64
+ = new TyTy::FloatType (mappings->get_next_hir_id (), TyTy::FloatType::F64);
+ auto usize = new TyTy::USizeType (mappings->get_next_hir_id ());
+ auto isize = new TyTy::ISizeType (mappings->get_next_hir_id ());
+ auto char_tyty = new TyTy::CharType (mappings->get_next_hir_id ());
+ auto str = new TyTy::StrType (mappings->get_next_hir_id ());
+ auto never = new TyTy::NeverType (mappings->get_next_hir_id ());
+
+ MKBUILTIN_TYPE ("u8", builtins, u8);
+ MKBUILTIN_TYPE ("u16", builtins, u16);
+ MKBUILTIN_TYPE ("u32", builtins, u32);
+ MKBUILTIN_TYPE ("u64", builtins, u64);
+ MKBUILTIN_TYPE ("u128", builtins, u128);
+ MKBUILTIN_TYPE ("i8", builtins, i8);
+ MKBUILTIN_TYPE ("i16", builtins, i16);
+ MKBUILTIN_TYPE ("i32", builtins, i32);
+ MKBUILTIN_TYPE ("i64", builtins, i64);
+ MKBUILTIN_TYPE ("i128", builtins, i128);
+ MKBUILTIN_TYPE ("bool", builtins, rbool);
+ MKBUILTIN_TYPE ("f32", builtins, f32);
+ MKBUILTIN_TYPE ("f64", builtins, f64);
+ MKBUILTIN_TYPE ("usize", builtins, usize);
+ MKBUILTIN_TYPE ("isize", builtins, isize);
+ MKBUILTIN_TYPE ("char", builtins, char_tyty);
+ MKBUILTIN_TYPE ("str", builtins, str);
+ MKBUILTIN_TYPE ("!", builtins, never);
+
+ // unit type ()
+ TyTy::TupleType *unit_tyty
+ = TyTy::TupleType::get_unit_type (mappings->get_next_hir_id ());
+ std::vector<std::unique_ptr<AST::Type> > elems;
+ AST::TupleType *unit_type
+ = new AST::TupleType (std::move (elems), Linemap::predeclared_location ());
+ builtins.push_back (unit_type);
+ tyctx->insert_builtin (unit_tyty->get_ref (), unit_type->get_node_id (),
+ unit_tyty);
+ set_unit_type_node_id (unit_type->get_node_id ());
+}
+
+void
+Resolver::insert_resolved_name (NodeId refId, NodeId defId)
+{
+ resolved_names[refId] = defId;
+ get_name_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_name (NodeId refId, NodeId *defId)
+{
+ auto it = resolved_names.find (refId);
+ if (it == resolved_names.end ())
+ return false;
+
+ *defId = it->second;
+ return true;
+}
+
+void
+Resolver::insert_resolved_type (NodeId refId, NodeId defId)
+{
+ // auto it = resolved_types.find (refId);
+ // rust_assert (it == resolved_types.end ());
+
+ resolved_types[refId] = defId;
+ get_type_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_type (NodeId refId, NodeId *defId)
+{
+ auto it = resolved_types.find (refId);
+ if (it == resolved_types.end ())
+ return false;
+
+ *defId = it->second;
+ return true;
+}
+
+void
+Resolver::insert_resolved_label (NodeId refId, NodeId defId)
+{
+ auto it = resolved_labels.find (refId);
+ rust_assert (it == resolved_labels.end ());
+
+ resolved_labels[refId] = defId;
+ get_label_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_label (NodeId refId, NodeId *defId)
+{
+ auto it = resolved_labels.find (refId);
+ if (it == resolved_labels.end ())
+ return false;
+
+ *defId = it->second;
+ return true;
+}
+
+void
+Resolver::insert_resolved_macro (NodeId refId, NodeId defId)
+{
+ auto it = resolved_macros.find (refId);
+ rust_assert (it == resolved_macros.end ());
+
+ resolved_labels[refId] = defId;
+ get_label_scope ().append_reference_for_def (refId, defId);
+}
+
+bool
+Resolver::lookup_resolved_macro (NodeId refId, NodeId *defId)
+{
+ auto it = resolved_macros.find (refId);
+ if (it == resolved_macros.end ())
+ return false;
+
+ *defId = it->second;
+ return true;
+}
+
+} // namespace Resolver
+} // namespace Rust
new file mode 100644
@@ -0,0 +1,212 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_NAME_RESOLVER_H
+#define RUST_NAME_RESOLVER_H
+
+#include "rust-system.h"
+#include "rust-canonical-path.h"
+#include "rust-hir-map.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace Resolver {
+
+class Rib
+{
+public:
+ // Rust uses local_def_ids assigned by def_collector on the AST
+ // lets use NodeId instead
+ Rib (CrateNum crateNum, NodeId node_id);
+
+ // this takes the relative paths of items within a compilation unit for lookup
+ void insert_name (
+ const CanonicalPath &path, NodeId id, Location locus, bool shadow,
+ std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb);
+
+ bool lookup_canonical_path (const NodeId &id, CanonicalPath *ident);
+ bool lookup_name (const CanonicalPath &ident, NodeId *id);
+ void clear_name (const CanonicalPath &ident, NodeId id);
+ void append_reference_for_def (NodeId def, NodeId ref);
+ bool have_references_for_node (NodeId def) const;
+ bool decl_was_declared_here (NodeId def) const;
+ void debug () const;
+ std::string debug_str () const;
+
+ CrateNum get_crate_num () const { return crate_num; }
+ NodeId get_node_id () const { return node_id; }
+ std::map<NodeId, Location> &get_declarations () { return decls_within_rib; }
+
+private:
+ CrateNum crate_num;
+ NodeId node_id;
+ std::map<CanonicalPath, NodeId> path_mappings;
+ std::map<NodeId, CanonicalPath> reverse_path_mappings;
+ std::map<NodeId, Location> decls_within_rib;
+ std::map<NodeId, std::set<NodeId>> references;
+ Analysis::Mappings *mappings;
+};
+
+class Scope
+{
+public:
+ Scope (CrateNum crate_num);
+
+ void
+ insert (const CanonicalPath &ident, NodeId id, Location locus, bool shadow,
+ std::function<void (const CanonicalPath &, NodeId, Location)> dup_cb);
+
+ void insert (const CanonicalPath &ident, NodeId id, Location locus);
+ bool lookup (const CanonicalPath &ident, NodeId *id);
+
+ void iterate (std::function<bool (Rib *)> cb);
+ void iterate (std::function<bool (const Rib *)> cb) const;
+
+ Rib *peek ();
+ void push (NodeId id);
+ Rib *pop ();
+
+ bool decl_was_declared_here (NodeId def) const;
+ void append_reference_for_def (NodeId refId, NodeId defId);
+
+ CrateNum get_crate_num () const { return crate_num; }
+
+private:
+ CrateNum crate_num;
+ std::vector<Rib *> stack;
+};
+
+class Resolver
+{
+public:
+ static Resolver *get ();
+ ~Resolver () {}
+
+ // these builtin types
+ void insert_builtin_types (Rib *r);
+
+ // these will be required for type resolution passes to
+ // map back to tyty nodes
+ std::vector<AST::Type *> &get_builtin_types ();
+
+ void push_new_name_rib (Rib *r);
+ void push_new_type_rib (Rib *r);
+ void push_new_label_rib (Rib *r);
+ void push_new_macro_rib (Rib *r);
+
+ bool find_name_rib (NodeId id, Rib **rib);
+ bool find_type_rib (NodeId id, Rib **rib);
+ bool find_label_rib (NodeId id, Rib **rib);
+ bool find_macro_rib (NodeId id, Rib **rib);
+
+ void insert_resolved_name (NodeId refId, NodeId defId);
+ bool lookup_resolved_name (NodeId refId, NodeId *defId);
+
+ void insert_resolved_type (NodeId refId, NodeId defId);
+ bool lookup_resolved_type (NodeId refId, NodeId *defId);
+
+ void insert_resolved_label (NodeId refId, NodeId defId);
+ bool lookup_resolved_label (NodeId refId, NodeId *defId);
+
+ void insert_resolved_macro (NodeId refId, NodeId defId);
+ bool lookup_resolved_macro (NodeId refId, NodeId *defId);
+
+ // proxy for scoping
+ Scope &get_name_scope () { return name_scope; }
+ Scope &get_type_scope () { return type_scope; }
+ Scope &get_label_scope () { return label_scope; }
+ Scope &get_macro_scope () { return macro_scope; }
+
+ NodeId get_global_type_node_id () { return global_type_node_id; }
+ void set_unit_type_node_id (NodeId id) { unit_ty_node_id = id; }
+ NodeId get_unit_type_node_id () { return unit_ty_node_id; }
+
+ void push_new_module_scope (NodeId module_id)
+ {
+ current_module_stack.push_back (module_id);
+ }
+
+ void pop_module_scope ()
+ {
+ rust_assert (!current_module_stack.empty ());
+ current_module_stack.pop_back ();
+ }
+
+ NodeId peek_current_module_scope () const
+ {
+ rust_assert (!current_module_stack.empty ());
+ return current_module_stack.back ();
+ }
+
+ NodeId peek_crate_module_scope () const
+ {
+ rust_assert (!current_module_stack.empty ());
+ return current_module_stack.front ();
+ }
+
+ NodeId peek_parent_module_scope () const
+ {
+ rust_assert (current_module_stack.size () > 1);
+ return current_module_stack.at (current_module_stack.size () - 2);
+ }
+
+private:
+ Resolver ();
+
+ void generate_builtins ();
+
+ Analysis::Mappings *mappings;
+ TypeCheckContext *tyctx;
+
+ std::vector<AST::Type *> builtins;
+
+ Scope name_scope;
+ Scope type_scope;
+ Scope label_scope;
+ Scope macro_scope;
+
+ NodeId global_type_node_id;
+ NodeId unit_ty_node_id;
+
+ // map a AST Node to a Rib
+ std::map<NodeId, Rib *> name_ribs;
+ std::map<NodeId, Rib *> type_ribs;
+ std::map<NodeId, Rib *> label_ribs;
+ std::map<NodeId, Rib *> macro_ribs;
+
+ // Rust uses DefIds to namespace these under a crate_num
+ // but then it uses the def_collector to assign local_defids
+ // to each ast node as well. not sure if this is going to fit
+ // with gcc very well to compile a full crate in one go but we will
+ // see.
+
+ // these are of the form ref->Def-NodeId
+ // we need two namespaces one for names and ones for types
+ std::map<NodeId, NodeId> resolved_names;
+ std::map<NodeId, NodeId> resolved_types;
+ std::map<NodeId, NodeId> resolved_labels;
+ std::map<NodeId, NodeId> resolved_macros;
+
+ // keep track of the current module scope ids
+ std::vector<NodeId> current_module_stack;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_NAME_RESOLVER_H