about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2017-11-13 17:42:13 +0000
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2017-11-14 14:54:34 +0200
commitb23c76e1dfe9af3d427cf94f0dead6b8c8c93fc4 (patch)
tree266b204e79d0637ce96934cd8b921abc0c111fbf
parenta8d6ab7e9814b22aca64559aad07403c1175fc82 (diff)
downloadrust-b23c76e1dfe9af3d427cf94f0dead6b8c8c93fc4.tar.gz
rust-b23c76e1dfe9af3d427cf94f0dead6b8c8c93fc4.zip
Backported merge of #45890 - arielb1:self-first, r=eddyb
check::method - unify receivers before normalizing method signatures

Normalizing method signatures can unify inference variables, which can
cause receiver unification to fail. Unify the receivers first to avoid
that.

Fixes #36701.
Fixes #45801.
Fixes #45855.

r? @eddyb

beta-nominating because #43880 made this ICE happen in more cases (the code in that issue ICEs post-#43880 only, but the unit test here ICEs on all versions).
-rw-r--r--src/librustc_typeck/check/method/confirm.rs30
-rw-r--r--src/test/compile-fail/issue-45801.rs35
2 files changed, 56 insertions, 9 deletions
diff --git a/src/librustc_typeck/check/method/confirm.rs b/src/librustc_typeck/check/method/confirm.rs
index a9830dd5dde..17ed0aaa30b 100644
--- a/src/librustc_typeck/check/method/confirm.rs
+++ b/src/librustc_typeck/check/method/confirm.rs
@@ -16,6 +16,7 @@ use hir::def_id::DefId;
 use rustc::ty::subst::Substs;
 use rustc::traits;
 use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
+use rustc::ty::subst::Subst;
 use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
 use rustc::ty::fold::TypeFoldable;
 use rustc::infer::{self, InferOk};
@@ -84,9 +85,6 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // Adjust the self expression the user provided and obtain the adjusted type.
         let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick);
 
-        // Make sure nobody calls `drop()` explicitly.
-        self.enforce_illegal_method_limitations(&pick);
-
         // Create substitutions for the method's type parameters.
         let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
         let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs);
@@ -96,6 +94,22 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // Create the final signature for the method, replacing late-bound regions.
         let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs);
 
+        // Unify the (adjusted) self type with what the method expects.
+        //
+        // SUBTLE: if we want good error messages, because of "guessing" while matching
+        // traits, no trait system method can be called before this point because they
+        // could alter our Self-type, except for normalizing the receiver from the
+        // signature (which is also done during probing).
+        let method_sig_rcvr =
+            self.normalize_associated_types_in(self.span, &method_sig.inputs()[0]);
+        self.unify_receivers(self_ty, method_sig_rcvr);
+
+        let (method_sig, method_predicates) =
+            self.normalize_associated_types_in(self.span, &(method_sig, method_predicates));
+
+        // Make sure nobody calls `drop()` explicitly.
+        self.enforce_illegal_method_limitations(&pick);
+
         // If there is a `Self: Sized` bound and `Self` is a trait object, it is possible that
         // something which derefs to `Self` actually implements the trait and the caller
         // wanted to make a static dispatch on it but forgot to import the trait.
@@ -106,9 +120,6 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         // appropriate hint suggesting to import the trait.
         let illegal_sized_bound = self.predicates_require_illegal_sized_bound(&method_predicates);
 
-        // Unify the (adjusted) self type with what the method expects.
-        self.unify_receivers(self_ty, method_sig.inputs()[0]);
-
         // Add any trait/regions obligations specified on the method's type parameters.
         // We won't add these if we encountered an illegal sized bound, so that we can use
         // a custom error in that case.
@@ -338,6 +349,9 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
     ///////////////////////////////////////////////////////////////////////////
     //
 
+    // NOTE: this returns the *unnormalized* predicates and method sig. Because of
+    // inference guessing, the predicates and method signature can't be normalized
+    // until we unify the `Self` type.
     fn instantiate_method_sig(&mut self,
                               pick: &probe::Pick<'tcx>,
                               all_substs: &'tcx Substs<'tcx>)
@@ -352,8 +366,6 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         let def_id = pick.item.def_id;
         let method_predicates = self.tcx.predicates_of(def_id)
                                     .instantiate(self.tcx, all_substs);
-        let method_predicates = self.normalize_associated_types_in(self.span,
-                                                                   &method_predicates);
 
         debug!("method_predicates after subst = {:?}", method_predicates);
 
@@ -369,7 +381,7 @@ impl<'a, 'gcx, 'tcx> ConfirmContext<'a, 'gcx, 'tcx> {
         debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
                method_sig);
 
-        let method_sig = self.instantiate_type_scheme(self.span, all_substs, &method_sig);
+        let method_sig = method_sig.subst(self.tcx, all_substs);
         debug!("type scheme substituted, method_sig={:?}", method_sig);
 
         (method_sig, method_predicates)
diff --git a/src/test/compile-fail/issue-45801.rs b/src/test/compile-fail/issue-45801.rs
new file mode 100644
index 00000000000..7823a7d6ba8
--- /dev/null
+++ b/src/test/compile-fail/issue-45801.rs
@@ -0,0 +1,35 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+struct Params;
+
+pub trait Plugin<E: ?Sized> {
+    type Error;
+}
+
+pub trait Pluggable {
+    fn get_ref<P: Plugin<Self>>(&mut self) -> Option<P::Error> {
+        None
+    }
+}
+
+struct Foo;
+impl Plugin<Foo> for Params {
+    type Error = ();
+}
+
+impl<T: Copy> Pluggable for T {}
+
+fn handle(req: &mut i32) {
+    req.get_ref::<Params>();
+    //~^ ERROR the trait bound `Params: Plugin<i32>` is not satisfied
+}
+
+fn main() {}