From 0c39762dd620c278f1defa42394f09293e1a98b9 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Jul 2022 05:20:37 +0000 Subject: [PATCH 1/2] Use fake substs to check for `Self: Sized` predicates on method receivers --- .../rustc_typeck/src/check/method/confirm.rs | 26 +++++++------ src/test/ui/methods/issues/issue-61525.rs | 20 ++++++++++ src/test/ui/methods/issues/issue-61525.stderr | 39 +++++++++++++++++++ 3 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 src/test/ui/methods/issues/issue-61525.rs create mode 100644 src/test/ui/methods/issues/issue-61525.stderr diff --git a/compiler/rustc_typeck/src/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs index d8cdc9275f435..b14f3d6de4ef1 100644 --- a/compiler/rustc_typeck/src/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -81,11 +81,25 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { let rcvr_substs = self.fresh_receiver_substs(self_ty, &pick); let all_substs = self.instantiate_method_substs(&pick, segment, rcvr_substs); - debug!("all_substs={:?}", all_substs); + debug!("rcvr_substs={rcvr_substs:?}, all_substs={all_substs:?}"); // Create the final signature for the method, replacing late-bound regions. let (method_sig, method_predicates) = self.instantiate_method_sig(&pick, all_substs); + // 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. + // See test `src/test/ui/issue-35976.rs`. + // + // In that case, we'll error anyway, but we'll also re-run the search with all traits + // in scope, and if we find another method which can be used, we'll output an + // appropriate hint suggesting to import the trait. + let filler_substs = rcvr_substs + .extend_to(self.tcx, pick.item.def_id, |def, _| self.tcx.mk_param_from_def(def)); + let illegal_sized_bound = self.predicates_require_illegal_sized_bound( + &self.tcx.predicates_of(pick.item.def_id).instantiate(self.tcx, filler_substs), + ); + // Unify the (adjusted) self type with what the method expects. // // SUBTLE: if we want good error messages, because of "guessing" while matching @@ -106,16 +120,6 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { // 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. - // See test `src/test/ui/issue-35976.rs`. - // - // In that case, we'll error anyway, but we'll also re-run the search with all traits - // in scope, and if we find another method which can be used, we'll output an - // appropriate hint suggesting to import the trait. - let illegal_sized_bound = self.predicates_require_illegal_sized_bound(&method_predicates); - // 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. diff --git a/src/test/ui/methods/issues/issue-61525.rs b/src/test/ui/methods/issues/issue-61525.rs new file mode 100644 index 0000000000000..c5ca0326e430c --- /dev/null +++ b/src/test/ui/methods/issues/issue-61525.rs @@ -0,0 +1,20 @@ +pub trait Example { + fn query(self, q: Q); +} + +impl Example for i32 { + fn query(self, _: Q) { + unimplemented!() + } +} + +mod nested { + use super::Example; + fn example() { + 1.query::("") + //~^ ERROR the size for values of type `dyn ToString` cannot be known at compilation time + //~| ERROR mismatched types + } +} + +fn main() {} diff --git a/src/test/ui/methods/issues/issue-61525.stderr b/src/test/ui/methods/issues/issue-61525.stderr new file mode 100644 index 0000000000000..aec968d7c44f4 --- /dev/null +++ b/src/test/ui/methods/issues/issue-61525.stderr @@ -0,0 +1,39 @@ +error[E0277]: the size for values of type `dyn ToString` cannot be known at compilation time + --> $DIR/issue-61525.rs:14:33 + | +LL | 1.query::("") + | ----- ^^ doesn't have a size known at compile-time + | | + | required by a bound introduced by this call + | + = help: the trait `Sized` is not implemented for `dyn ToString` +note: required by a bound in `Example::query` + --> $DIR/issue-61525.rs:2:14 + | +LL | fn query(self, q: Q); + | ^ required by this bound in `Example::query` +help: consider relaxing the implicit `Sized` restriction + | +LL | fn query(self, q: Q); + | ++++++++ + +error[E0308]: mismatched types + --> $DIR/issue-61525.rs:14:33 + | +LL | 1.query::("") + | --------------------- ^^ expected trait object `dyn ToString`, found `&str` + | | + | arguments to this function are incorrect + | + = note: expected trait object `dyn ToString` + found reference `&'static str` +note: associated function defined here + --> $DIR/issue-61525.rs:2:8 + | +LL | fn query(self, q: Q); + | ^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. From 88f2140d8736329610a4c0bd8000e164c9170537 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 11 Jul 2022 05:21:41 +0000 Subject: [PATCH 2/2] Do not suggest same trait over again --- compiler/rustc_typeck/src/check/method/mod.rs | 5 +++-- src/test/ui/issues/issue-35976.stderr | 5 ----- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index e29f0275bf48d..c0b3a23fde437 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -20,8 +20,8 @@ use rustc_hir::def_id::DefId; use rustc_infer::infer::{self, InferOk}; use rustc_middle::ty::subst::Subst; use rustc_middle::ty::subst::{InternalSubsts, SubstsRef}; -use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::{self, ToPredicate, Ty, TypeVisitable}; +use rustc_middle::ty::{DefIdTree, GenericParamDefKind}; use rustc_span::symbol::Ident; use rustc_span::Span; use rustc_trait_selection::traits; @@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // We probe again, taking all traits into account (not only those in scope). - let candidates = match self.lookup_probe( + let mut candidates = match self.lookup_probe( span, segment.ident, self_ty, @@ -243,6 +243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .collect(), _ => Vec::new(), }; + candidates.retain(|candidate| *candidate != self.tcx.parent(result.callee.def_id)); return Err(IllegalSizedBound(candidates, needs_mut, span)); } diff --git a/src/test/ui/issues/issue-35976.stderr b/src/test/ui/issues/issue-35976.stderr index f9b9b7dbd34bb..fe16f97b9d0f5 100644 --- a/src/test/ui/issues/issue-35976.stderr +++ b/src/test/ui/issues/issue-35976.stderr @@ -6,11 +6,6 @@ LL | fn wait(&self) where Self: Sized; ... LL | arg.wait(); | ^^^^ - | -help: another candidate was found in the following trait, perhaps add a `use` for it: - | -LL | use private::Future; - | error: aborting due to previous error