aboutsummaryrefslogtreecommitdiff
path: root/gcc/rust/backend/rust-compile-resolve-path.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/rust/backend/rust-compile-resolve-path.cc')
-rw-r--r--gcc/rust/backend/rust-compile-resolve-path.cc301
1 files changed, 301 insertions, 0 deletions
diff --git a/gcc/rust/backend/rust-compile-resolve-path.cc b/gcc/rust/backend/rust-compile-resolve-path.cc
new file mode 100644
index 0000000..4fb3d54
--- /dev/null
+++ b/gcc/rust/backend/rust-compile-resolve-path.cc
@@ -0,0 +1,301 @@
+// Copyright (C) 2020-2022 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include "rust-compile-resolve-path.h"
+#include "rust-compile-intrinsic.h"
+#include "rust-compile-item.h"
+#include "rust-compile-implitem.h"
+#include "rust-compile-expr.h"
+#include "rust-hir-trait-resolve.h"
+#include "rust-hir-path-probe.h"
+#include "rust-compile-extern.h"
+#include "rust-constexpr.h"
+
+namespace Rust {
+namespace Compile {
+
+void
+ResolvePathRef::visit (HIR::QualifiedPathInExpression &expr)
+{
+ resolved = resolve (expr.get_final_segment ().get_segment (),
+ expr.get_mappings (), expr.get_locus (), true);
+}
+
+void
+ResolvePathRef::visit (HIR::PathInExpression &expr)
+{
+ resolved = resolve (expr.get_final_segment ().get_segment (),
+ expr.get_mappings (), expr.get_locus (), false);
+}
+
+tree
+ResolvePathRef::resolve (const HIR::PathIdentSegment &final_segment,
+ const Analysis::NodeMapping &mappings,
+ Location expr_locus, bool is_qualified_path)
+{
+ TyTy::BaseType *lookup = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_type (mappings.get_hirid (), &lookup);
+ rust_assert (ok);
+
+ // need to look up the reference for this identifier
+ NodeId ref_node_id = UNKNOWN_NODEID;
+ if (!ctx->get_resolver ()->lookup_resolved_name (mappings.get_nodeid (),
+ &ref_node_id))
+ {
+ // this can fail because it might be a Constructor for something
+ // in that case the caller should attempt ResolvePathType::Compile
+
+ // it might be an enum data-less enum variant
+ if (lookup->get_kind () != TyTy::TypeKind::ADT)
+ return error_mark_node;
+
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (lookup);
+
+ // it might be a unit-struct
+ if (adt->is_unit ())
+ {
+ return ctx->get_backend ()->unit_expression ();
+ }
+
+ if (!adt->is_enum ())
+ return error_mark_node;
+
+ HirId variant_id;
+ if (!ctx->get_tyctx ()->lookup_variant_definition (mappings.get_hirid (),
+ &variant_id))
+ return error_mark_node;
+
+ int union_disriminator = -1;
+ TyTy::VariantDef *variant = nullptr;
+ if (!adt->lookup_variant_by_id (variant_id, &variant,
+ &union_disriminator))
+ return error_mark_node;
+
+ // this can only be for discriminant variants the others are built up
+ // using call-expr or struct-init
+ rust_assert (variant->get_variant_type ()
+ == TyTy::VariantDef::VariantType::NUM);
+
+ // we need the actual gcc type
+ tree compiled_adt_type = TyTyResolveCompile::compile (ctx, adt);
+
+ // make the ctor for the union
+ HIR::Expr *discrim_expr = variant->get_discriminant ();
+ tree discrim_expr_node = CompileExpr::Compile (discrim_expr, ctx);
+ tree folded_discrim_expr = fold_expr (discrim_expr_node);
+ tree qualifier = folded_discrim_expr;
+
+ return ctx->get_backend ()->constructor_expression (compiled_adt_type,
+ true, {qualifier},
+ union_disriminator,
+ expr_locus);
+ }
+
+ HirId ref;
+ if (!ctx->get_mappings ()->lookup_node_to_hir (ref_node_id, &ref))
+ {
+ rust_error_at (expr_locus, "reverse call path lookup failure");
+ return error_mark_node;
+ }
+
+ // might be a constant
+ tree constant_expr;
+ if (ctx->lookup_const_decl (ref, &constant_expr))
+ {
+ TREE_USED (constant_expr) = 1;
+ return constant_expr;
+ }
+
+ // this might be a variable reference or a function reference
+ Bvariable *var = nullptr;
+ if (ctx->lookup_var_decl (ref, &var))
+ {
+ // TREE_USED is setup in the gcc abstraction here
+ return ctx->get_backend ()->var_expression (var, expr_locus);
+ }
+
+ // might be a match pattern binding
+ tree binding = error_mark_node;
+ if (ctx->lookup_pattern_binding (ref, &binding))
+ {
+ TREE_USED (binding) = 1;
+ return binding;
+ }
+
+ // it might be a function call
+ if (lookup->get_kind () == TyTy::TypeKind::FNDEF)
+ {
+ TyTy::FnType *fntype = static_cast<TyTy::FnType *> (lookup);
+ tree fn = NULL_TREE;
+ if (ctx->lookup_function_decl (fntype->get_ty_ref (), &fn))
+ {
+ TREE_USED (fn) = 1;
+ return address_expression (fn, expr_locus);
+ }
+ else if (fntype->get_abi () == ABI::INTRINSIC)
+ {
+ Intrinsics compile (ctx);
+ fn = compile.compile (fntype);
+ TREE_USED (fn) = 1;
+ return address_expression (fn, expr_locus);
+ }
+ }
+
+ // let the query system figure it out
+ tree resolved_item = query_compile (ref, lookup, final_segment, mappings,
+ expr_locus, is_qualified_path);
+ if (resolved_item != error_mark_node)
+ {
+ TREE_USED (resolved_item) = 1;
+ }
+ return resolved_item;
+}
+
+tree
+HIRCompileBase::query_compile (HirId ref, TyTy::BaseType *lookup,
+ const HIR::PathIdentSegment &final_segment,
+ const Analysis::NodeMapping &mappings,
+ Location expr_locus, bool is_qualified_path)
+{
+ HIR::Item *resolved_item = ctx->get_mappings ()->lookup_hir_item (ref);
+ HirId parent_block;
+ HIR::ExternalItem *resolved_extern_item
+ = ctx->get_mappings ()->lookup_hir_extern_item (ref, &parent_block);
+ bool is_hir_item = resolved_item != nullptr;
+ bool is_hir_extern_item = resolved_extern_item != nullptr;
+ if (is_hir_item)
+ {
+ if (!lookup->has_subsititions_defined ())
+ return CompileItem::compile (resolved_item, ctx, nullptr, true,
+ expr_locus);
+ else
+ return CompileItem::compile (resolved_item, ctx, lookup, true,
+ expr_locus);
+ }
+ else if (is_hir_extern_item)
+ {
+ if (!lookup->has_subsititions_defined ())
+ return CompileExternItem::compile (resolved_extern_item, ctx, nullptr,
+ true, expr_locus);
+ else
+ return CompileExternItem::compile (resolved_extern_item, ctx, lookup,
+ true, expr_locus);
+ }
+ else
+ {
+ HirId parent_impl_id = UNKNOWN_HIRID;
+ HIR::ImplItem *resolved_item
+ = ctx->get_mappings ()->lookup_hir_implitem (ref, &parent_impl_id);
+ bool is_impl_item = resolved_item != nullptr;
+ if (is_impl_item)
+ {
+ rust_assert (parent_impl_id != UNKNOWN_HIRID);
+ HIR::Item *impl_ref
+ = ctx->get_mappings ()->lookup_hir_item (parent_impl_id);
+ rust_assert (impl_ref != nullptr);
+ HIR::ImplBlock *impl = static_cast<HIR::ImplBlock *> (impl_ref);
+
+ TyTy::BaseType *self = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_type (
+ impl->get_type ()->get_mappings ().get_hirid (), &self);
+ rust_assert (ok);
+
+ if (!lookup->has_subsititions_defined ())
+ return CompileInherentImplItem::Compile (resolved_item, ctx,
+ nullptr, true, expr_locus);
+ else
+ return CompileInherentImplItem::Compile (resolved_item, ctx, lookup,
+ true, expr_locus);
+ }
+ else
+ {
+ // it might be resolved to a trait item
+ HIR::TraitItem *trait_item
+ = ctx->get_mappings ()->lookup_hir_trait_item (ref);
+ HIR::Trait *trait = ctx->get_mappings ()->lookup_trait_item_mapping (
+ trait_item->get_mappings ().get_hirid ());
+
+ Resolver::TraitReference *trait_ref
+ = &Resolver::TraitReference::error_node ();
+ bool ok = ctx->get_tyctx ()->lookup_trait_reference (
+ trait->get_mappings ().get_defid (), &trait_ref);
+ rust_assert (ok);
+
+ TyTy::BaseType *receiver = nullptr;
+ ok = ctx->get_tyctx ()->lookup_receiver (mappings.get_hirid (),
+ &receiver);
+ rust_assert (ok);
+
+ if (receiver->get_kind () == TyTy::TypeKind::PARAM)
+ {
+ TyTy::ParamType *p = static_cast<TyTy::ParamType *> (receiver);
+ receiver = p->resolve ();
+ }
+
+ // the type resolver can only resolve type bounds to their trait
+ // item so its up to us to figure out if this path should resolve
+ // to an trait-impl-block-item or if it can be defaulted to the
+ // trait-impl-item's definition
+ std::vector<Resolver::PathProbeCandidate> candidates
+ = Resolver::PathProbeImplTrait::Probe (receiver, final_segment,
+ trait_ref);
+ if (candidates.size () == 0)
+ {
+ // this means we are defaulting back to the trait_item if
+ // possible
+ Resolver::TraitItemReference *trait_item_ref = nullptr;
+ bool ok = trait_ref->lookup_hir_trait_item (*trait_item,
+ &trait_item_ref);
+ rust_assert (ok); // found
+ rust_assert (trait_item_ref->is_optional ()); // has definition
+
+ return CompileTraitItem::Compile (
+ trait_item_ref->get_hir_trait_item (), ctx, lookup, true,
+ expr_locus);
+ }
+ else
+ {
+ Resolver::PathProbeCandidate &candidate = candidates.at (0);
+ rust_assert (candidate.is_impl_candidate ());
+
+ HIR::ImplBlock *impl = candidate.item.impl.parent;
+ HIR::ImplItem *impl_item = candidate.item.impl.impl_item;
+
+ TyTy::BaseType *self = nullptr;
+ bool ok = ctx->get_tyctx ()->lookup_type (
+ impl->get_type ()->get_mappings ().get_hirid (), &self);
+ rust_assert (ok);
+
+ if (!lookup->has_subsititions_defined ())
+ return CompileInherentImplItem::Compile (impl_item, ctx,
+ nullptr, true,
+ expr_locus);
+ else
+ return CompileInherentImplItem::Compile (impl_item, ctx, lookup,
+ true, expr_locus);
+
+ lookup->set_ty_ref (impl_item->get_impl_mappings ().get_hirid ());
+ }
+ }
+ }
+
+ return error_mark_node;
+}
+
+} // namespace Compile
+} // namespace Rust