Skip to content

Commit

Permalink
Auto merge of #45890 - arielb1:self-first, r=eddyb
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
bors committed Nov 13, 2017
2 parents aca22a8 + 5901f1c commit 8efbf7a
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 9 deletions.
30 changes: 21 additions & 9 deletions src/librustc_typeck/check/method/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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);
Expand All @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -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>)
Expand All @@ -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);

Expand All @@ -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)
Expand Down
35 changes: 35 additions & 0 deletions src/test/compile-fail/issue-45801.rs
Original file line number Diff line number Diff line change
@@ -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() {}

0 comments on commit 8efbf7a

Please sign in to comment.