From patchwork Tue Dec 6 10:13:48 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arthur Cohen X-Patchwork-Id: 61510 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8E930395C052 for ; Tue, 6 Dec 2022 10:17:59 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by sourceware.org (Postfix) with ESMTPS id 9D0E6396E46B for ; Tue, 6 Dec 2022 10:12:14 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org 9D0E6396E46B Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=embecosm.com Received: by mail-wr1-x42b.google.com with SMTP id d1so22712161wrs.12 for ; Tue, 06 Dec 2022 02:12:14 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:from:to:cc:subject :date:message-id:reply-to; bh=kHbfIItlcNhk4QLLUncA7XzS5dy8KQqqEYYFWLfkx7w=; b=cSLxvSfdy73xlQPJaBDTkgU8LW1qoHJLzh1zn0pdhL9+QGrDASPsxUJYqRpjHFzKCf ZUPWENhtHU+QbAxdd5nTDsIaQotlsyziLo62IUU57J1NRRBeU+rGVfg/+p7We0to9sew yoneyJQWFJ4mX0xPMOuqtRo1h6AZDRc9cAkVvkVWTlSCniMn8GwgysGBxF4P9CJaRqRN Nnx+98vNRFdXn4CFMrNKA7i+p6byNzpGq+w1x49awbIgtjUpMdX3Qi0L4L5yqSRtBGZ7 VMF48jAQfduPEkCl1qVBX+mm7y65B05vA/jhfojxZN3gT7PZ1kIsO0uBTOZClnMxpkyh m4yA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:reply-to:references :in-reply-to:message-id:date:subject:cc:to:from:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=kHbfIItlcNhk4QLLUncA7XzS5dy8KQqqEYYFWLfkx7w=; b=mt2Fd1ac0fTbdzWJx3RklGt99Dnca4U/FirwIwqBdt00KiAM1p1YNBEBV+jLxqcRf0 oYU4blmTshJV9cABkN7MX+zaSBV8bVMFXApEJj1TjIcUZ0EA3PJm4FMeQTKfVyW8l2HI tjbvk1shvrpGxSoViI86aY+rQS/mCkrYKefVSSymb6lEvBxA8VWm6klbrZyc8WsnVtbN BouMtIOXgSi+5wmiqgdgnf2pwFEEYCooEV4b9AbZq+MPtpHcmGDqAWmrFTTiLSwkeXa6 rEKLNFxXKRnhXSKl1uIXN9SfzNqsy1d/7CQQLBobpGGDwFpEvCOh2Tdd8K9uIoRVvc36 CZWA== X-Gm-Message-State: ANoB5plSM6VQNkWKfz37Tj9jt9ckCZ1vS8nMXqxOyTa0wQQjb5J6xDmu Gocejz3Qi8dcUY1TBhS5UdJRglZbZ6cSwUW9Yg== X-Google-Smtp-Source: AA0mqf7M6ycSMokxWlHb9NydtyHux+Epr63gK9ztO1/ndhjvNFAVAXsOdE8rdFCj/UaL5sfPfhmYcw== X-Received: by 2002:a5d:6b0e:0:b0:236:7439:61e7 with SMTP id v14-20020a5d6b0e000000b00236743961e7mr44182588wrw.611.1670321532285; Tue, 06 Dec 2022 02:12:12 -0800 (PST) Received: from platypus.lan ([2001:861:5e4c:3bb0:6424:328a:1734:3249]) by smtp.googlemail.com with ESMTPSA id r10-20020a05600c458a00b003cfd4a50d5asm27052699wmo.34.2022.12.06.02.12.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 06 Dec 2022 02:12:11 -0800 (PST) From: arthur.cohen@embecosm.com To: gcc-patches@gcc.gnu.org Cc: gcc-rust@gcc.gnu.org, Philip Herron Subject: [PATCH Rust front-end v4 16/46] gccrs: Add name resolution pass to the Rust front-end Date: Tue, 6 Dec 2022 11:13:48 +0100 Message-Id: <20221206101417.778807-17-arthur.cohen@embecosm.com> X-Mailer: git-send-email 2.38.1 In-Reply-To: <20221206101417.778807-1-arthur.cohen@embecosm.com> References: <20221206101417.778807-1-arthur.cohen@embecosm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-21.9 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: arthur.cohen@embecosm.com Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" From: Philip Herron The name resolution is split into two phases, one toplevel pass which scans the whole "Crate" which iterates all items and nested items in modules to generate a context class full of CanonicalPath items. It also generates a hierarchy of parent->child and child->parent relationships using the AST NodeId for PathResolution in the second phase. The second phase drills into each item like functions and creates a stack of canonical paths for variables etc so that we can store information in a side table of usage variable 'a' resolves to NodeId '123' which refers to the NodeId of the "let a;" statement. --- gcc/rust/resolve/rust-ast-resolve-base.cc | 658 +++++++++ gcc/rust/resolve/rust-ast-resolve-base.h | 221 +++ gcc/rust/resolve/rust-ast-resolve-expr.cc | 574 ++++++++ gcc/rust/resolve/rust-ast-resolve-expr.h | 133 ++ gcc/rust/resolve/rust-ast-resolve-implitem.h | 275 ++++ gcc/rust/resolve/rust-ast-resolve-item.cc | 1237 +++++++++++++++++ gcc/rust/resolve/rust-ast-resolve-item.h | 149 ++ gcc/rust/resolve/rust-ast-resolve-path.cc | 384 +++++ gcc/rust/resolve/rust-ast-resolve-path.h | 52 + gcc/rust/resolve/rust-ast-resolve-pattern.cc | 163 +++ gcc/rust/resolve/rust-ast-resolve-pattern.h | 98 ++ gcc/rust/resolve/rust-ast-resolve-stmt.cc | 38 + gcc/rust/resolve/rust-ast-resolve-stmt.h | 378 +++++ .../rust-ast-resolve-struct-expr-field.cc | 61 + .../rust-ast-resolve-struct-expr-field.h | 55 + gcc/rust/resolve/rust-ast-resolve-toplevel.h | 460 ++++++ gcc/rust/resolve/rust-ast-resolve-type.cc | 582 ++++++++ gcc/rust/resolve/rust-ast-resolve-type.h | 290 ++++ gcc/rust/resolve/rust-ast-resolve.cc | 115 ++ gcc/rust/resolve/rust-ast-resolve.h | 50 + gcc/rust/resolve/rust-ast-verify-assignee.h | 84 ++ gcc/rust/resolve/rust-name-resolver.cc | 503 +++++++ gcc/rust/resolve/rust-name-resolver.h | 212 +++ 23 files changed, 6772 insertions(+) create mode 100644 gcc/rust/resolve/rust-ast-resolve-base.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-base.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-expr.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-expr.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-implitem.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-item.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-item.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-path.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-path.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-pattern.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-pattern.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-stmt.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-stmt.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-toplevel.h create mode 100644 gcc/rust/resolve/rust-ast-resolve-type.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve-type.h create mode 100644 gcc/rust/resolve/rust-ast-resolve.cc create mode 100644 gcc/rust/resolve/rust-ast-resolve.h create mode 100644 gcc/rust/resolve/rust-ast-verify-assignee.h create mode 100644 gcc/rust/resolve/rust-name-resolver.cc create mode 100644 gcc/rust/resolve/rust-name-resolver.h diff --git a/gcc/rust/resolve/rust-ast-resolve-base.cc b/gcc/rust/resolve/rust-ast-resolve-base.cc new file mode 100644 index 00000000000..2a78918fbdb --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-base.cc @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-base.h b/gcc/rust/resolve/rust-ast-resolve-base.h new file mode 100644 index 00000000000..32f30bcea62 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-base.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.cc b/gcc/rust/resolve/rust-ast-resolve-expr.cc new file mode 100644 index 00000000000..4cc4e26e3e9 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-expr.cc @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-expr.h b/gcc/rust/resolve/rust-ast-resolve-expr.h new file mode 100644 index 00000000000..11a846ac8cd --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-expr.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-implitem.h b/gcc/rust/resolve/rust-ast-resolve-implitem.h new file mode 100644 index 00000000000..29dbe3436f5 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-implitem.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-item.cc b/gcc/rust/resolve/rust-ast-resolve-item.cc new file mode 100644 index 00000000000..0c38f28d530 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-item.cc @@ -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 +// . + +#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 (nullptr)); + + std::vector> segments; + segments.push_back (std::unique_ptr ( + 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 = ""; + 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 (nullptr)); + + std::vector> segments; + segments.push_back (std::unique_ptr ( + 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 + = ""; + 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 (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 &paths); +static void +flatten_rebind (const AST::UseTreeRebind &glob, + std::vector &paths); +static void +flatten_list (const AST::UseTreeList &glob, + std::vector &paths); + +static void +flatten (const AST::UseTree *tree, std::vector &paths) +{ + switch (tree->get_kind ()) + { + case AST::UseTree::Glob: { + auto glob = static_cast (tree); + flatten_glob (*glob, paths); + break; + } + case AST::UseTree::Rebind: { + auto rebind = static_cast (tree); + flatten_rebind (*rebind, paths); + break; + } + case AST::UseTree::List: { + auto list = static_cast (tree); + flatten_list (*list, paths); + break; + } + break; + } +} + +static void +flatten_glob (const AST::UseTreeGlob &glob, std::vector &paths) +{ + if (glob.has_path ()) + paths.emplace_back (glob.get_path ()); +} + +static void +flatten_rebind (const AST::UseTreeRebind &rebind, + std::vector &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 &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 (); + 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 +flatten_use_dec_to_paths (const AST::UseDeclaration &use_item) +{ + auto paths = std::vector (); + + 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::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::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::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::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::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 ( + new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, baz, + Location ())); + auto use1 = std::unique_ptr ( + new Rust::AST::UseTreeRebind (Rust::AST::UseTreeRebind::NONE, bul, + Location ())); + + auto uses = std::vector> (); + 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::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 diff --git a/gcc/rust/resolve/rust-ast-resolve-item.h b/gcc/rust/resolve/rust-ast-resolve-item.h new file mode 100644 index 00000000000..ce521f057f6 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-item.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-path.cc b/gcc/rust/resolve/rust-ast-resolve-path.cc new file mode 100644 index 00000000000..b139c6a8720 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-path.cc @@ -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 +// . + +#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 % 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 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 % 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 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 diff --git a/gcc/rust/resolve/rust-ast-resolve-path.h b/gcc/rust/resolve/rust-ast-resolve-path.h new file mode 100644 index 00000000000..a9af0c5819c --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-path.h @@ -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 +// . + +#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 &segs, + NodeId expr_node_id, Location expr_locus); +}; + +} // namespace Resolver +} // namespace Rust + +#endif // !RUST_AST_RESOLVE_PATH_H diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.cc b/gcc/rust/resolve/rust-ast-resolve-pattern.cc new file mode 100644 index 00000000000..9386d36d25e --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.cc @@ -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 +// . + +#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 &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 (*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 (*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 &items = pattern.get_items (); + switch (items->get_pattern_type ()) + { + case AST::TuplePatternItems::TuplePatternItemType::MULTIPLE: { + AST::TuplePatternItemsMultiple &ref + = *static_cast ( + 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 ( + 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 (bound); + + ResolvePath::go (&ref.get_path ()); + } + break; + + case AST::RangePatternBound::RangePatternBoundType::QUALPATH: { + AST::RangePatternBoundQualPath &ref + = *static_cast (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 diff --git a/gcc/rust/resolve/rust-ast-resolve-pattern.h b/gcc/rust/resolve/rust-ast-resolve-pattern.h new file mode 100644 index 00000000000..fcbb23fdf08 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-pattern.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.cc b/gcc/rust/resolve/rust-ast-resolve-stmt.cc new file mode 100644 index 00000000000..1ce3df0891c --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.cc @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-stmt.h b/gcc/rust/resolve/rust-ast-resolve-stmt.h new file mode 100644 index 00000000000..6f21bc35a33 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-stmt.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc new file mode 100644 index 00000000000..4d8b6c788f3 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.cc @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h new file mode 100644 index 00000000000..ce60b136e4b --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-struct-expr-field.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-toplevel.h b/gcc/rust/resolve/rust-ast-resolve-toplevel.h new file mode 100644 index 00000000000..43ae8e47673 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-toplevel.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve-type.cc b/gcc/rust/resolve/rust-ast-resolve-type.cc new file mode 100644 index 00000000000..6b08613755a --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-type.cc @@ -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 +// . + +#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 (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 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 &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 (final_seg.get ()); + + std::vector 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 = ""; + 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 diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h new file mode 100644 index 00000000000..5a71268c0d4 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve-type.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc new file mode 100644 index 00000000000..93fa7c8761c --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve.cc @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-resolve.h b/gcc/rust/resolve/rust-ast-resolve.h new file mode 100644 index 00000000000..a2e10d5c742 --- /dev/null +++ b/gcc/rust/resolve/rust-ast-resolve.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-ast-verify-assignee.h b/gcc/rust/resolve/rust-ast-verify-assignee.h new file mode 100644 index 00000000000..74551cb014d --- /dev/null +++ b/gcc/rust/resolve/rust-ast-verify-assignee.h @@ -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 +// . + +#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 diff --git a/gcc/rust/resolve/rust-name-resolver.cc b/gcc/rust/resolve/rust-name-resolver.cc new file mode 100644 index 00000000000..fb7087425c1 --- /dev/null +++ b/gcc/rust/resolve/rust-name-resolver.cc @@ -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 +// . + +#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 ( \ + new AST::TypePathSegment (::std::move (seg), false, \ + Linemap::predeclared_location ())); \ + ::std::vector< ::std::unique_ptr > 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 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 (id, path)); + decls_within_rib.insert (std::pair (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 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 cb) +{ + for (auto it = stack.rbegin (); it != stack.rend (); ++it) + { + if (!cb (*it)) + return; + } +} + +void +Scope::iterate (std::function 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 & +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 > 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 diff --git a/gcc/rust/resolve/rust-name-resolver.h b/gcc/rust/resolve/rust-name-resolver.h new file mode 100644 index 00000000000..014628a87c9 --- /dev/null +++ b/gcc/rust/resolve/rust-name-resolver.h @@ -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 +// . + +#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 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 &get_declarations () { return decls_within_rib; } + +private: + CrateNum crate_num; + NodeId node_id; + std::map path_mappings; + std::map reverse_path_mappings; + std::map decls_within_rib; + std::map> references; + Analysis::Mappings *mappings; +}; + +class Scope +{ +public: + Scope (CrateNum crate_num); + + void + insert (const CanonicalPath &ident, NodeId id, Location locus, bool shadow, + std::function dup_cb); + + void insert (const CanonicalPath &ident, NodeId id, Location locus); + bool lookup (const CanonicalPath &ident, NodeId *id); + + void iterate (std::function cb); + void iterate (std::function 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 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 &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 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 name_ribs; + std::map type_ribs; + std::map label_ribs; + std::map 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 resolved_names; + std::map resolved_types; + std::map resolved_labels; + std::map resolved_macros; + + // keep track of the current module scope ids + std::vector current_module_stack; +}; + +} // namespace Resolver +} // namespace Rust + +#endif // RUST_NAME_RESOLVER_H