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.
This commit is contained in:
Ariel Ben-Yehuda 2017-11-09 20:17:51 +02:00
parent 6e2977499b
commit 5901f1c8b5
2 changed files with 56 additions and 9 deletions

View File

@ -16,6 +16,7 @@ use hir::def_id::DefId;
use rustc::ty::subst::Substs; use rustc::ty::subst::Substs;
use rustc::traits; use rustc::traits;
use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty}; use rustc::ty::{self, LvaluePreference, NoPreference, PreferMutLvalue, Ty};
use rustc::ty::subst::Subst;
use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref}; use rustc::ty::adjustment::{Adjustment, Adjust, AutoBorrow, OverloadedDeref};
use rustc::ty::fold::TypeFoldable; use rustc::ty::fold::TypeFoldable;
use rustc::infer::{self, InferOk}; 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. // Adjust the self expression the user provided and obtain the adjusted type.
let self_ty = self.adjust_self_ty(unadjusted_self_ty, &pick); 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. // Create substitutions for the method's type parameters.
let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick); let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick);
let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs); 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. // Create the final signature for the method, replacing late-bound regions.
let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs); 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 // 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 // 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. // 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. // appropriate hint suggesting to import the trait.
let illegal_sized_bound = self.predicates_require_illegal_sized_bound(&method_predicates); 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. // 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 // We won't add these if we encountered an illegal sized bound, so that we can use
// a custom error in that case. // 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, fn instantiate_method_sig(&mut self,
pick: &probe::Pick<'tcx>, pick: &probe::Pick<'tcx>,
all_substs: &'tcx Substs<'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 def_id = pick.item.def_id;
let method_predicates = self.tcx.predicates_of(def_id) let method_predicates = self.tcx.predicates_of(def_id)
.instantiate(self.tcx, all_substs); .instantiate(self.tcx, all_substs);
let method_predicates = self.normalize_associated_types_in(self.span,
&method_predicates);
debug!("method_predicates after subst = {:?}", 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={:?}", debug!("late-bound lifetimes from method instantiated, method_sig={:?}",
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); debug!("type scheme substituted, method_sig={:?}", method_sig);
(method_sig, method_predicates) (method_sig, method_predicates)

View File

@ -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() {}