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:
parent
6e2977499b
commit
5901f1c8b5
@ -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)
|
||||
|
35
src/test/compile-fail/issue-45801.rs
Normal file
35
src/test/compile-fail/issue-45801.rs
Normal 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() {}
|
Loading…
Reference in New Issue
Block a user