aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Herron <philip.herron@embecosm.com>2021-09-13 15:31:19 +0100
committerPhilip Herron <philip.herron@embecosm.com>2021-09-14 13:23:56 +0100
commit002313b343746f8c72b62522e48e04fa0953b2d0 (patch)
treed393eecd5333696158e868e907ae93f7530de8ec
parentc644ee4c4351e3590f5396e94ec24ad7b828a954 (diff)
downloadgcc-002313b343746f8c72b62522e48e04fa0953b2d0.zip
gcc-002313b343746f8c72b62522e48e04fa0953b2d0.tar.gz
gcc-002313b343746f8c72b62522e48e04fa0953b2d0.tar.bz2
Initial autoderef support for method calls
There is compiler magic for method calls the self parameter can be of several forms: - specified type (self: Type) - immutable Self (self) - mutable Self (mut self) - immutable reference (&self) - mutable reference (&mut self) This updates our HIR lowering to actually lower this correctly and apply the apropriate Self type to the TyTy::FnDef. The code used to just default to plain Self ignoring any modifiers. Rust also allows something called the autoderef cycle to coerce the receiver to the correct type for the function such as: ```rust struct Foo(i32); impl Foo { fn bar(&self) { } } fn main() { let a = Foo(123); a.bar(); } ``` In this example the method call is expected to apply an implict reference to variable 'a' such that the method call becomes: ``` Foo::bar(&a); ``` The algorithm is detailed here: https://doc.rust-lang.org/nightly/nomicon/dot-operator.html 1. Try to match Self 2. Apply an immutable Reference and Try again 3. Apply an mutable Reference and Try again 4. Can we dereference ? [deref and go back to 1] else [quit] This is not 100% complete since we do not yet support operator overloading so we wil require an update to support the Deref operator overload for more complex types. Fixes: #241
-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
+}