aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-11-18 00:16:47 +0000
committerGitHub <noreply@github.com>2021-11-18 00:16:47 +0000
commit0995184e26f81f8ba6872c3efb59f640a7fe7162 (patch)
tree01e0e210f795a5fbf25c386aae758d0336ccad8c
parent63fc39600ce2640e9c4d07e00e162c2529b1820a (diff)
parentdb832831ed15ad25aec99a7d4a87b7019e5f1aa4 (diff)
downloadgcc-0995184e26f81f8ba6872c3efb59f640a7fe7162.zip
gcc-0995184e26f81f8ba6872c3efb59f640a7fe7162.tar.gz
gcc-0995184e26f81f8ba6872c3efb59f640a7fe7162.tar.bz2
Merge #810
810: Fix MethodCalls for covariant impl blocks r=philberty a=philberty I think we need to research more into how we probe for potential candidates for method calls. This fixes a few bugs going on in #808 one where the canonical path was empty and one where we fail to probe directly on the receiver of reference types to impl blocks but we must be able to also support that autoderef means that a receiver's root type might actually be the type we care about for example a reference to a generic type-parameter and we probe its bounds for candidates for example. Lets consult the rustc code and references on this. Fixes #808 Co-authored-by: Philip Herron <philip.herron@embecosm.com>
-rw-r--r--gcc/rust/Make-lang.in1
-rw-r--r--gcc/rust/resolve/rust-ast-resolve-type.h3
-rw-r--r--gcc/rust/resolve/rust-ast-resolve.cc38
-rw-r--r--gcc/rust/typecheck/rust-hir-type-check-expr.h29
-rw-r--r--gcc/rust/typecheck/rust-substitution-mapper.cc49
-rw-r--r--gcc/rust/typecheck/rust-substitution-mapper.h8
-rw-r--r--gcc/rust/typecheck/rust-tyty-call.h9
-rw-r--r--gcc/rust/typecheck/rust-tyty.cc2
-rw-r--r--gcc/testsuite/rust/compile/torture/issue-808.rs23
9 files changed, 140 insertions, 22 deletions
diff --git a/gcc/rust/Make-lang.in b/gcc/rust/Make-lang.in
index f3302c2e..f0e9bc3 100644
--- a/gcc/rust/Make-lang.in
+++ b/gcc/rust/Make-lang.in
@@ -86,6 +86,7 @@ GRS_OBJS = \
rust/rust-hir-const-fold.o \
rust/rust-hir-type-check-type.o \
rust/rust-hir-type-check-struct.o \
+ rust/rust-substitution-mapper.o \
rust/rust-lint-marklive.o \
rust/rust-hir-type-check-path.o \
rust/rust-compile-intrinsic.o \
diff --git a/gcc/rust/resolve/rust-ast-resolve-type.h b/gcc/rust/resolve/rust-ast-resolve-type.h
index 838d173..2bcf79d 100644
--- a/gcc/rust/resolve/rust-ast-resolve-type.h
+++ b/gcc/rust/resolve/rust-ast-resolve-type.h
@@ -101,6 +101,7 @@ protected:
using Rust::Resolver::ResolverBase::visit;
public:
+ // FIXME this should really only take AST::TypeNoBounds&
static CanonicalPath resolve (AST::Type &type,
bool include_generic_args = true,
bool type_resolve_generic_args = true)
@@ -121,6 +122,8 @@ public:
}
}
+ void visit (AST::ReferenceType &ref) override;
+
void visit (AST::TypePathSegmentGeneric &seg) override;
void visit (AST::TypePathSegment &seg) override;
diff --git a/gcc/rust/resolve/rust-ast-resolve.cc b/gcc/rust/resolve/rust-ast-resolve.cc
index 921b77c..9a0d349 100644
--- a/gcc/rust/resolve/rust-ast-resolve.cc
+++ b/gcc/rust/resolve/rust-ast-resolve.cc
@@ -439,8 +439,10 @@ ResolveTypeToCanonicalPath::visit (AST::TypePathSegmentGeneric &seg)
if (!seg.has_generic_args ())
{
- result = CanonicalPath::new_seg (seg.get_node_id (),
- seg.get_ident_segment ().as_string ());
+ auto ident_segment
+ = CanonicalPath::new_seg (seg.get_node_id (),
+ seg.get_ident_segment ().as_string ());
+ result = result.append (ident_segment);
return;
}
@@ -454,14 +456,18 @@ ResolveTypeToCanonicalPath::visit (AST::TypePathSegmentGeneric &seg)
{
std::string generics
= canonicalize_generic_args (seg.get_generic_args ());
- result = CanonicalPath::new_seg (seg.get_node_id (),
- seg.get_ident_segment ().as_string ()
- + "::" + generics);
+ auto generic_segment
+ = CanonicalPath::new_seg (seg.get_node_id (),
+ seg.get_ident_segment ().as_string ()
+ + "::" + generics);
+ result = result.append (generic_segment);
return;
}
- result = CanonicalPath::new_seg (seg.get_node_id (),
- seg.get_ident_segment ().as_string ());
+ auto ident_segment
+ = CanonicalPath::new_seg (seg.get_node_id (),
+ seg.get_ident_segment ().as_string ());
+ result = result.append (ident_segment);
}
void
@@ -481,6 +487,24 @@ ResolveTypeToCanonicalPath::visit (AST::TypePathSegment &seg)
result = result.append (ident_seg);
}
+void
+ResolveTypeToCanonicalPath::visit (AST::ReferenceType &ref)
+{
+ auto inner_type
+ = ResolveTypeToCanonicalPath::resolve (*ref.get_type_referenced ().get (),
+ include_generic_args_flag,
+ type_resolve_generic_args_flag);
+
+ std::string segment_string ("&");
+ if (ref.get_has_mut ())
+ segment_string += "mut ";
+
+ segment_string += inner_type.get ();
+
+ auto ident_seg = CanonicalPath::new_seg (ref.get_node_id (), segment_string);
+ result = result.append (ident_seg);
+}
+
// rust-ast-resolve-expr.h
void
diff --git a/gcc/rust/typecheck/rust-hir-type-check-expr.h b/gcc/rust/typecheck/rust-hir-type-check-expr.h
index daef15b..9eef755 100644
--- a/gcc/rust/typecheck/rust-hir-type-check-expr.h
+++ b/gcc/rust/typecheck/rust-hir-type-check-expr.h
@@ -265,15 +265,29 @@ public:
bool probe_impls = !receiver_is_generic;
bool ignore_mandatory_trait_items = !receiver_is_generic;
+ auto probe_type = probe_impls ? receiver_tyty : root;
auto candidates
- = PathProbeType::Probe (root, expr.get_method_name ().get_segment (),
+ = PathProbeType::Probe (probe_type,
+ expr.get_method_name ().get_segment (),
probe_impls, probe_bounds,
ignore_mandatory_trait_items);
if (candidates.empty ())
{
- rust_error_at (expr.get_locus (),
- "failed to resolve the PathExprSegment to any item");
- return;
+ if (probe_impls)
+ {
+ candidates
+ = PathProbeType::Probe (root,
+ expr.get_method_name ().get_segment (),
+ probe_impls, probe_bounds,
+ ignore_mandatory_trait_items);
+ }
+
+ if (candidates.empty ())
+ {
+ rust_error_at (expr.get_locus (),
+ "failed to resolve the PathExprSegment to any item");
+ return;
+ }
}
std::vector<Adjustment> adjustments;
@@ -295,6 +309,10 @@ public:
return;
}
+ // Get the adjusted self
+ Adjuster adj (receiver_tyty);
+ TyTy::BaseType *adjusted_self = adj.adjust_type (adjustments);
+
// store the adjustments for code-generation to know what to do
context->insert_autoderef_mappings (expr.get_mappings ().get_hirid (),
std::move (adjustments));
@@ -401,7 +419,8 @@ public:
}
TyTy::BaseType *function_ret_tyty
- = TyTy::TypeCheckMethodCallExpr::go (lookup, expr, context);
+ = TyTy::TypeCheckMethodCallExpr::go (lookup, expr, adjusted_self,
+ context);
if (function_ret_tyty == nullptr
|| function_ret_tyty->get_kind () == TyTy::TypeKind::ERROR)
{
diff --git a/gcc/rust/typecheck/rust-substitution-mapper.cc b/gcc/rust/typecheck/rust-substitution-mapper.cc
new file mode 100644
index 0000000..a439416
--- /dev/null
+++ b/gcc/rust/typecheck/rust-substitution-mapper.cc
@@ -0,0 +1,49 @@
+// Copyright (C) 2020-2021 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-substitution-mapper.h"
+#include "rust-hir-type-check.h"
+
+namespace Rust {
+namespace Resolver {
+
+TyTy::BaseType *
+SubstMapperInternal::Resolve (TyTy::BaseType *base,
+ TyTy::SubstitutionArgumentMappings &mappings)
+{
+ SubstMapperInternal mapper (base->get_ref (), mappings);
+ base->accept_vis (mapper);
+ rust_assert (mapper.resolved != nullptr);
+
+ // insert these new implict types into the context
+ bool is_fn = mapper.resolved->get_kind () == TyTy::TypeKind::FNDEF;
+ bool is_adt = mapper.resolved->get_kind () == TyTy::TypeKind::ADT;
+ bool is_param = mapper.resolved->get_kind () == TyTy::TypeKind::PARAM;
+ if (!is_fn && !is_adt && !is_param)
+ {
+ auto context = TypeCheckContext::get ();
+ context->insert_type (
+ Analysis::NodeMapping (0, 0, mapper.resolved->get_ty_ref (), 0),
+ mapper.resolved);
+ }
+
+ return mapper.resolved;
+}
+
+} // namespace Resolver
+} // namespace Rust
diff --git a/gcc/rust/typecheck/rust-substitution-mapper.h b/gcc/rust/typecheck/rust-substitution-mapper.h
index 0b3ec3b..0932038 100644
--- a/gcc/rust/typecheck/rust-substitution-mapper.h
+++ b/gcc/rust/typecheck/rust-substitution-mapper.h
@@ -154,13 +154,7 @@ class SubstMapperInternal : public TyTy::TyVisitor
{
public:
static TyTy::BaseType *Resolve (TyTy::BaseType *base,
- TyTy::SubstitutionArgumentMappings &mappings)
- {
- SubstMapperInternal mapper (base->get_ref (), mappings);
- base->accept_vis (mapper);
- rust_assert (mapper.resolved != nullptr);
- return mapper.resolved;
- }
+ TyTy::SubstitutionArgumentMappings &mappings);
void visit (TyTy::FnType &type) override
{
diff --git a/gcc/rust/typecheck/rust-tyty-call.h b/gcc/rust/typecheck/rust-tyty-call.h
index c11fd4d..3080427 100644
--- a/gcc/rust/typecheck/rust-tyty-call.h
+++ b/gcc/rust/typecheck/rust-tyty-call.h
@@ -88,9 +88,10 @@ class TypeCheckMethodCallExpr : private TyVisitor
public:
// Resolve the Method parameters and return back the return type
static BaseType *go (BaseType *ref, HIR::MethodCallExpr &call,
+ TyTy::BaseType *adjusted_self,
Resolver::TypeCheckContext *context)
{
- TypeCheckMethodCallExpr checker (call, context);
+ TypeCheckMethodCallExpr checker (call, adjusted_self, context);
ref->accept_vis (checker);
return checker.resolved;
}
@@ -125,13 +126,15 @@ public:
private:
TypeCheckMethodCallExpr (HIR::MethodCallExpr &c,
+ TyTy::BaseType *adjusted_self,
Resolver::TypeCheckContext *context)
- : resolved (nullptr), call (c), context (context),
- mappings (Analysis::Mappings::get ())
+ : resolved (nullptr), call (c), adjusted_self (adjusted_self),
+ context (context), mappings (Analysis::Mappings::get ())
{}
BaseType *resolved;
HIR::MethodCallExpr &call;
+ TyTy::BaseType *adjusted_self;
Resolver::TypeCheckContext *context;
Analysis::Mappings *mappings;
};
diff --git a/gcc/rust/typecheck/rust-tyty.cc b/gcc/rust/typecheck/rust-tyty.cc
index 378416f..add4dbe 100644
--- a/gcc/rust/typecheck/rust-tyty.cc
+++ b/gcc/rust/typecheck/rust-tyty.cc
@@ -2786,6 +2786,8 @@ TypeCheckCallExpr::visit (FnPtr &type)
void
TypeCheckMethodCallExpr::visit (FnType &type)
{
+ adjusted_self->unify (type.get_self_type ());
+
// +1 for the receiver self
size_t num_args_to_call = call.num_params () + 1;
if (num_args_to_call != type.num_params ())
diff --git a/gcc/testsuite/rust/compile/torture/issue-808.rs b/gcc/testsuite/rust/compile/torture/issue-808.rs
new file mode 100644
index 0000000..bfbf774
--- /dev/null
+++ b/gcc/testsuite/rust/compile/torture/issue-808.rs
@@ -0,0 +1,23 @@
+pub trait Foo {
+ type Target;
+ // { dg-warning "unused name" "" { target *-*-* } .-1 }
+
+ fn bar(&self) -> &Self::Target;
+ // { dg-warning "unused name .self." "" { target *-*-* } .-1 }
+ // { dg-warning "unused name .Foo::bar." "" { target *-*-* } .-2 }
+}
+
+impl<T> Foo for &T {
+ type Target = T;
+
+ fn bar(&self) -> &T {
+ *self
+ }
+}
+
+pub fn main() {
+ let a: i32 = 123;
+ let b: &i32 = &a;
+
+ b.bar();
+}