From 5901f1c8b52315f705dac1d072f438139338b195 Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Thu, 9 Nov 2017 20:17:51 +0200 Subject: [PATCH] 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. --- src/librustc_typeck/check/method/confirm.rs | 30 ++++++++++++------ src/test/compile-fail/issue-45801.rs | 35 +++++++++++++++++++++ 2 files changed, 56 insertions(+), 9 deletions(-) create mode 100644 src/test/compile-fail/issue-45801.rs 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +struct Params; + +pub trait Plugin { + type Error; +} + +pub trait Pluggable { + fn get_ref>(&mut self) -> Option { + None + } +} + +struct Foo; +impl Plugin for Params { + type Error = (); +} + +impl Pluggable for T {} + +fn handle(req: &mut i32) { + req.get_ref::(); + //~^ ERROR the trait bound `Params: Plugin` is not satisfied +} + +fn main() {}