From c13af7db21c8e7978f5d6bd462a397f5f7a29c8d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 10 Mar 2024 18:50:55 +0000 Subject: [PATCH 1/6] Some early clean-ups in method probe --- compiler/rustc_hir_typeck/src/method/probe.rs | 59 +++---------------- 1 file changed, 8 insertions(+), 51 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 2876e0b49db22..7e480d666951b 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; use rustc_middle::ty::AssocItem; use rustc_middle::ty::GenericParamDefKind; use rustc_middle::ty::ToPredicate; -use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; +use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::ty::{GenericArgs, GenericArgsRef}; use rustc_session::lint; use rustc_span::def_id::DefId; @@ -745,7 +745,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } let (impl_ty, impl_args) = self.impl_ty_and_args(impl_def_id); - let impl_ty = impl_ty.instantiate(self.tcx, impl_args); debug!("impl_ty: {:?}", impl_ty); @@ -818,7 +817,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return; } - let new_trait_ref = this.instantiate_bound_regions_with_erased(new_trait_ref); + let new_trait_ref = this.tcx.instantiate_bound_regions_with_erased(new_trait_ref); let (xform_self_ty, xform_ret_ty) = this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args); @@ -929,27 +928,12 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } } - fn matches_return_type( - &self, - method: ty::AssocItem, - self_ty: Option>, - expected: Ty<'tcx>, - ) -> bool { + fn matches_return_type(&self, method: ty::AssocItem, expected: Ty<'tcx>) -> bool { match method.kind { ty::AssocKind::Fn => self.probe(|_| { let args = self.fresh_args_for_item(self.span, method.def_id); let fty = self.tcx.fn_sig(method.def_id).instantiate(self.tcx, args); let fty = self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, fty); - - if let Some(self_ty) = self_ty { - if self - .at(&ObligationCause::dummy(), self.param_env) - .sup(DefineOpaqueTypes::No, fty.inputs()[0], self_ty) - .is_err() - { - return false; - } - } self.can_sub(self.param_env, fty.output(), expected) }), _ => false, @@ -1040,7 +1024,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .filter(|candidate| candidate_filter(&candidate.item)) .filter(|candidate| { if let Some(return_ty) = self.return_type { - self.matches_return_type(candidate.item, None, return_ty) + self.matches_return_type(candidate.item, return_ty) } else { true } @@ -1894,40 +1878,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn_sig.instantiate(self.tcx, args) }; - self.instantiate_bound_regions_with_erased(xform_fn_sig) + self.tcx.instantiate_bound_regions_with_erased(xform_fn_sig) } /// Gets the type of an impl and generate generic parameters with inference vars. - fn impl_ty_and_args( - &self, - impl_def_id: DefId, - ) -> (ty::EarlyBinder>, GenericArgsRef<'tcx>) { - (self.tcx.type_of(impl_def_id), self.fresh_args_for_item(self.span, impl_def_id)) - } - - /// Replaces late-bound-regions bound by `value` with `'static` using - /// `ty::instantiate_bound_regions_with_erased`. - /// - /// This is only a reasonable thing to do during the *probe* phase, not the *confirm* phase, of - /// method matching. It is reasonable during the probe phase because we don't consider region - /// relationships at all. Therefore, we can just replace all the region variables with 'static - /// rather than creating fresh region variables. This is nice for two reasons: - /// - /// 1. Because the numbers of the region variables would otherwise be fairly unique to this - /// particular method call, it winds up creating fewer types overall, which helps for memory - /// usage. (Admittedly, this is a rather small effect, though measurable.) - /// - /// 2. It makes it easier to deal with higher-ranked trait bounds, because we can replace any - /// late-bound regions with 'static. Otherwise, if we were going to replace late-bound - /// regions with actual region variables as is proper, we'd have to ensure that the same - /// region got replaced with the same variable, which requires a bit more coordination - /// and/or tracking the instantiations and - /// so forth. - fn instantiate_bound_regions_with_erased(&self, value: ty::Binder<'tcx, T>) -> T - where - T: TypeFoldable>, - { - self.tcx.instantiate_bound_regions_with_erased(value) + fn impl_ty_and_args(&self, impl_def_id: DefId) -> (Ty<'tcx>, GenericArgsRef<'tcx>) { + let args = self.fresh_args_for_item(self.span, impl_def_id); + (self.tcx.type_of(impl_def_id).instantiate(self.tcx, args), args) } /// Determine if the given associated item type is relevant in the current context. From ff4653a08f0c9dad1db927727e102c51f0ea39b2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 10 Mar 2024 19:43:20 -0400 Subject: [PATCH 2/6] Use fulfillment, not evaluate, during method probe --- compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/method/probe.rs | 431 ++++++------------ .../src/traits/engine.rs | 13 + tests/ui/derives/issue-91550.stderr | 27 +- tests/ui/impl-trait/issues/issue-62742.rs | 2 +- tests/ui/impl-trait/issues/issue-62742.stderr | 50 +- tests/ui/impl-trait/issues/issue-84073.rs | 3 +- tests/ui/impl-trait/issues/issue-84073.stderr | 28 +- .../option-as_deref.stderr | 1 + .../option-as_deref_mut.stderr | 1 + .../result-as_deref.stderr | 1 + .../result-as_deref_mut.stderr | 1 + .../fulfillment-disqualifies-method.rs | 32 ++ tests/ui/methods/leak-check-disquality.rs | 26 ++ .../ui/mismatched_types/issue-36053-2.stderr | 10 +- .../missing-trait-bounds/issue-35677.stderr | 2 - tests/ui/nll/issue-57362-2.rs | 3 +- tests/ui/nll/issue-57362-2.stderr | 6 +- .../nll/issue-57642-higher-ranked-subtype.rs | 3 +- .../issue-57642-higher-ranked-subtype.stderr | 8 +- tests/ui/resolve/issue-85671.rs | 3 +- tests/ui/resolve/issue-85671.stderr | 17 + .../derive-trait-for-method-call.stderr | 24 +- ...t-trait-alias-bound-on-generic-impl.stderr | 7 - .../method-on-unbounded-type-param.stderr | 2 +- tests/ui/traits/track-obligations.stderr | 30 +- tests/ui/typeck/issue-31173.stderr | 2 +- 27 files changed, 328 insertions(+), 407 deletions(-) create mode 100644 tests/ui/methods/fulfillment-disqualifies-method.rs create mode 100644 tests/ui/methods/leak-check-disquality.rs create mode 100644 tests/ui/resolve/issue-85671.stderr diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index d6d22a43fe0b8..618d90a07ec29 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -889,7 +889,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { [candidate] => format!( "the method of the same name on {} `{}`", match candidate.kind { - probe::CandidateKind::InherentImplCandidate(..) => "the inherent impl for", + probe::CandidateKind::InherentImplCandidate(_) => "the inherent impl for", _ => "trait", }, self.tcx.def_path_str(candidate.item.container_id(self.tcx)) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 7e480d666951b..c31b54c642db2 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -31,13 +31,12 @@ use rustc_span::edit_distance::{ }; use rustc_span::symbol::sym; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; use rustc_trait_selection::traits::query::method_autoderef::{ CandidateStep, MethodAutoderefStepsResult, }; use rustc_trait_selection::traits::query::CanonicalTyGoal; -use rustc_trait_selection::traits::NormalizeExt; +use rustc_trait_selection::traits::ObligationCtxt; use rustc_trait_selection::traits::{self, ObligationCause}; use std::cell::RefCell; use std::cmp::max; @@ -99,39 +98,6 @@ impl<'a, 'tcx> Deref for ProbeContext<'a, 'tcx> { #[derive(Debug, Clone)] pub(crate) struct Candidate<'tcx> { - // Candidates are (I'm not quite sure, but they are mostly) basically - // some metadata on top of a `ty::AssocItem` (without args). - // - // However, method probing wants to be able to evaluate the predicates - // for a function with the args applied - for example, if a function - // has `where Self: Sized`, we don't want to consider it unless `Self` - // is actually `Sized`, and similarly, return-type suggestions want - // to consider the "actual" return type. - // - // The way this is handled is through `xform_self_ty`. It contains - // the receiver type of this candidate, but `xform_self_ty`, - // `xform_ret_ty` and `kind` (which contains the predicates) have the - // generic parameters of this candidate instantiated with the *same set* - // of inference variables, which acts as some weird sort of "query". - // - // When we check out a candidate, we require `xform_self_ty` to be - // a subtype of the passed-in self-type, and this equates the type - // variables in the rest of the fields. - // - // For example, if we have this candidate: - // ``` - // trait Foo { - // fn foo(&self) where Self: Sized; - // } - // ``` - // - // Then `xform_self_ty` will be `&'erased ?X` and `kind` will contain - // the predicate `?X: Sized`, so if we are evaluating `Foo` for a - // the receiver `&T`, we'll do the subtyping which will make `?X` - // get the right value, then when we evaluate the predicate we'll check - // if `T: Sized`. - xform_self_ty: Ty<'tcx>, - xform_ret_ty: Option>, pub(crate) item: ty::AssocItem, pub(crate) kind: CandidateKind<'tcx>, pub(crate) import_ids: SmallVec<[LocalDefId; 1]>, @@ -139,17 +105,10 @@ pub(crate) struct Candidate<'tcx> { #[derive(Debug, Clone)] pub(crate) enum CandidateKind<'tcx> { - InherentImplCandidate( - GenericArgsRef<'tcx>, - // Normalize obligations - Vec>, - ), - ObjectCandidate, - TraitCandidate(ty::TraitRef<'tcx>), - WhereClauseCandidate( - // Trait - ty::PolyTraitRef<'tcx>, - ), + InherentImplCandidate(DefId), + ObjectCandidate(ty::PolyTraitRef<'tcx>), + TraitCandidate(ty::PolyTraitRef<'tcx>), + WhereClauseCandidate(ty::PolyTraitRef<'tcx>), } #[derive(Debug, PartialEq, Eq, Copy, Clone)] @@ -743,41 +702,10 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.record_static_candidate(CandidateSource::Impl(impl_def_id)); continue; } - - let (impl_ty, impl_args) = self.impl_ty_and_args(impl_def_id); - - debug!("impl_ty: {:?}", impl_ty); - - // Determine the receiver type that the method itself expects. - let (xform_self_ty, xform_ret_ty) = self.xform_self_ty(item, impl_ty, impl_args); - debug!("xform_self_ty: {:?}, xform_ret_ty: {:?}", xform_self_ty, xform_ret_ty); - - // We can't use `FnCtxt::normalize` as it will pollute the - // fcx's fulfillment context after this probe is over. - // - // Note: we only normalize `xform_self_ty` here since the normalization - // of the return type can lead to inference results that prohibit - // valid candidates from being found, see issue #85671 - // - // FIXME Postponing the normalization of the return type likely only hides a deeper bug, - // which might be caused by the `param_env` itself. The clauses of the `param_env` - // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized, - // see issue #89650 - let cause = traits::ObligationCause::misc(self.span, self.body_id); - let InferOk { value: xform_self_ty, obligations } = - self.fcx.at(&cause, self.param_env).normalize(xform_self_ty); - - debug!( - "assemble_inherent_impl_probe after normalization: xform_self_ty = {:?}/{:?}", - xform_self_ty, xform_ret_ty - ); - self.push_candidate( Candidate { - xform_self_ty, - xform_ret_ty, item, - kind: InherentImplCandidate(impl_args, obligations), + kind: InherentImplCandidate(impl_def_id), import_ids: smallvec![], }, true, @@ -809,26 +737,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // a `&self` method will wind up with an argument type like `&dyn Trait`. let trait_ref = principal.with_self_ty(self.tcx, self_ty); self.elaborate_bounds(iter::once(trait_ref), |this, new_trait_ref, item| { - if new_trait_ref.has_non_region_bound_vars() { - this.dcx().span_delayed_bug( - this.span, - "tried to select method from HRTB with non-lifetime bound vars", - ); - return; - } - - let new_trait_ref = this.tcx.instantiate_bound_regions_with_erased(new_trait_ref); - - let (xform_self_ty, xform_ret_ty) = - this.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args); this.push_candidate( - Candidate { - xform_self_ty, - xform_ret_ty, - item, - kind: ObjectCandidate, - import_ids: smallvec![], - }, + Candidate { item, kind: ObjectCandidate(new_trait_ref), import_ids: smallvec![] }, true, ); }); @@ -859,19 +769,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }); self.elaborate_bounds(bounds, |this, poly_trait_ref, item| { - let trait_ref = this.instantiate_binder_with_fresh_vars( - this.span, - infer::BoundRegionConversionTime::FnCall, - poly_trait_ref, - ); - - let (xform_self_ty, xform_ret_ty) = - this.xform_self_ty(item, trait_ref.self_ty(), trait_ref.args); - this.push_candidate( Candidate { - xform_self_ty, - xform_ret_ty, item, kind: WhereClauseCandidate(poly_trait_ref), import_ids: smallvec![], @@ -962,21 +861,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { bound_trait_ref.def_id(), )); } else { - let new_trait_ref = self.instantiate_binder_with_fresh_vars( - self.span, - infer::BoundRegionConversionTime::FnCall, - bound_trait_ref, - ); - - let (xform_self_ty, xform_ret_ty) = - self.xform_self_ty(item, new_trait_ref.self_ty(), new_trait_ref.args); self.push_candidate( Candidate { - xform_self_ty, - xform_ret_ty, item, import_ids: import_ids.clone(), - kind: TraitCandidate(new_trait_ref), + kind: TraitCandidate(bound_trait_ref), }, false, ); @@ -995,16 +884,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.record_static_candidate(CandidateSource::Trait(trait_def_id)); continue; } - - let (xform_self_ty, xform_ret_ty) = - self.xform_self_ty(item, trait_ref.self_ty(), trait_args); self.push_candidate( Candidate { - xform_self_ty, - xform_ret_ty, item, import_ids: import_ids.clone(), - kind: TraitCandidate(trait_ref), + kind: TraitCandidate(ty::Binder::dummy(trait_ref)), }, false, ); @@ -1434,16 +1318,20 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn candidate_source(&self, candidate: &Candidate<'tcx>, self_ty: Ty<'tcx>) -> CandidateSource { match candidate.kind { - InherentImplCandidate(..) => { + InherentImplCandidate(_) => { CandidateSource::Impl(candidate.item.container_id(self.tcx)) } - ObjectCandidate | WhereClauseCandidate(_) => { + ObjectCandidate(_) | WhereClauseCandidate(_) => { CandidateSource::Trait(candidate.item.container_id(self.tcx)) } TraitCandidate(trait_ref) => self.probe(|_| { + let trait_ref = + self.instantiate_binder_with_fresh_vars(self.span, infer::FnCall, trait_ref); + let (xform_self_ty, _) = + self.xform_self_ty(candidate.item, trait_ref.self_ty(), trait_ref.args); let _ = self.at(&ObligationCause::dummy(), self.param_env).sup( DefineOpaqueTypes::No, - candidate.xform_self_ty, + xform_self_ty, self_ty, ); match self.select_trait_candidate(trait_ref) { @@ -1470,54 +1358,39 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ) -> ProbeResult { debug!("consider_probe: self_ty={:?} probe={:?}", self_ty, probe); - self.probe(|_| { - // First check that the self type can be related. - let sub_obligations = match self.at(&ObligationCause::dummy(), self.param_env).sup( - DefineOpaqueTypes::No, - probe.xform_self_ty, - self_ty, - ) { - Ok(InferOk { obligations, value: () }) => obligations, - Err(err) => { - debug!("--> cannot relate self-types {:?}", err); - return ProbeResult::NoMatch; - } - }; + self.probe(|snapshot| { + let outer_universe = self.universe(); let mut result = ProbeResult::Match; - let mut xform_ret_ty = probe.xform_ret_ty; - debug!(?xform_ret_ty); - - let cause = traits::ObligationCause::misc(self.span, self.body_id); + let cause = &self.misc(self.span); + let ocx = ObligationCtxt::new(self); - let mut parent_pred = None; + let mut trait_predicate = None; + let (mut xform_self_ty, mut xform_ret_ty); - // If so, impls may carry other conditions (e.g., where - // clauses) that must be considered. Make sure that those - // match as well (or at least may match, sometimes we - // don't have enough information to fully evaluate). match probe.kind { - InherentImplCandidate(args, ref ref_obligations) => { - // `xform_ret_ty` hasn't been normalized yet, only `xform_self_ty`, - // see the reasons mentioned in the comments in `assemble_inherent_impl_probe` - // for why this is necessary - let InferOk { - value: normalized_xform_ret_ty, - obligations: normalization_obligations, - } = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty); - xform_ret_ty = normalized_xform_ret_ty; - debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty); - + InherentImplCandidate(impl_def_id) => { + let impl_args = self.fresh_args_for_item(self.span, impl_def_id); + let impl_ty = self.tcx.type_of(impl_def_id).instantiate(self.tcx, impl_args); + (xform_self_ty, xform_ret_ty) = + self.xform_self_ty(probe.item, impl_ty, impl_args); + xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); + // FIXME: Weirdly, we normalize the ret ty in this candidate, but no other candidates. + xform_ret_ty = ocx.normalize(cause, self.param_env, xform_ret_ty); + match ocx.eq_no_opaques(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} + Err(err) => { + debug!("--> cannot relate self-types {:?}", err); + return ProbeResult::NoMatch; + } + } // Check whether the impl imposes obligations we have to worry about. let impl_def_id = probe.item.container_id(self.tcx); - let impl_bounds = self.tcx.predicates_of(impl_def_id); - let impl_bounds = impl_bounds.instantiate(self.tcx, args); - - let InferOk { value: impl_bounds, obligations: norm_obligations } = - self.fcx.at(&cause, self.param_env).normalize(impl_bounds); - + let impl_bounds = + self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_args); + let impl_bounds = ocx.normalize(cause, self.param_env, impl_bounds); // Convert the bounds into obligations. - let impl_obligations = traits::predicates_for_generics( + ocx.register_obligations(traits::predicates_for_generics( |idx, span| { let code = if span.is_dummy() { traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx) @@ -1533,106 +1406,56 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { }, self.param_env, impl_bounds, - ); - - let candidate_obligations = impl_obligations - .chain(norm_obligations) - .chain(ref_obligations.iter().cloned()) - .chain(normalization_obligations); - - // Evaluate those obligations to see if they might possibly hold. - for o in candidate_obligations { - let o = self.resolve_vars_if_possible(o); - if !self.predicate_may_hold(&o) { - result = ProbeResult::NoMatch; - let parent_o = o.clone(); - let implied_obligations = traits::elaborate(self.tcx, vec![o]); - for o in implied_obligations { - let parent = if o == parent_o { - None - } else { - if o.predicate.to_opt_poly_trait_pred().map(|p| p.def_id()) - == self.tcx.lang_items().sized_trait() - { - // We don't care to talk about implicit `Sized` bounds. - continue; - } - Some(parent_o.predicate) - }; - if !self.predicate_may_hold(&o) { - possibly_unsatisfied_predicates.push(( - o.predicate, - parent, - Some(o.cause), - )); - } - } - } - } - } - - ObjectCandidate | WhereClauseCandidate(..) => { - // These have no additional conditions to check. + )); } - - TraitCandidate(trait_ref) => { + TraitCandidate(poly_trait_ref) => { + // Some trait methods are excluded for arrays before 2021. + // (`array.into_iter()` wants a slice iterator for compatibility.) if let Some(method_name) = self.method_name { - // Some trait methods are excluded for arrays before 2021. - // (`array.into_iter()` wants a slice iterator for compatibility.) if self_ty.is_array() && !method_name.span.at_least_rust_2021() { - let trait_def = self.tcx.trait_def(trait_ref.def_id); + let trait_def = self.tcx.trait_def(poly_trait_ref.def_id()); if trait_def.skip_array_during_method_dispatch { return ProbeResult::NoMatch; } } } - let predicate = ty::Binder::dummy(trait_ref).to_predicate(self.tcx); - parent_pred = Some(predicate); - let obligation = - traits::Obligation::new(self.tcx, cause.clone(), self.param_env, predicate); - if !self.predicate_may_hold(&obligation) { - result = ProbeResult::NoMatch; - if self.probe(|_| { - match self.select_trait_candidate(trait_ref) { - Err(_) => return true, - Ok(Some(impl_source)) - if !impl_source.borrow_nested_obligations().is_empty() => - { - for obligation in impl_source.borrow_nested_obligations() { - // Determine exactly which obligation wasn't met, so - // that we can give more context in the error. - if !self.predicate_may_hold(obligation) { - let nested_predicate = - self.resolve_vars_if_possible(obligation.predicate); - let predicate = - self.resolve_vars_if_possible(predicate); - let p = if predicate == nested_predicate { - // Avoid "`MyStruct: Foo` which is required by - // `MyStruct: Foo`" in E0599. - None - } else { - Some(predicate) - }; - possibly_unsatisfied_predicates.push(( - nested_predicate, - p, - Some(obligation.cause.clone()), - )); - } - } - } - _ => { - // Some nested subobligation of this predicate - // failed. - let predicate = self.resolve_vars_if_possible(predicate); - possibly_unsatisfied_predicates.push((predicate, None, None)); - } - } - false - }) { - // This candidate's primary obligation doesn't even - // select - don't bother registering anything in - // `potentially_unsatisfied_predicates`. + + let trait_ref = self.instantiate_binder_with_fresh_vars( + self.span, + infer::FnCall, + poly_trait_ref, + ); + (xform_self_ty, xform_ret_ty) = + self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); + xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); + match ocx.eq_no_opaques(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} + Err(err) => { + debug!("--> cannot relate self-types {:?}", err); + return ProbeResult::NoMatch; + } + } + ocx.register_obligation(traits::Obligation::new( + self.tcx, + cause.clone(), + self.param_env, + ty::Binder::dummy(trait_ref), + )); + trait_predicate = Some(ty::Binder::dummy(trait_ref).to_predicate(self.tcx)); + } + ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => { + let trait_ref = self.instantiate_binder_with_fresh_vars( + self.span, + infer::FnCall, + poly_trait_ref, + ); + (xform_self_ty, xform_ret_ty) = + self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); + xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); + match ocx.eq_no_opaques(cause, self.param_env, xform_self_ty, self_ty) { + Ok(()) => {} + Err(err) => { + debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; } } @@ -1640,11 +1463,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } // Evaluate those obligations to see if they might possibly hold. - for o in sub_obligations { - let o = self.resolve_vars_if_possible(o); - if !self.predicate_may_hold(&o) { - result = ProbeResult::NoMatch; - possibly_unsatisfied_predicates.push((o.predicate, parent_pred, Some(o.cause))); + for error in ocx.select_where_possible() { + result = ProbeResult::NoMatch; + let nested_predicate = self.resolve_vars_if_possible(error.obligation.predicate); + if let Some(trait_predicate) = trait_predicate + && nested_predicate == self.resolve_vars_if_possible(trait_predicate) + { + // Don't report possibly unsatisfied predicates if the root + // trait obligation from a `TraitCandidate` is unsatisfied. + // That just means the candidate doesn't hold. + } else { + possibly_unsatisfied_predicates.push(( + nested_predicate, + Some(self.resolve_vars_if_possible(error.root_obligation.predicate)) + .filter(|root_predicate| *root_predicate != nested_predicate), + Some(error.obligation.cause), + )); } } @@ -1656,38 +1490,39 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // We don't normalize the other candidates for perf/backwards-compat reasons... // but `self.return_type` is only set on the diagnostic-path, so we // should be okay doing it here. - if !matches!(probe.kind, InherentImplCandidate(..)) { - let InferOk { - value: normalized_xform_ret_ty, - obligations: normalization_obligations, - } = self.fcx.at(&cause, self.param_env).normalize(xform_ret_ty); - xform_ret_ty = normalized_xform_ret_ty; - debug!("xform_ret_ty after normalization: {:?}", xform_ret_ty); - // Evaluate those obligations to see if they might possibly hold. - for o in normalization_obligations { - let o = self.resolve_vars_if_possible(o); - if !self.predicate_may_hold(&o) { - result = ProbeResult::NoMatch; - possibly_unsatisfied_predicates.push(( - o.predicate, - None, - Some(o.cause), - )); - } - } + if !matches!(probe.kind, InherentImplCandidate(_)) { + xform_ret_ty = ocx.normalize(&cause, self.param_env, xform_ret_ty); } debug!("comparing return_ty {:?} with xform ret ty {:?}", return_ty, xform_ret_ty); - if let ProbeResult::Match = result - && self - .at(&ObligationCause::dummy(), self.param_env) - .sup(DefineOpaqueTypes::Yes, return_ty, xform_ret_ty) - .is_err() - { - result = ProbeResult::BadReturnType; + match ocx.sup(cause, self.param_env, return_ty, xform_ret_ty) { + Ok(()) => {} + Err(_) => { + result = ProbeResult::BadReturnType; + } + } + + // Evaluate those obligations to see if they might possibly hold. + for error in ocx.select_where_possible() { + result = ProbeResult::NoMatch; + possibly_unsatisfied_predicates.push(( + error.obligation.predicate, + Some(error.root_obligation.predicate) + .filter(|predicate| *predicate != error.obligation.predicate), + Some(error.root_obligation.cause), + )); } } + // Previously, method probe used `evaluate_predicate` to determine if a predicate + // was impossible to satisfy. This did a leak check, so we must also do a leak + // check here to prevent backwards-incompatible ambiguity being introduced. See + // `tests/ui/methods/leak-check-disquality.rs` for a simple example of when this + // may happen. + if let Err(_) = self.leak_check(outer_universe, Some(snapshot)) { + result = ProbeResult::NoMatch; + } + result }) } @@ -1881,12 +1716,6 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.tcx.instantiate_bound_regions_with_erased(xform_fn_sig) } - /// Gets the type of an impl and generate generic parameters with inference vars. - fn impl_ty_and_args(&self, impl_def_id: DefId) -> (Ty<'tcx>, GenericArgsRef<'tcx>) { - let args = self.fresh_args_for_item(self.span, impl_def_id); - (self.tcx.type_of(impl_def_id).instantiate(self.tcx, args), args) - } - /// Determine if the given associated item type is relevant in the current context. fn is_relevant_kind_for_mode(&self, kind: ty::AssocKind) -> bool { match (self.mode, kind) { @@ -2008,10 +1837,10 @@ impl<'tcx> Candidate<'tcx> { Pick { item: self.item, kind: match self.kind { - InherentImplCandidate(..) => InherentImplPick, - ObjectCandidate => ObjectPick, + InherentImplCandidate(_) => InherentImplPick, + ObjectCandidate(_) => ObjectPick, TraitCandidate(_) => TraitPick, - WhereClauseCandidate(ref trait_ref) => { + WhereClauseCandidate(trait_ref) => { // Only trait derived from where-clauses should // appear here, so they should not contain any // inference variables or other artifacts. This @@ -2022,7 +1851,7 @@ impl<'tcx> Candidate<'tcx> { && !trait_ref.skip_binder().args.has_placeholders() ); - WhereClausePick(*trait_ref) + WhereClausePick(trait_ref) } }, import_ids: self.import_ids.clone(), diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 9fbec174ce8d2..68c76dcf29734 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -129,6 +129,19 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } + pub fn eq_no_opaques>( + &self, + cause: &ObligationCause<'tcx>, + param_env: ty::ParamEnv<'tcx>, + expected: T, + actual: T, + ) -> Result<(), TypeError<'tcx>> { + self.infcx + .at(cause, param_env) + .eq(DefineOpaqueTypes::No, expected, actual) + .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) + } + /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. pub fn sub>( &self, diff --git a/tests/ui/derives/issue-91550.stderr b/tests/ui/derives/issue-91550.stderr index 9e17189671827..4d637c9728385 100644 --- a/tests/ui/derives/issue-91550.stderr +++ b/tests/ui/derives/issue-91550.stderr @@ -2,15 +2,13 @@ error[E0599]: the method `insert` exists for struct `HashSet`, but its tr --> $DIR/issue-91550.rs:8:8 | LL | struct Value(u32); - | ------------ doesn't satisfy `Value: Eq`, `Value: Hash` or `Value: PartialEq` + | ------------ doesn't satisfy `Value: Eq` or `Value: Hash` ... LL | hs.insert(Value(0)); | ^^^^^^ | = note: the following trait bounds were not satisfied: `Value: Eq` - `Value: PartialEq` - which is required by `Value: Eq` `Value: Hash` help: consider annotating `Value` with `#[derive(Eq, Hash, PartialEq)]` | @@ -22,7 +20,7 @@ error[E0599]: the method `use_eq` exists for struct `Object`, but its --> $DIR/issue-91550.rs:26:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Eq` or `NoDerives: PartialEq` + | -------------------- doesn't satisfy `NoDerives: Eq` LL | LL | struct Object(T); | ---------------- method `use_eq` not found for this struct @@ -37,9 +35,6 @@ LL | impl Object { | ^^ --------- | | | unsatisfied trait bound introduced here - = note: the following trait bounds were not satisfied: - `NoDerives: PartialEq` - which is required by `NoDerives: Eq` help: consider annotating `NoDerives` with `#[derive(Eq, PartialEq)]` | LL + #[derive(Eq, PartialEq)] @@ -50,7 +45,7 @@ error[E0599]: the method `use_ord` exists for struct `Object`, but it --> $DIR/issue-91550.rs:27:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd` + | -------------------- doesn't satisfy `NoDerives: Ord` LL | LL | struct Object(T); | ---------------- method `use_ord` not found for this struct @@ -65,13 +60,6 @@ LL | impl Object { | ^^^ --------- | | | unsatisfied trait bound introduced here - = note: the following trait bounds were not satisfied: - `NoDerives: PartialOrd` - which is required by `NoDerives: Ord` - `NoDerives: PartialEq` - which is required by `NoDerives: Ord` - `NoDerives: Eq` - which is required by `NoDerives: Ord` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | LL + #[derive(Eq, Ord, PartialEq, PartialOrd)] @@ -82,7 +70,7 @@ error[E0599]: the method `use_ord_and_partial_ord` exists for struct `Object $DIR/issue-91550.rs:28:9 | LL | pub struct NoDerives; - | -------------------- doesn't satisfy `NoDerives: Eq`, `NoDerives: Ord`, `NoDerives: PartialEq` or `NoDerives: PartialOrd` + | -------------------- doesn't satisfy `NoDerives: Ord` or `NoDerives: PartialOrd` LL | LL | struct Object(T); | ---------------- method `use_ord_and_partial_ord` not found for this struct @@ -100,13 +88,6 @@ LL | impl Object { | | | | | unsatisfied trait bound introduced here | unsatisfied trait bound introduced here - = note: the following trait bounds were not satisfied: - `NoDerives: PartialEq` - which is required by `NoDerives: Ord` - `NoDerives: Eq` - which is required by `NoDerives: Ord` - `NoDerives: PartialEq` - which is required by `NoDerives: PartialOrd` help: consider annotating `NoDerives` with `#[derive(Eq, Ord, PartialEq, PartialOrd)]` | LL + #[derive(Eq, Ord, PartialEq, PartialOrd)] diff --git a/tests/ui/impl-trait/issues/issue-62742.rs b/tests/ui/impl-trait/issues/issue-62742.rs index 11a75737e5545..bd48c51c06546 100644 --- a/tests/ui/impl-trait/issues/issue-62742.rs +++ b/tests/ui/impl-trait/issues/issue-62742.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; fn _alias_check() { WrongImpl::foo(0i32); //~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied - //~| ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied + //~| ERROR the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied WrongImpl::<()>::foo(0i32); //~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied //~| ERROR trait bounds were not satisfied diff --git a/tests/ui/impl-trait/issues/issue-62742.stderr b/tests/ui/impl-trait/issues/issue-62742.stderr index 9ec581c231b7b..f6798f55a472c 100644 --- a/tests/ui/impl-trait/issues/issue-62742.stderr +++ b/tests/ui/impl-trait/issues/issue-62742.stderr @@ -1,30 +1,27 @@ -error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied - --> $DIR/issue-62742.rs:4:5 +error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied + --> $DIR/issue-62742.rs:4:16 | LL | WrongImpl::foo(0i32); - | ^^^^^^^^^^^^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` + | ^^^ function or associated item cannot be called on `SafeImpl<_, RawImpl<_>>` due to unsatisfied trait bounds +... +LL | pub struct RawImpl(PhantomData); + | --------------------- doesn't satisfy `RawImpl<_>: Raw<_>` +... +LL | pub struct SafeImpl>(PhantomData<(A, T)>); + | ----------------------------------------- function or associated item `foo` not found for this struct | - = help: the trait `Raw<[_]>` is implemented for `RawImpl<_>` -note: required by a bound in `SafeImpl::::foo` +note: trait bound `RawImpl<_>: Raw<_>` was not satisfied --> $DIR/issue-62742.rs:29:20 | LL | impl> SafeImpl { - | ^^^^^^ required by this bound in `SafeImpl::::foo` -LL | pub fn foo(value: A::Value) {} - | --- required by a bound in this associated function - -error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied - --> $DIR/issue-62742.rs:4:5 - | -LL | WrongImpl::foo(0i32); - | ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` - | - = help: the trait `Raw<[_]>` is implemented for `RawImpl<_>` -note: required by a bound in `SafeImpl` - --> $DIR/issue-62742.rs:27:35 + | ^^^^^^ -------------- + | | + | unsatisfied trait bound introduced here +note: the trait `Raw` must be implemented + --> $DIR/issue-62742.rs:13:1 | -LL | pub struct SafeImpl>(PhantomData<(A, T)>); - | ^^^^^^ required by this bound in `SafeImpl` +LL | pub trait Raw { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied --> $DIR/issue-62742.rs:7:22 @@ -51,6 +48,19 @@ note: the trait `Raw` must be implemented LL | pub trait Raw { | ^^^^^^^^^^^^^^^^^^^^^^^^ +error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied + --> $DIR/issue-62742.rs:4:5 + | +LL | WrongImpl::foo(0i32); + | ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` + | + = help: the trait `Raw<[_]>` is implemented for `RawImpl<_>` +note: required by a bound in `SafeImpl` + --> $DIR/issue-62742.rs:27:35 + | +LL | pub struct SafeImpl>(PhantomData<(A, T)>); + | ^^^^^^ required by this bound in `SafeImpl` + error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied --> $DIR/issue-62742.rs:7:5 | diff --git a/tests/ui/impl-trait/issues/issue-84073.rs b/tests/ui/impl-trait/issues/issue-84073.rs index 85d9d461fd9ad..f2f1835dc344e 100644 --- a/tests/ui/impl-trait/issues/issue-84073.rs +++ b/tests/ui/impl-trait/issues/issue-84073.rs @@ -29,5 +29,6 @@ where } fn main() { - Race::new(|race| race.when()); //~ ERROR overflow assigning `_` to `Option<_>` + Race::new(|race| race.when()); + //~^ ERROR the method `when` exists for struct `RaceBuilder<_, Never<_>>`, but its trait bounds were not satisfied } diff --git a/tests/ui/impl-trait/issues/issue-84073.stderr b/tests/ui/impl-trait/issues/issue-84073.stderr index ab119a8a4f456..eeb23b130819d 100644 --- a/tests/ui/impl-trait/issues/issue-84073.stderr +++ b/tests/ui/impl-trait/issues/issue-84073.stderr @@ -1,9 +1,29 @@ -error[E0275]: overflow assigning `_` to `Option<_>` - --> $DIR/issue-84073.rs:32:22 +error[E0599]: the method `when` exists for struct `RaceBuilder<_, Never<_>>`, but its trait bounds were not satisfied + --> $DIR/issue-84073.rs:32:27 | +LL | pub struct Never(PhantomData); + | ------------------- doesn't satisfy `Never<_>: StatefulFuture>` +... +LL | pub struct RaceBuilder { + | ---------------------------- method `when` not found for this struct +... LL | Race::new(|race| race.when()); - | ^^^^ + | ^^^^ method cannot be called on `RaceBuilder<_, Never<_>>` due to unsatisfied trait bounds + | +note: trait bound `Never<_>: StatefulFuture>` was not satisfied + --> $DIR/issue-84073.rs:14:8 + | +LL | impl RaceBuilder + | ----------------- +LL | where +LL | F: StatefulFuture>, + | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here +note: the trait `StatefulFuture` must be implemented + --> $DIR/issue-84073.rs:3:1 + | +LL | pub trait StatefulFuture {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0275`. +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr b/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr index 84247a4270484..0468e0522d1e7 100644 --- a/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr +++ b/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr @@ -6,6 +6,7 @@ LL | let _result = &Some(42).as_deref(); | = note: the following trait bounds were not satisfied: `{integer}: Deref` + which is required by `<{integer} as Deref>::Target = _` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr b/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr index bf05ab5665cba..cf4e866901cd9 100644 --- a/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr +++ b/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr @@ -6,6 +6,7 @@ LL | let _result = &mut Some(42).as_deref_mut(); | = note: the following trait bounds were not satisfied: `{integer}: Deref` + which is required by `<{integer} as Deref>::Target = _` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr b/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr index ac744a6d3b672..0e3e7999044fc 100644 --- a/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr +++ b/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr @@ -6,6 +6,7 @@ LL | let _result = &Ok(42).as_deref(); | = note: the following trait bounds were not satisfied: `{integer}: Deref` + which is required by `<{integer} as Deref>::Target = _` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr b/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr index 688d2cf3486e8..43143db0da742 100644 --- a/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr +++ b/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr @@ -6,6 +6,7 @@ LL | let _result = &mut Ok(42).as_deref_mut(); | = note: the following trait bounds were not satisfied: `{integer}: Deref` + which is required by `<{integer} as Deref>::Target = _` error: aborting due to 1 previous error diff --git a/tests/ui/methods/fulfillment-disqualifies-method.rs b/tests/ui/methods/fulfillment-disqualifies-method.rs new file mode 100644 index 0000000000000..639e1c7fc5c02 --- /dev/null +++ b/tests/ui/methods/fulfillment-disqualifies-method.rs @@ -0,0 +1,32 @@ +// Tests that using fulfillment in the trait solver means that we detect that a +// method is impossible, leading to no ambiguity. +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +#[derive(Default)] +struct W(A, B); + +trait Constrain { + type Output; +} + +impl Constrain for i32 { + type Output = u32; +} + +trait Impossible {} + +impl W where A: Constrain, B: Impossible { + fn method(&self) {} +} + +impl W { + fn method(&self) {} +} + +fn main() { + let w: W = W::default(); + w.method(); +} diff --git a/tests/ui/methods/leak-check-disquality.rs b/tests/ui/methods/leak-check-disquality.rs new file mode 100644 index 0000000000000..d3b7dd4b80719 --- /dev/null +++ b/tests/ui/methods/leak-check-disquality.rs @@ -0,0 +1,26 @@ +// Tests that using fulfillment in the trait solver means that we detect that a +// method is impossible, leading to no ambiguity. +//@ check-pass +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +struct W(Option, Option); + +impl<'a> W { + fn method(&self) {} +} + +trait Leak {} +impl Leak for T {} + +impl W { + fn method(&self) {} +} + +fn test<'a>() { + let x: W = W(None, None); + x.method(); +} + +fn main() {} diff --git a/tests/ui/mismatched_types/issue-36053-2.stderr b/tests/ui/mismatched_types/issue-36053-2.stderr index ffaa276b62e4b..5b8332016dedc 100644 --- a/tests/ui/mismatched_types/issue-36053-2.stderr +++ b/tests/ui/mismatched_types/issue-36053-2.stderr @@ -21,14 +21,16 @@ error[E0599]: the method `count` exists for struct `Filter>, {cl LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | --------- ^^^^^ method cannot be called due to unsatisfied trait bounds | | - | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` or `_: FnMut<(&&str,)>` + | doesn't satisfy `_: FnMut<(&&str,)>` or `_: FnOnce<(&&str,)>` | = note: the following trait bounds were not satisfied: - `<{closure@$DIR/issue-36053-2.rs:7:39: 7:48} as FnOnce<(&&str,)>>::Output = bool` - which is required by `Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` `{closure@$DIR/issue-36053-2.rs:7:39: 7:48}: FnMut<(&&str,)>` which is required by `Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` - `Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` + `{closure@$DIR/issue-36053-2.rs:7:39: 7:48}: FnOnce<(&&str,)>` + which is required by `Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` + `{closure@$DIR/issue-36053-2.rs:7:39: 7:48}: FnMut<(&&str,)>` + which is required by `&mut Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` + `{closure@$DIR/issue-36053-2.rs:7:39: 7:48}: FnOnce<(&&str,)>` which is required by `&mut Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` error: aborting due to 2 previous errors diff --git a/tests/ui/missing-trait-bounds/issue-35677.stderr b/tests/ui/missing-trait-bounds/issue-35677.stderr index f73bff51e7ad1..3bfdd4da6dac8 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.stderr +++ b/tests/ui/missing-trait-bounds/issue-35677.stderr @@ -6,8 +6,6 @@ LL | this.is_subset(other) | = note: the following trait bounds were not satisfied: `T: Eq` - `T: PartialEq` - which is required by `T: Eq` `T: Hash` help: consider restricting the type parameters to satisfy the trait bounds | diff --git a/tests/ui/nll/issue-57362-2.rs b/tests/ui/nll/issue-57362-2.rs index a0b0ea1d03893..bc0d0f5291f66 100644 --- a/tests/ui/nll/issue-57362-2.rs +++ b/tests/ui/nll/issue-57362-2.rs @@ -19,7 +19,8 @@ impl<'a> X for fn(&'a ()) { } fn g() { - let x = ::make_g(); //~ ERROR the function + let x = ::make_g(); + //~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope } fn main() {} diff --git a/tests/ui/nll/issue-57362-2.stderr b/tests/ui/nll/issue-57362-2.stderr index 57477f5341ede..a78c96dbd0d59 100644 --- a/tests/ui/nll/issue-57362-2.stderr +++ b/tests/ui/nll/issue-57362-2.stderr @@ -1,11 +1,9 @@ -error[E0599]: the function or associated item `make_g` exists for fn pointer `fn(&())`, but its trait bounds were not satisfied +error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope --> $DIR/issue-57362-2.rs:22:25 | LL | let x = ::make_g(); - | ^^^^^^ function or associated item cannot be called on `fn(&())` due to unsatisfied trait bounds + | ^^^^^^ function or associated item not found in `fn(&())` | - = note: the following trait bounds were not satisfied: - `for<'a> fn(&'a ()): X` = help: items from traits can only be used if the trait is implemented and in scope note: `X` defines an item `make_g`, perhaps you need to implement it --> $DIR/issue-57362-2.rs:8:1 diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.rs b/tests/ui/nll/issue-57642-higher-ranked-subtype.rs index eba859cde2206..69187cab34227 100644 --- a/tests/ui/nll/issue-57642-higher-ranked-subtype.rs +++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.rs @@ -28,7 +28,8 @@ impl Y for fn(T) { } fn higher_ranked_region_has_lost_its_binder() { - let x = ::make_g(); //~ ERROR the function + let x = ::make_g(); + //~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope } fn magical() { diff --git a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr index d1e94bc702cae..998d06b77065f 100644 --- a/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr +++ b/tests/ui/nll/issue-57642-higher-ranked-subtype.stderr @@ -1,11 +1,9 @@ -error[E0599]: the function or associated item `make_g` exists for fn pointer `fn(&())`, but its trait bounds were not satisfied +error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope --> $DIR/issue-57642-higher-ranked-subtype.rs:31:25 | LL | let x = ::make_g(); - | ^^^^^^ function or associated item cannot be called on `fn(&())` due to unsatisfied trait bounds + | ^^^^^^ function or associated item not found in `fn(&())` | - = note: the following trait bounds were not satisfied: - `for<'a> fn(&'a ()): X` = help: items from traits can only be used if the trait is implemented and in scope note: `X` defines an item `make_g`, perhaps you need to implement it --> $DIR/issue-57642-higher-ranked-subtype.rs:4:1 @@ -14,7 +12,7 @@ LL | trait X { | ^^^^^^^ error[E0599]: no function or associated item named `make_f` found for fn pointer `for<'a> fn(&'a ())` in the current scope - --> $DIR/issue-57642-higher-ranked-subtype.rs:35:25 + --> $DIR/issue-57642-higher-ranked-subtype.rs:36:25 | LL | let x = ::make_f(); | ^^^^^^ function or associated item not found in `fn(&())` diff --git a/tests/ui/resolve/issue-85671.rs b/tests/ui/resolve/issue-85671.rs index 54db03f774eeb..ac001cebda775 100644 --- a/tests/ui/resolve/issue-85671.rs +++ b/tests/ui/resolve/issue-85671.rs @@ -1,5 +1,3 @@ -//@ check-pass - // Some trait with a function that returns a slice: pub trait AsSlice { type Element; @@ -24,6 +22,7 @@ impl A { Self: AsSlice, { self.as_ref_a().as_ref_a(); + //~^ ERROR no method named `as_ref_a` found for struct `A<&[Coef]>` in the current scope } pub fn as_ref_a(&self) -> A<&[::Element]> diff --git a/tests/ui/resolve/issue-85671.stderr b/tests/ui/resolve/issue-85671.stderr new file mode 100644 index 0000000000000..0571e600197e9 --- /dev/null +++ b/tests/ui/resolve/issue-85671.stderr @@ -0,0 +1,17 @@ +error[E0599]: no method named `as_ref_a` found for struct `A<&[Coef]>` in the current scope + --> $DIR/issue-85671.rs:24:25 + | +LL | pub struct A(Cont); + | ------------------ method `as_ref_a` not found for this struct +... +LL | self.as_ref_a().as_ref_a(); + | ---- ^^^^^^^^ method not found in `A<&[Coef]>` + | | + | method `as_ref_a` is available on `&A` + | + = note: the method was found for + - `A` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/tests/ui/suggestions/derive-trait-for-method-call.stderr b/tests/ui/suggestions/derive-trait-for-method-call.stderr index 9d6d29ec74eec..ae3a0391eea24 100644 --- a/tests/ui/suggestions/derive-trait-for-method-call.stderr +++ b/tests/ui/suggestions/derive-trait-for-method-call.stderr @@ -74,22 +74,30 @@ LL | struct Struct { error[E0599]: the method `test` exists for struct `Foo, Instant>`, but its trait bounds were not satisfied --> $DIR/derive-trait-for-method-call.rs:40:15 | +LL | enum Enum { + | --------- doesn't satisfy `Enum: Clone` +... LL | struct Foo (X, Y); | ---------------- method `test` not found for this struct ... LL | let y = x.test(); | ^^^^ method cannot be called on `Foo, Instant>` due to unsatisfied trait bounds | -note: the following trait bounds were not satisfied: - `Instant: Default` - `Vec: Clone` - --> $DIR/derive-trait-for-method-call.rs:20:9 +note: trait bound `Instant: Default` was not satisfied + --> $DIR/derive-trait-for-method-call.rs:20:40 | LL | impl Foo { - | ^^^^^ ^^^^^^^ --------- - | | | - | | unsatisfied trait bound introduced here - | unsatisfied trait bound introduced here + | ^^^^^^^ --------- + | | + | unsatisfied trait bound introduced here + = note: the following trait bounds were not satisfied: + `Enum: Clone` + which is required by `Vec: Clone` +help: consider annotating `Enum` with `#[derive(Clone)]` + | +LL + #[derive(Clone)] +LL | enum Enum { + | error: aborting due to 3 previous errors diff --git a/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.stderr b/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.stderr index 74526b4dbc182..49a4db7491ed8 100644 --- a/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.stderr +++ b/tests/ui/traits/alias/issue-108132-unmet-trait-alias-bound-on-generic-impl.stderr @@ -12,13 +12,6 @@ note: trait bound `(): Iterator` was not satisfied | LL | trait IteratorAlias = Iterator; | ------------- ^^^^^^^^ unsatisfied trait bound introduced here -note: trait bound `(): IteratorAlias` was not satisfied - --> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:9:9 - | -LL | impl Foo { - | ^^^^^^^^^^^^^ ------ - | | - | unsatisfied trait bound introduced here error: aborting due to 1 previous error diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr index 4d968e7bee10f..3853761936537 100644 --- a/tests/ui/traits/method-on-unbounded-type-param.stderr +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -70,7 +70,7 @@ LL | x.cmp(&x); which is required by `Box: Iterator` `dyn T: Ord` which is required by `Box: Ord` - `Box: Iterator` + `dyn T: Iterator` which is required by `&mut Box: Iterator` `dyn T: Iterator` which is required by `&mut dyn T: Iterator` diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr index 822fc91e43fea..141f565077a5b 100644 --- a/tests/ui/traits/track-obligations.stderr +++ b/tests/ui/traits/track-obligations.stderr @@ -2,7 +2,10 @@ error[E0599]: the method `check` exists for struct `Client<()>`, but its trait b --> $DIR/track-obligations.rs:83:16 | LL | struct ALayer(C); - | ---------------- doesn't satisfy `<_ as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` or `ALayer<()>: ParticularServiceLayer<()>` + | ---------------- doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>` +... +LL | struct AService; + | --------------- doesn't satisfy `>::Response = Res` ... LL | struct Client(C); | ---------------- method `check` not found for this struct @@ -10,27 +13,14 @@ LL | struct Client(C); LL | Client(()).check(); | ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds | -note: trait bound ` as Layer<()>>::Service = as ParticularServiceLayer<()>>::Service` was not satisfied - --> $DIR/track-obligations.rs:35:14 - | -LL | pub trait ParticularServiceLayer: - | ---------------------- -LL | Layer>::Service> - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here -note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied - --> $DIR/track-obligations.rs:71:16 +note: trait bound `>::Response = Res` was not satisfied + --> $DIR/track-obligations.rs:24:21 | -LL | impl Client - | --------- +LL | impl ParticularService for T + | ----------------- - LL | where -LL | ALayer: ParticularServiceLayer, - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here -note: the trait `ParticularServiceLayer` must be implemented - --> $DIR/track-obligations.rs:34:1 - | -LL | / pub trait ParticularServiceLayer: -LL | | Layer>::Service> - | |____________________________________________________________________^ +LL | T: Service, + | ^^^^^^^^^^^^^^ unsatisfied trait bound introduced here error[E0271]: type mismatch resolving `>::Response == Res` --> $DIR/track-obligations.rs:87:11 diff --git a/tests/ui/typeck/issue-31173.stderr b/tests/ui/typeck/issue-31173.stderr index 0983147a5f0c5..5fee16b5e89f7 100644 --- a/tests/ui/typeck/issue-31173.stderr +++ b/tests/ui/typeck/issue-31173.stderr @@ -39,7 +39,7 @@ LL | | .collect(); = note: the following trait bounds were not satisfied: `, {closure@$DIR/issue-31173.rs:7:21: 7:25}> as Iterator>::Item = &_` which is required by `Cloned, {closure@$DIR/issue-31173.rs:7:21: 7:25}>>: Iterator` - `Cloned, {closure@$DIR/issue-31173.rs:7:21: 7:25}>>: Iterator` + `, {closure@$DIR/issue-31173.rs:7:21: 7:25}> as Iterator>::Item = &_` which is required by `&mut Cloned, {closure@$DIR/issue-31173.rs:7:21: 7:25}>>: Iterator` error: aborting due to 2 previous errors From d9fec1321acf9c397781ca0dd6f130b4d100fe0b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 14 Mar 2024 14:51:55 -0400 Subject: [PATCH 3/6] Normalize xform_ret_ty after constrained --- compiler/rustc_hir_typeck/src/method/probe.rs | 38 +++++++++++++++---- .../src/traits/engine.rs | 13 ------- ...ied-gat-bound-during-assoc-ty-selection.rs | 2 +- .../option-as_deref.stderr | 1 - .../option-as_deref_mut.stderr | 1 - .../result-as_deref.stderr | 1 - .../result-as_deref_mut.stderr | 1 - tests/ui/nll/issue-57362-2.rs | 1 + tests/ui/nll/issue-57362-2.stderr | 2 +- tests/ui/resolve/issue-85671.rs | 3 +- tests/ui/resolve/issue-85671.stderr | 17 --------- 11 files changed, 35 insertions(+), 45 deletions(-) delete mode 100644 tests/ui/resolve/issue-85671.stderr diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index c31b54c642db2..4921020952036 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1375,15 +1375,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, impl_ty, impl_args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Weirdly, we normalize the ret ty in this candidate, but no other candidates. - xform_ret_ty = ocx.normalize(cause, self.param_env, xform_ret_ty); - match ocx.eq_no_opaques(cause, self.param_env, xform_self_ty, self_ty) { - Ok(()) => {} + // FIXME: Make this `ocx.eq` once we define opaques more eagerly. + match self.at(cause, self.param_env).eq( + DefineOpaqueTypes::No, + xform_self_ty, + self_ty, + ) { + Ok(infer_ok) => { + ocx.register_infer_ok_obligations(infer_ok); + } Err(err) => { debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; } } + // FIXME: Weirdly, we normalize the ret ty in this candidate, but no other candidates. + xform_ret_ty = ocx.normalize(cause, self.param_env, xform_ret_ty); // Check whether the impl imposes obligations we have to worry about. let impl_def_id = probe.item.container_id(self.tcx); let impl_bounds = @@ -1425,11 +1432,19 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { infer::FnCall, poly_trait_ref, ); + let trait_ref = ocx.normalize(cause, self.param_env, trait_ref); (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - match ocx.eq_no_opaques(cause, self.param_env, xform_self_ty, self_ty) { - Ok(()) => {} + // FIXME: Make this `ocx.eq` once we define opaques more eagerly. + match self.at(cause, self.param_env).eq( + DefineOpaqueTypes::No, + xform_self_ty, + self_ty, + ) { + Ok(infer_ok) => { + ocx.register_infer_ok_obligations(infer_ok); + } Err(err) => { debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; @@ -1452,8 +1467,15 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - match ocx.eq_no_opaques(cause, self.param_env, xform_self_ty, self_ty) { - Ok(()) => {} + // FIXME: Make this `ocx.eq` once we define opaques more eagerly. + match self.at(cause, self.param_env).eq( + DefineOpaqueTypes::No, + xform_self_ty, + self_ty, + ) { + Ok(infer_ok) => { + ocx.register_infer_ok_obligations(infer_ok); + } Err(err) => { debug!("--> cannot relate self-types {:?}", err); return ProbeResult::NoMatch; diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs index 68c76dcf29734..9fbec174ce8d2 100644 --- a/compiler/rustc_trait_selection/src/traits/engine.rs +++ b/compiler/rustc_trait_selection/src/traits/engine.rs @@ -129,19 +129,6 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> { .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) } - pub fn eq_no_opaques>( - &self, - cause: &ObligationCause<'tcx>, - param_env: ty::ParamEnv<'tcx>, - expected: T, - actual: T, - ) -> Result<(), TypeError<'tcx>> { - self.infcx - .at(cause, param_env) - .eq(DefineOpaqueTypes::No, expected, actual) - .map(|infer_ok| self.register_infer_ok_obligations(infer_ok)) - } - /// Checks whether `expected` is a subtype of `actual`: `expected <: actual`. pub fn sub>( &self, diff --git a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs index 86da6ebfaaa42..d7dff329df1e6 100644 --- a/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs +++ b/tests/ui/generic-associated-types/issue-119942-unsatisified-gat-bound-during-assoc-ty-selection.rs @@ -29,5 +29,5 @@ where fn main() { let mut list = RcNode::::new(); - //~^ ERROR trait bounds were not satisfied + //~^ ERROR the variant or associated item `new` exists for enum `Node`, but its trait bounds were not satisfied } diff --git a/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr b/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr index 0468e0522d1e7..84247a4270484 100644 --- a/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr +++ b/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr @@ -6,7 +6,6 @@ LL | let _result = &Some(42).as_deref(); | = note: the following trait bounds were not satisfied: `{integer}: Deref` - which is required by `<{integer} as Deref>::Target = _` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr b/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr index cf4e866901cd9..bf05ab5665cba 100644 --- a/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr +++ b/tests/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr @@ -6,7 +6,6 @@ LL | let _result = &mut Some(42).as_deref_mut(); | = note: the following trait bounds were not satisfied: `{integer}: Deref` - which is required by `<{integer} as Deref>::Target = _` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr b/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr index 0e3e7999044fc..ac744a6d3b672 100644 --- a/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr +++ b/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr @@ -6,7 +6,6 @@ LL | let _result = &Ok(42).as_deref(); | = note: the following trait bounds were not satisfied: `{integer}: Deref` - which is required by `<{integer} as Deref>::Target = _` error: aborting due to 1 previous error diff --git a/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr b/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr index 43143db0da742..688d2cf3486e8 100644 --- a/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr +++ b/tests/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr @@ -6,7 +6,6 @@ LL | let _result = &mut Ok(42).as_deref_mut(); | = note: the following trait bounds were not satisfied: `{integer}: Deref` - which is required by `<{integer} as Deref>::Target = _` error: aborting due to 1 previous error diff --git a/tests/ui/nll/issue-57362-2.rs b/tests/ui/nll/issue-57362-2.rs index bc0d0f5291f66..664cdf89a3886 100644 --- a/tests/ui/nll/issue-57362-2.rs +++ b/tests/ui/nll/issue-57362-2.rs @@ -18,6 +18,7 @@ impl<'a> X for fn(&'a ()) { } } +// FIXME(@compiler-errors): This error message is less than helpful. fn g() { let x = ::make_g(); //~^ ERROR no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope diff --git a/tests/ui/nll/issue-57362-2.stderr b/tests/ui/nll/issue-57362-2.stderr index a78c96dbd0d59..24787b990e312 100644 --- a/tests/ui/nll/issue-57362-2.stderr +++ b/tests/ui/nll/issue-57362-2.stderr @@ -1,5 +1,5 @@ error[E0599]: no function or associated item named `make_g` found for fn pointer `for<'a> fn(&'a ())` in the current scope - --> $DIR/issue-57362-2.rs:22:25 + --> $DIR/issue-57362-2.rs:23:25 | LL | let x = ::make_g(); | ^^^^^^ function or associated item not found in `fn(&())` diff --git a/tests/ui/resolve/issue-85671.rs b/tests/ui/resolve/issue-85671.rs index ac001cebda775..54db03f774eeb 100644 --- a/tests/ui/resolve/issue-85671.rs +++ b/tests/ui/resolve/issue-85671.rs @@ -1,3 +1,5 @@ +//@ check-pass + // Some trait with a function that returns a slice: pub trait AsSlice { type Element; @@ -22,7 +24,6 @@ impl A { Self: AsSlice, { self.as_ref_a().as_ref_a(); - //~^ ERROR no method named `as_ref_a` found for struct `A<&[Coef]>` in the current scope } pub fn as_ref_a(&self) -> A<&[::Element]> diff --git a/tests/ui/resolve/issue-85671.stderr b/tests/ui/resolve/issue-85671.stderr deleted file mode 100644 index 0571e600197e9..0000000000000 --- a/tests/ui/resolve/issue-85671.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error[E0599]: no method named `as_ref_a` found for struct `A<&[Coef]>` in the current scope - --> $DIR/issue-85671.rs:24:25 - | -LL | pub struct A(Cont); - | ------------------ method `as_ref_a` not found for this struct -... -LL | self.as_ref_a().as_ref_a(); - | ---- ^^^^^^^^ method not found in `A<&[Coef]>` - | | - | method `as_ref_a` is available on `&A` - | - = note: the method was found for - - `A` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0599`. From 9d4f1d8b7eb3ac14dd1e3ba4f286a5db2c4232c5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 26 Mar 2024 13:16:19 -0400 Subject: [PATCH 4/6] Check that predicate may hold BEFORE registering it in ocx --- compiler/rustc_hir_typeck/src/method/probe.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 4921020952036..1dcda06a349e2 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -31,6 +31,7 @@ use rustc_span::edit_distance::{ }; use rustc_span::symbol::sym; use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP}; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy; use rustc_trait_selection::traits::query::method_autoderef::{ CandidateStep, MethodAutoderefStepsResult, @@ -1450,12 +1451,22 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return ProbeResult::NoMatch; } } - ocx.register_obligation(traits::Obligation::new( + let obligation = traits::Obligation::new( self.tcx, cause.clone(), self.param_env, ty::Binder::dummy(trait_ref), - )); + ); + + // FIXME(-Znext-solver): We only need this hack to deal with fatal + // overflow in the old solver. + if self.infcx.next_trait_solver() || self.infcx.predicate_may_hold(&obligation) + { + ocx.register_obligation(obligation); + } else { + result = ProbeResult::NoMatch; + } + trait_predicate = Some(ty::Binder::dummy(trait_ref).to_predicate(self.tcx)); } ObjectCandidate(poly_trait_ref) | WhereClauseCandidate(poly_trait_ref) => { From 93c6c0445db7f33d3fd85edbfb64768a88cef5ba Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 26 Mar 2024 13:35:13 -0400 Subject: [PATCH 5/6] Restore error messaging --- compiler/rustc_hir_typeck/src/method/probe.rs | 11 +++++++++++ tests/ui/mismatched_types/issue-36053-2.stderr | 10 ++++------ tests/ui/traits/method-on-unbounded-type-param.stderr | 2 +- tests/ui/typeck/issue-31173.stderr | 2 +- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 1dcda06a349e2..cfeb0792d9fe3 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1465,6 +1465,17 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { ocx.register_obligation(obligation); } else { result = ProbeResult::NoMatch; + if let Ok(Some(candidate)) = self.select_trait_candidate(trait_ref) { + for nested_obligation in candidate.nested_obligations() { + if !self.infcx.predicate_may_hold(&nested_obligation) { + possibly_unsatisfied_predicates.push(( + self.resolve_vars_if_possible(nested_obligation.predicate), + Some(self.resolve_vars_if_possible(obligation.predicate)), + Some(nested_obligation.cause), + )); + } + } + } } trait_predicate = Some(ty::Binder::dummy(trait_ref).to_predicate(self.tcx)); diff --git a/tests/ui/mismatched_types/issue-36053-2.stderr b/tests/ui/mismatched_types/issue-36053-2.stderr index 5b8332016dedc..ffaa276b62e4b 100644 --- a/tests/ui/mismatched_types/issue-36053-2.stderr +++ b/tests/ui/mismatched_types/issue-36053-2.stderr @@ -21,16 +21,14 @@ error[E0599]: the method `count` exists for struct `Filter>, {cl LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); | --------- ^^^^^ method cannot be called due to unsatisfied trait bounds | | - | doesn't satisfy `_: FnMut<(&&str,)>` or `_: FnOnce<(&&str,)>` + | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` or `_: FnMut<(&&str,)>` | = note: the following trait bounds were not satisfied: - `{closure@$DIR/issue-36053-2.rs:7:39: 7:48}: FnMut<(&&str,)>` - which is required by `Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` - `{closure@$DIR/issue-36053-2.rs:7:39: 7:48}: FnOnce<(&&str,)>` + `<{closure@$DIR/issue-36053-2.rs:7:39: 7:48} as FnOnce<(&&str,)>>::Output = bool` which is required by `Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` `{closure@$DIR/issue-36053-2.rs:7:39: 7:48}: FnMut<(&&str,)>` - which is required by `&mut Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` - `{closure@$DIR/issue-36053-2.rs:7:39: 7:48}: FnOnce<(&&str,)>` + which is required by `Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` + `Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` which is required by `&mut Filter>, {closure@$DIR/issue-36053-2.rs:7:39: 7:48}>: Iterator` error: aborting due to 2 previous errors diff --git a/tests/ui/traits/method-on-unbounded-type-param.stderr b/tests/ui/traits/method-on-unbounded-type-param.stderr index 3853761936537..4d968e7bee10f 100644 --- a/tests/ui/traits/method-on-unbounded-type-param.stderr +++ b/tests/ui/traits/method-on-unbounded-type-param.stderr @@ -70,7 +70,7 @@ LL | x.cmp(&x); which is required by `Box: Iterator` `dyn T: Ord` which is required by `Box: Ord` - `dyn T: Iterator` + `Box: Iterator` which is required by `&mut Box: Iterator` `dyn T: Iterator` which is required by `&mut dyn T: Iterator` diff --git a/tests/ui/typeck/issue-31173.stderr b/tests/ui/typeck/issue-31173.stderr index 5fee16b5e89f7..0983147a5f0c5 100644 --- a/tests/ui/typeck/issue-31173.stderr +++ b/tests/ui/typeck/issue-31173.stderr @@ -39,7 +39,7 @@ LL | | .collect(); = note: the following trait bounds were not satisfied: `, {closure@$DIR/issue-31173.rs:7:21: 7:25}> as Iterator>::Item = &_` which is required by `Cloned, {closure@$DIR/issue-31173.rs:7:21: 7:25}>>: Iterator` - `, {closure@$DIR/issue-31173.rs:7:21: 7:25}> as Iterator>::Item = &_` + `Cloned, {closure@$DIR/issue-31173.rs:7:21: 7:25}>>: Iterator` which is required by `&mut Cloned, {closure@$DIR/issue-31173.rs:7:21: 7:25}>>: Iterator` error: aborting due to 2 previous errors From 8995c2c4a20197358605c3dad609e39f90a75ce8 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 5 Apr 2024 22:00:43 -0400 Subject: [PATCH 6/6] Use sup instead of eq when unifying self type --- compiler/rustc_hir_typeck/src/method/probe.rs | 12 ++--- tests/ui/impl-trait/issues/issue-62742.rs | 11 ++-- tests/ui/impl-trait/issues/issue-62742.stderr | 52 ++++--------------- tests/ui/impl-trait/issues/issue-84073.rs | 2 +- tests/ui/impl-trait/issues/issue-84073.stderr | 26 ++-------- tests/ui/methods/self-type-is-sup-no-eq.rs | 24 +++++++++ 6 files changed, 52 insertions(+), 75 deletions(-) create mode 100644 tests/ui/methods/self-type-is-sup-no-eq.rs diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index cfeb0792d9fe3..8a7ebd6478b13 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1376,8 +1376,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, impl_ty, impl_args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.eq` once we define opaques more eagerly. - match self.at(cause, self.param_env).eq( + // FIXME: Make this `ocx.sup` once we define opaques more eagerly. + match self.at(cause, self.param_env).sup( DefineOpaqueTypes::No, xform_self_ty, self_ty, @@ -1437,8 +1437,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.eq` once we define opaques more eagerly. - match self.at(cause, self.param_env).eq( + // FIXME: Make this `ocx.sup` once we define opaques more eagerly. + match self.at(cause, self.param_env).sup( DefineOpaqueTypes::No, xform_self_ty, self_ty, @@ -1489,8 +1489,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { (xform_self_ty, xform_ret_ty) = self.xform_self_ty(probe.item, trait_ref.self_ty(), trait_ref.args); xform_self_ty = ocx.normalize(cause, self.param_env, xform_self_ty); - // FIXME: Make this `ocx.eq` once we define opaques more eagerly. - match self.at(cause, self.param_env).eq( + // FIXME: Make this `ocx.sup` once we define opaques more eagerly. + match self.at(cause, self.param_env).sup( DefineOpaqueTypes::No, xform_self_ty, self_ty, diff --git a/tests/ui/impl-trait/issues/issue-62742.rs b/tests/ui/impl-trait/issues/issue-62742.rs index bd48c51c06546..56c63a1daa867 100644 --- a/tests/ui/impl-trait/issues/issue-62742.rs +++ b/tests/ui/impl-trait/issues/issue-62742.rs @@ -1,12 +1,17 @@ use std::marker::PhantomData; -fn _alias_check() { +fn a() { WrongImpl::foo(0i32); - //~^ ERROR the trait bound `RawImpl<_>: Raw<_>` is not satisfied - //~| ERROR the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied + //~^ ERROR overflow assigning `_` to `[_]` +} + +fn b() { WrongImpl::<()>::foo(0i32); //~^ ERROR the trait bound `RawImpl<()>: Raw<()>` is not satisfied //~| ERROR trait bounds were not satisfied +} + +fn c() { CorrectImpl::foo(0i32); } diff --git a/tests/ui/impl-trait/issues/issue-62742.stderr b/tests/ui/impl-trait/issues/issue-62742.stderr index f6798f55a472c..7a1bcfc70d54f 100644 --- a/tests/ui/impl-trait/issues/issue-62742.stderr +++ b/tests/ui/impl-trait/issues/issue-62742.stderr @@ -1,30 +1,11 @@ -error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<_, RawImpl<_>>`, but its trait bounds were not satisfied +error[E0275]: overflow assigning `_` to `[_]` --> $DIR/issue-62742.rs:4:16 | LL | WrongImpl::foo(0i32); - | ^^^ function or associated item cannot be called on `SafeImpl<_, RawImpl<_>>` due to unsatisfied trait bounds -... -LL | pub struct RawImpl(PhantomData); - | --------------------- doesn't satisfy `RawImpl<_>: Raw<_>` -... -LL | pub struct SafeImpl>(PhantomData<(A, T)>); - | ----------------------------------------- function or associated item `foo` not found for this struct - | -note: trait bound `RawImpl<_>: Raw<_>` was not satisfied - --> $DIR/issue-62742.rs:29:20 - | -LL | impl> SafeImpl { - | ^^^^^^ -------------- - | | - | unsatisfied trait bound introduced here -note: the trait `Raw` must be implemented - --> $DIR/issue-62742.rs:13:1 - | -LL | pub trait Raw { - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ error[E0599]: the function or associated item `foo` exists for struct `SafeImpl<(), RawImpl<()>>`, but its trait bounds were not satisfied - --> $DIR/issue-62742.rs:7:22 + --> $DIR/issue-62742.rs:9:22 | LL | WrongImpl::<()>::foo(0i32); | ^^^ function or associated item cannot be called on `SafeImpl<(), RawImpl<()>>` due to unsatisfied trait bounds @@ -36,33 +17,20 @@ LL | pub struct SafeImpl>(PhantomData<(A, T)>); | ----------------------------------------- function or associated item `foo` not found for this struct | note: trait bound `RawImpl<()>: Raw<()>` was not satisfied - --> $DIR/issue-62742.rs:29:20 + --> $DIR/issue-62742.rs:34:20 | LL | impl> SafeImpl { | ^^^^^^ -------------- | | | unsatisfied trait bound introduced here note: the trait `Raw` must be implemented - --> $DIR/issue-62742.rs:13:1 + --> $DIR/issue-62742.rs:18:1 | LL | pub trait Raw { | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `RawImpl<_>: Raw<_>` is not satisfied - --> $DIR/issue-62742.rs:4:5 - | -LL | WrongImpl::foo(0i32); - | ^^^^^^^^^ the trait `Raw<_>` is not implemented for `RawImpl<_>` - | - = help: the trait `Raw<[_]>` is implemented for `RawImpl<_>` -note: required by a bound in `SafeImpl` - --> $DIR/issue-62742.rs:27:35 - | -LL | pub struct SafeImpl>(PhantomData<(A, T)>); - | ^^^^^^ required by this bound in `SafeImpl` - error[E0277]: the trait bound `RawImpl<()>: Raw<()>` is not satisfied - --> $DIR/issue-62742.rs:7:5 + --> $DIR/issue-62742.rs:9:5 | LL | WrongImpl::<()>::foo(0i32); | ^^^^^^^^^^^^^^^ the trait `Raw<()>` is not implemented for `RawImpl<()>` @@ -70,12 +38,12 @@ LL | WrongImpl::<()>::foo(0i32); = help: the trait `Raw<[()]>` is implemented for `RawImpl<()>` = help: for that trait implementation, expected `[()]`, found `()` note: required by a bound in `SafeImpl` - --> $DIR/issue-62742.rs:27:35 + --> $DIR/issue-62742.rs:32:35 | LL | pub struct SafeImpl>(PhantomData<(A, T)>); | ^^^^^^ required by this bound in `SafeImpl` -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0277, E0599. -For more information about an error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0275, E0277, E0599. +For more information about an error, try `rustc --explain E0275`. diff --git a/tests/ui/impl-trait/issues/issue-84073.rs b/tests/ui/impl-trait/issues/issue-84073.rs index f2f1835dc344e..7acee44a722a4 100644 --- a/tests/ui/impl-trait/issues/issue-84073.rs +++ b/tests/ui/impl-trait/issues/issue-84073.rs @@ -30,5 +30,5 @@ where fn main() { Race::new(|race| race.when()); - //~^ ERROR the method `when` exists for struct `RaceBuilder<_, Never<_>>`, but its trait bounds were not satisfied + //~^ ERROR overflow assigning `_` to `Option<_>` } diff --git a/tests/ui/impl-trait/issues/issue-84073.stderr b/tests/ui/impl-trait/issues/issue-84073.stderr index eeb23b130819d..0f4c6e83fbe70 100644 --- a/tests/ui/impl-trait/issues/issue-84073.stderr +++ b/tests/ui/impl-trait/issues/issue-84073.stderr @@ -1,29 +1,9 @@ -error[E0599]: the method `when` exists for struct `RaceBuilder<_, Never<_>>`, but its trait bounds were not satisfied +error[E0275]: overflow assigning `_` to `Option<_>` --> $DIR/issue-84073.rs:32:27 | -LL | pub struct Never(PhantomData); - | ------------------- doesn't satisfy `Never<_>: StatefulFuture>` -... -LL | pub struct RaceBuilder { - | ---------------------------- method `when` not found for this struct -... LL | Race::new(|race| race.when()); - | ^^^^ method cannot be called on `RaceBuilder<_, Never<_>>` due to unsatisfied trait bounds - | -note: trait bound `Never<_>: StatefulFuture>` was not satisfied - --> $DIR/issue-84073.rs:14:8 - | -LL | impl RaceBuilder - | ----------------- -LL | where -LL | F: StatefulFuture>, - | ^^^^^^^^^^^^^^^^^^^^^^^^^ unsatisfied trait bound introduced here -note: the trait `StatefulFuture` must be implemented - --> $DIR/issue-84073.rs:3:1 - | -LL | pub trait StatefulFuture {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^ error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0599`. +For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/methods/self-type-is-sup-no-eq.rs b/tests/ui/methods/self-type-is-sup-no-eq.rs new file mode 100644 index 0000000000000..ec28b964a0518 --- /dev/null +++ b/tests/ui/methods/self-type-is-sup-no-eq.rs @@ -0,0 +1,24 @@ +//@ check-pass + +// Test that we use `sup` not `eq` during method probe, since this has an effect +// on the leak check. This is (conceptually) minimized from a crater run for +// `wrend 0.3.6`. + +use std::ops::Deref; + +struct A; + +impl Deref for A { + type Target = B; + + fn deref(&self) -> &::Target { todo!() } +} + +struct B(T); +impl B { + fn method(&self) {} +} + +fn main() { + A.method(); +}