aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-09-14 15:00:47 +0000
committerGitHub <noreply@github.com>2021-09-14 15:00:47 +0000
commitc8ffaa101c936822f5853a276d530da09c96cf52 (patch)
treed393eecd5333696158e868e907ae93f7530de8ec /gcc
parentc644ee4c4351e3590f5396e94ec24ad7b828a954 (diff)
parent002313b343746f8c72b62522e48e04fa0953b2d0 (diff)
downloadgcc-c8ffaa101c936822f5853a276d530da09c96cf52.zip
gcc-c8ffaa101c936822f5853a276d530da09c96cf52.tar.gz
gcc-c8ffaa101c936822f5853a276d530da09c96cf52.tar.bz2
Merge #672
672: Initial autoderef support for method calls r=philberty a=philberty The commit message contains more detail but this reference is good: https://doc.rust-lang.org/nightly/nomicon/dot-operator.html This is not 100% complete since we do not yet support operator overloading so we will require an update to support the Deref operator overload for more complex types. Fixes: #241 Co-authored-by: Philip Herron <philip.herron@embecosm.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/rust/backend/rust-compile.cc26
-rw-r--r--gcc/rust/hir/rust-ast-lower.cc21
-rw-r--r--gcc/rust/hir/tree/rust-hir-item.h8
-rw-r--r--gcc/rust/typecheck/rust-autoderef.h74
-rw-r--r--gcc/rust/typecheck/rust-hir-dot-operator.h182
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h60
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-implitem.h40
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.cc39
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check.h22
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc12
-rw-r--r--gcc/rust/typecheck/rust-tyty.h8
-rw-r--r--gcc/testsuite/rust/compile/method1.rs6
-rw-r--r--gcc/testsuite/rust/execute/torture/method1.rs27
13 files changed, 481 insertions, 44 deletions
diff --git a/gcc/rust/backend/rust-compile.cc b/gcc/rust/backend/rust-compile.cc
index ef2c16a..5214b1d 100644
--- a/gcc/rust/backend/rust-compile.cc
+++ b/gcc/rust/backend/rust-compile.cc
@@ -277,6 +277,32 @@ CompileExpr::visit (HIR::MethodCallExpr &expr)
// method receiver
Bexpression *self = CompileExpr::Compile (expr.get_receiver ().get (), ctx);
rust_assert (self != nullptr);
+
+ // lookup the autoderef mappings
+ std::vector<Resolver::Adjustment> *adjustments = nullptr;
+ ok = ctx->get_tyctx ()->lookup_autoderef_mappings (
+ expr.get_mappings ().get_hirid (), &adjustments);
+ rust_assert (ok);
+
+ for (auto &adjustment : *adjustments)
+ {
+ switch (adjustment.get_type ())
+ {
+ case Resolver::Adjustment::AdjustmentType::IMM_REF:
+ case Resolver::Adjustment::AdjustmentType::MUT_REF:
+ self = ctx->get_backend ()->address_expression (
+ self, expr.get_receiver ()->get_locus ());
+ break;
+
+ case Resolver::Adjustment::AdjustmentType::DEREF_REF:
+ Btype *expected_type
+ = TyTyResolveCompile::compile (ctx, adjustment.get_expected ());
+ self = ctx->get_backend ()->indirect_expression (
+ expected_type, self, true, /* known_valid*/
+ expr.get_receiver ()->get_locus ());
+ break;
+ }
+ }
args.push_back (self);
// normal args
diff --git a/gcc/rust/hir/rust-ast-lower.cc b/gcc/rust/hir/rust-ast-lower.cc
index b64e1a0..5c70b2c 100644
--- a/gcc/rust/hir/rust-ast-lower.cc
+++ b/gcc/rust/hir/rust-ast-lower.cc
@@ -403,17 +403,26 @@ ASTLoweringBase::lower_generic_args (AST::GenericArgs &args)
HIR::SelfParam
ASTLoweringBase::lower_self (AST::SelfParam &self)
{
- HIR::Type *type = self.has_type ()
- ? ASTLoweringType::translate (self.get_type ().get ())
- : nullptr;
-
auto crate_num = mappings->get_current_crate ();
Analysis::NodeMapping mapping (crate_num, self.get_node_id (),
mappings->get_next_hir_id (crate_num),
mappings->get_next_localdef_id (crate_num));
- return HIR::SelfParam (mapping, std::unique_ptr<HIR::Type> (type),
- self.get_is_mut (), self.get_locus ());
+ if (self.has_type ())
+ {
+ HIR::Type *type = ASTLoweringType::translate (self.get_type ().get ());
+ return HIR::SelfParam (mapping, std::unique_ptr<HIR::Type> (type),
+ self.get_is_mut (), self.get_locus ());
+ }
+ else if (!self.get_has_ref ())
+ {
+ return HIR::SelfParam (mapping, std::unique_ptr<HIR::Type> (nullptr),
+ self.get_is_mut (), self.get_locus ());
+ }
+
+ AST::Lifetime l = self.get_lifetime ();
+ return HIR::SelfParam (mapping, lower_lifetime (l), self.get_is_mut (),
+ self.get_locus ());
}
void
diff --git a/gcc/rust/hir/tree/rust-hir-item.h b/gcc/rust/hir/tree/rust-hir-item.h
index 936e11f..0b2cf10 100644
--- a/gcc/rust/hir/tree/rust-hir-item.h
+++ b/gcc/rust/hir/tree/rust-hir-item.h
@@ -310,10 +310,10 @@ struct SelfParam
public:
enum ImplicitSelfKind
{
- IMM,
- MUT,
- IMM_REF,
- MUT_REF,
+ IMM, // self
+ MUT, // mut self
+ IMM_REF, // &self
+ MUT_REF, // &mut self
NONE
};
diff --git a/gcc/rust/typecheck/rust-autoderef.h b/gcc/rust/typecheck/rust-autoderef.h
new file mode 100644
index 0000000..7a9083d
--- /dev/null
+++ b/gcc/rust/typecheck/rust-autoderef.h
@@ -0,0 +1,74 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_AUTODEREF
+#define RUST_AUTODEREF
+
+#include "rust-tyty.h"
+
+namespace Rust {
+namespace Resolver {
+
+class Adjustment
+{
+public:
+ enum AdjustmentType
+ {
+ IMM_REF,
+ MUT_REF,
+ DEREF_REF
+ };
+
+ Adjustment (AdjustmentType type, TyTy::BaseType *expected)
+ : type (type), expected (expected)
+ {}
+
+ AdjustmentType get_type () const { return type; }
+
+ TyTy::BaseType *get_expected () const { return expected; }
+
+ std::string as_string () const
+ {
+ return Adjustment::type_string (get_type ()) + "->"
+ + get_expected ()->debug_str ();
+ }
+
+ static std::string type_string (AdjustmentType type)
+ {
+ switch (type)
+ {
+ case AdjustmentType::IMM_REF:
+ return "IMM_REF";
+ case AdjustmentType::MUT_REF:
+ return "MUT_REF";
+ case AdjustmentType::DEREF_REF:
+ return "DEREF_REF";
+ }
+ gcc_unreachable ();
+ return "";
+ }
+
+private:
+ AdjustmentType type;
+ TyTy::BaseType *expected;
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_AUTODEREF
diff --git a/gcc/rust/typecheck/rust-hir-dot-operator.h b/gcc/rust/typecheck/rust-hir-dot-operator.h
new file mode 100644
index 0000000..6743862
--- /dev/null
+++ b/gcc/rust/typecheck/rust-hir-dot-operator.h
@@ -0,0 +1,182 @@
+// Copyright (C) 2020 Free Software Foundation, Inc.
+
+// This file is part of GCC.
+
+// GCC is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 3, or (at your option) any later
+// version.
+
+// GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+// for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with GCC; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#ifndef RUST_HIR_DOT_OPERATOR
+#define RUST_HIR_DOT_OPERATOR
+
+#include "rust-hir-path-probe.h"
+
+namespace Rust {
+namespace Resolver {
+
+// lookup if method exists for current type
+// if exists: done
+// if not: check again for auto-ref and auto-mut-ref
+// deref and start again with 1.*/
+
+// https://doc.rust-lang.org/nightly/nomicon/dot-operator.html
+
+class MethodResolution
+{
+public:
+ static PathProbeCandidate *
+ Select (std::vector<PathProbeCandidate> &candidates, TyTy::BaseType *receiver,
+ std::vector<Adjustment> &adjustments)
+ {
+ TyTy::BaseType *r = receiver;
+ while (true)
+ {
+ PathProbeCandidate *c = nullptr;
+
+ // 1. try raw
+ c = Try (candidates, r);
+ if (c != nullptr)
+ return c;
+
+ // 2. try ref
+ TyTy::ReferenceType *r1
+ = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
+ false);
+ c = Try (candidates, r1);
+ if (c != nullptr)
+ {
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::IMM_REF, r1));
+ return c;
+ }
+
+ // 3. try mut ref
+ TyTy::ReferenceType *r2
+ = new TyTy::ReferenceType (r->get_ref (), TyTy::TyVar (r->get_ref ()),
+ true);
+ c = Try (candidates, r2);
+ if (c != nullptr)
+ {
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::MUT_REF, r2));
+ return c;
+ }
+
+ // 4. deref to to 1, if cannot deref then quit
+ bool can_deref = r->get_kind () == TyTy::TypeKind::REF;
+ if (!can_deref)
+ return nullptr;
+
+ // FIXME this needs to use deref trait and fall back to unsized to
+ // remove array syntax
+
+ TyTy::ReferenceType *rr = static_cast<TyTy::ReferenceType *> (r);
+ r = rr->get_base ();
+ adjustments.push_back (
+ Adjustment (Adjustment::AdjustmentType::DEREF_REF, r));
+ }
+ return nullptr;
+ }
+
+private:
+ static PathProbeCandidate *Try (std::vector<PathProbeCandidate> &candidates,
+ const TyTy::BaseType *receiver)
+ {
+ TypeCheckContext *context = TypeCheckContext::get ();
+
+ // probe impls
+ for (auto &c : candidates)
+ {
+ bool is_func = c.type == PathProbeCandidate::CandidateType::IMPL_FUNC;
+ HIR::ImplBlock *block = c.item.impl.parent;
+ if (is_func && !block->has_trait_ref ())
+ {
+ HIR::Function *func
+ = static_cast<HIR::Function *> (c.item.impl.impl_item);
+
+ TyTy::BaseType *lookup = nullptr;
+ bool ok = context->lookup_type (func->get_mappings ().get_hirid (),
+ &lookup);
+ rust_assert (ok);
+ rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
+ if (fn->is_method ())
+ {
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (receiver->can_eq (fn_self, false))
+ {
+ return &c;
+ }
+ }
+ }
+ }
+
+ // probe trait impls
+ for (auto &c : candidates)
+ {
+ bool is_func = c.type == PathProbeCandidate::CandidateType::IMPL_FUNC;
+ HIR::ImplBlock *block = c.item.impl.parent;
+ if (is_func && block->has_trait_ref ())
+ {
+ HIR::Function *func
+ = static_cast<HIR::Function *> (c.item.impl.impl_item);
+
+ TyTy::BaseType *lookup = nullptr;
+ bool ok = context->lookup_type (func->get_mappings ().get_hirid (),
+ &lookup);
+ rust_assert (ok);
+ rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
+ if (fn->is_method ())
+ {
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (receiver->can_eq (fn_self, false))
+ {
+ return &c;
+ }
+ }
+ }
+ }
+
+ // probe trait bounds
+ for (auto &c : candidates)
+ {
+ bool is_func = c.type == PathProbeCandidate::CandidateType::TRAIT_FUNC;
+ if (is_func)
+ {
+ const TraitItemReference *item_ref = c.item.trait.item_ref;
+ TyTy::BaseType *lookup = item_ref->get_tyty ();
+ rust_assert (lookup->get_kind () == TyTy::TypeKind::FNDEF);
+
+ TyTy::FnType *fn = static_cast<TyTy::FnType *> (lookup);
+ if (fn->is_method ())
+ {
+ TyTy::BaseType *fn_self = fn->get_self_type ();
+ if (receiver->can_eq (fn_self, false))
+ {
+ return &c;
+ }
+ }
+ }
+ }
+
+ return nullptr;
+ }
+};
+
+} // namespace Resolver
+} // namespace Rust
+
+#endif // RUST_HIR_DOT_OPERATOR
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index 31c8909..07d4f90 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -30,6 +30,7 @@
#include "rust-hir-const-fold.h"
#include "rust-hir-trait-resolve.h"
#include "rust-hir-type-bounds.h"
+#include "rust-hir-dot-operator.h"
namespace Rust {
namespace Resolver {
@@ -207,7 +208,7 @@ public:
{
auto receiver_tyty
= TypeCheckExpr::Resolve (expr.get_receiver ().get (), false);
- if (receiver_tyty == nullptr)
+ if (receiver_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
rust_error_at (expr.get_receiver ()->get_locus (),
"failed to resolve receiver in MethodCallExpr");
@@ -216,50 +217,67 @@ public:
context->insert_receiver (expr.get_mappings ().get_hirid (), receiver_tyty);
+ // in order to probe of the correct type paths we need the root type, which
+ // strips any references
+ TyTy::BaseType *root = receiver_tyty->get_root ();
+
// https://doc.rust-lang.org/reference/expressions/method-call-expr.html
// method resolution is complex in rust once we start handling generics and
// traits. For now we only support looking up the valid name in impl blocks
// which is simple. There will need to be adjustments to ensure we can turn
// the receiver into borrowed references etc
- bool reciever_is_generic
- = receiver_tyty->get_kind () == TyTy::TypeKind::PARAM;
+ bool reciever_is_generic = root->get_kind () == TyTy::TypeKind::PARAM;
bool probe_bounds = true;
bool probe_impls = !reciever_is_generic;
bool ignore_mandatory_trait_items = !reciever_is_generic;
auto candidates
- = PathProbeType::Probe (receiver_tyty,
- expr.get_method_name ().get_segment (),
+ = PathProbeType::Probe (root, expr.get_method_name ().get_segment (),
probe_impls, probe_bounds,
ignore_mandatory_trait_items);
- if (candidates.size () == 0)
+ if (candidates.empty ())
{
rust_error_at (expr.get_locus (),
- "failed to resolve the PathExprSegment to any Method");
+ "failed to resolve the PathExprSegment to any item");
return;
}
- else if (candidates.size () > 1)
+
+ std::vector<Adjustment> adjustments;
+ PathProbeCandidate *resolved_candidate
+ = MethodResolution::Select (candidates, receiver_tyty, adjustments);
+ if (resolved_candidate == nullptr)
{
- ReportMultipleCandidateError::Report (
- candidates, expr.get_method_name ().get_segment (),
- expr.get_method_name ().get_locus ());
+ if (candidates.size () > 1)
+ {
+ // not sure if this is the correct error here
+ ReportMultipleCandidateError::Report (
+ candidates, expr.get_method_name ().get_segment (),
+ expr.get_method_name ().get_locus ());
+ }
+ else
+ {
+ rust_error_at (expr.get_locus (), "failed to resolve method");
+ }
return;
}
- auto resolved_candidate = candidates.at (0);
- TyTy::BaseType *lookup_tyty = resolved_candidate.ty;
+ // store the adjustments for code-generation to know what to do
+ context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (),
+ std::move (adjustments));
+
+ TyTy::BaseType *lookup_tyty = resolved_candidate->ty;
NodeId resolved_node_id
- = resolved_candidate.is_impl_candidate ()
- ? resolved_candidate.item.impl.impl_item->get_impl_mappings ()
+ = resolved_candidate->is_impl_candidate ()
+ ? resolved_candidate->item.impl.impl_item->get_impl_mappings ()
.get_nodeid ()
- : resolved_candidate.item.trait.item_ref->get_mappings ()
+ : resolved_candidate->item.trait.item_ref->get_mappings ()
.get_nodeid ();
if (lookup_tyty->get_kind () != TyTy::TypeKind::FNDEF)
{
RichLocation r (expr.get_method_name ().get_locus ());
- r.add_range (resolved_candidate.locus);
+ r.add_range (resolved_candidate->locus);
rust_error_at (r, "associated impl item is not a method");
return;
}
@@ -269,14 +287,14 @@ public:
if (!fn->is_method ())
{
RichLocation r (expr.get_method_name ().get_locus ());
- r.add_range (resolved_candidate.locus);
+ r.add_range (resolved_candidate->locus);
rust_error_at (r, "associated function is not a method");
return;
}
- if (receiver_tyty->get_kind () == TyTy::TypeKind::ADT)
+ if (root->get_kind () == TyTy::TypeKind::ADT)
{
- TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (receiver_tyty);
+ TyTy::ADTType *adt = static_cast<TyTy::ADTType *> (root);
if (adt->has_substitutions () && fn->needs_substitution ())
{
// consider the case where we have:
@@ -298,7 +316,7 @@ public:
// default types GenericParams on impl blocks since these must
// always be at the end of the list
- auto s = fn->get_self_type ();
+ auto s = fn->get_self_type ()->get_root ();
rust_assert (s->can_eq (adt, false));
rust_assert (s->get_kind () == TyTy::TypeKind::ADT);
TyTy::ADTType *self_adt = static_cast<TyTy::ADTType *> (s);
diff --git a/gcc/rust/typecheck/rust-hir-type-check-implitem.h b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
index d3977c3..94674ad 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-implitem.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-implitem.h
@@ -220,10 +220,45 @@ public:
HIR::IdentifierPattern *self_pattern = new HIR::IdentifierPattern (
"self", self_param.get_locus (), self_param.is_ref (),
self_param.is_mut (), std::unique_ptr<HIR::Pattern> (nullptr));
- context->insert_type (self_param.get_mappings (), self->clone ());
+
+ // might have a specified type
+ TyTy::BaseType *self_type = nullptr;
+ if (self_param.has_type ())
+ {
+ std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
+ self_type = TypeCheckType::Resolve (specified_type.get ());
+ }
+ else
+ {
+ switch (self_param.get_self_kind ())
+ {
+ case HIR::SelfParam::IMM:
+ case HIR::SelfParam::MUT:
+ self_type = self->clone ();
+ break;
+
+ case HIR::SelfParam::IMM_REF:
+ self_type = new TyTy::ReferenceType (
+ self_param.get_mappings ().get_hirid (),
+ TyTy::TyVar (self->get_ref ()), false);
+ break;
+
+ case HIR::SelfParam::MUT_REF:
+ self_type = new TyTy::ReferenceType (
+ self_param.get_mappings ().get_hirid (),
+ TyTy::TyVar (self->get_ref ()), true);
+ break;
+
+ default:
+ gcc_unreachable ();
+ return;
+ }
+ }
+
+ context->insert_type (self_param.get_mappings (), self_type);
params.push_back (
std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern,
- self->clone ()));
+ self_type));
}
for (auto &param : function.get_function_params ())
@@ -242,6 +277,7 @@ public:
function.get_mappings ().get_defid (), function.get_function_name (),
function.is_method () ? FNTYPE_IS_METHOD_FLAG : FNTYPE_DEFAULT_FLAGS,
ABI::RUST, std::move (params), ret_type, std::move (substitutions));
+
context->insert_type (function.get_mappings (), fnType);
}
diff --git a/gcc/rust/typecheck/rust-hir-type-check.cc b/gcc/rust/typecheck/rust-hir-type-check.cc
index f960f77..0cd6883 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.cc
+++ b/gcc/rust/typecheck/rust-hir-type-check.cc
@@ -529,10 +529,43 @@ TraitItemReference::get_type_from_fn (/*const*/ HIR::TraitItemFunc &fn) const
self_param.is_ref (),
self_param.is_mut (),
std::unique_ptr<HIR::Pattern> (nullptr));
- context->insert_type (self_param.get_mappings (), self->clone ());
+ // might have a specified type
+ TyTy::BaseType *self_type = nullptr;
+ if (self_param.has_type ())
+ {
+ std::unique_ptr<HIR::Type> &specified_type = self_param.get_type ();
+ self_type = TypeCheckType::Resolve (specified_type.get ());
+ }
+ else
+ {
+ switch (self_param.get_self_kind ())
+ {
+ case HIR::SelfParam::IMM:
+ case HIR::SelfParam::MUT:
+ self_type = self->clone ();
+ break;
+
+ case HIR::SelfParam::IMM_REF:
+ self_type = new TyTy::ReferenceType (
+ self_param.get_mappings ().get_hirid (),
+ TyTy::TyVar (self->get_ref ()), false);
+ break;
+
+ case HIR::SelfParam::MUT_REF:
+ self_type = new TyTy::ReferenceType (
+ self_param.get_mappings ().get_hirid (),
+ TyTy::TyVar (self->get_ref ()), true);
+ break;
+
+ default:
+ gcc_unreachable ();
+ return nullptr;
+ }
+ }
+
+ context->insert_type (self_param.get_mappings (), self_type);
params.push_back (
- std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern,
- self->clone ()));
+ std::pair<HIR::Pattern *, TyTy::BaseType *> (self_pattern, self_type));
}
for (auto &param : function.get_function_params ())
diff --git a/gcc/rust/typecheck/rust-hir-type-check.h b/gcc/rust/typecheck/rust-hir-type-check.h
index 491de85..bcad5db 100644
--- a/gcc/rust/typecheck/rust-hir-type-check.h
+++ b/gcc/rust/typecheck/rust-hir-type-check.h
@@ -23,6 +23,7 @@
#include "rust-hir-map.h"
#include "rust-tyty.h"
#include "rust-hir-trait-ref.h"
+#include "rust-autoderef.h"
namespace Rust {
namespace Resolver {
@@ -183,6 +184,24 @@ public:
return UNKNOWN_HIRID;
}
+ void insert_autoderef_mappings (HirId id,
+ std::vector<Adjustment> &&adjustments)
+ {
+ rust_assert (autoderef_mappings.find (id) == autoderef_mappings.end ());
+ autoderef_mappings.emplace (id, std::move (adjustments));
+ }
+
+ bool lookup_autoderef_mappings (HirId id,
+ std::vector<Adjustment> **adjustments)
+ {
+ auto it = autoderef_mappings.find (id);
+ if (it == autoderef_mappings.end ())
+ return false;
+
+ *adjustments = &it->second;
+ return true;
+ }
+
private:
TypeCheckContext ();
@@ -200,6 +219,9 @@ private:
associated_traits_to_impls;
std::map<HirId, HirId> associated_type_mappings;
+
+ // adjustment mappings
+ std::map<HirId, std::vector<Adjustment>> autoderef_mappings;
};
class TypeResolution
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 398b531..ef981cc 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -112,6 +112,18 @@ BaseType::inherit_bounds (
}
}
+BaseType *
+BaseType::get_root ()
+{
+ BaseType *root = this;
+ while (root->get_kind () == TyTy::REF)
+ {
+ ReferenceType *r = static_cast<ReferenceType *> (root);
+ root = r->get_base ();
+ }
+ return root;
+}
+
TyVar::TyVar (HirId ref) : ref (ref)
{
// ensure this reference is defined within the context
diff --git a/gcc/rust/typecheck/rust-tyty.h b/gcc/rust/typecheck/rust-tyty.h
index d3d4afd..a7eb132 100644
--- a/gcc/rust/typecheck/rust-tyty.h
+++ b/gcc/rust/typecheck/rust-tyty.h
@@ -221,8 +221,7 @@ public:
// Unify two types. Returns a pointer to the newly-created unified ty, or
// nullptr if the two ty cannot be unified. The caller is responsible for
- // releasing the memory of the returned ty. using ignore_errors alows for a
- // can_eq style unification
+ // releasing the memory of the returned ty.
virtual BaseType *unify (BaseType *other) = 0;
// similar to unify but does not actually perform type unification but
@@ -312,6 +311,8 @@ public:
debug_str ().c_str ());
}
+ BaseType *get_root ();
+
protected:
BaseType (HirId ref, HirId ty_ref, TypeKind kind,
std::set<HirId> refs = std::set<HirId> ())
@@ -1146,8 +1147,7 @@ public:
BaseType *get_self_type () const
{
rust_assert (is_method ());
- // FIXME this will need updated when we support coercion for & mut self etc
- return get_params ().at (0).second;
+ return param_at (0).second;
}
std::vector<std::pair<HIR::Pattern *, BaseType *>> &get_params ()
diff --git a/gcc/testsuite/rust/compile/method1.rs b/gcc/testsuite/rust/compile/method1.rs
index 0597671..cce4ecf 100644
--- a/gcc/testsuite/rust/compile/method1.rs
+++ b/gcc/testsuite/rust/compile/method1.rs
@@ -1,15 +1,13 @@
struct Foo(i32);
-
impl Foo {
fn test() {}
}
pub fn main() {
- // { dg-error {expected \[\(\)\] got \[<tyty::error>\]} "" { target *-*-* } .-1 }
let a;
a = Foo(123);
- a.test()
- // { dg-error "associated function is not a method" "" { target *-*-* } .-1 }
+ a.test();
+ // { dg-error "failed to resolve method" "" { target *-*-* } .-1 }
// { dg-error {failed to type resolve expression} "" { target *-*-* } .-2 }
}
diff --git a/gcc/testsuite/rust/execute/torture/method1.rs b/gcc/testsuite/rust/execute/torture/method1.rs
new file mode 100644
index 0000000..6af6133
--- /dev/null
+++ b/gcc/testsuite/rust/execute/torture/method1.rs
@@ -0,0 +1,27 @@
+/* { dg-output "124\n458" } */
+extern "C" {
+ fn printf(s: *const i8, ...);
+}
+
+struct Foo(i32);
+impl Foo {
+ fn bar(&self, i: i32) {
+ unsafe {
+ let a = "%i\n\0";
+ let b = a as *const str;
+ let c = b as *const i8;
+
+ printf(c, self.0 + i);
+ }
+ }
+}
+
+fn main() -> i32 {
+ let a = Foo(123);
+ a.bar(1);
+
+ let b = &Foo(456);
+ b.bar(2);
+
+ 0
+}