diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 8a7ebd6478b13..1e2186116a43d 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -15,6 +15,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::DefineOpaqueTypes; use rustc_infer::infer::{self, InferOk, TyCtxtInferExt}; +use rustc_infer::traits::EvaluationResult; use rustc_middle::middle::stability; use rustc_middle::query::Providers; use rustc_middle::ty::fast_reject::{simplify_type, TreatParams}; @@ -37,6 +38,7 @@ 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; @@ -1375,7 +1377,9 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { 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); + let InferOk { value: normalized, mut obligations } = + self.at(cause, self.param_env).normalize(xform_self_ty); + xform_self_ty = normalized; // FIXME: Make this `ocx.sup` once we define opaques more eagerly. match self.at(cause, self.param_env).sup( DefineOpaqueTypes::No, @@ -1397,8 +1401,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { 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. - ocx.register_obligations(traits::predicates_for_generics( + obligations.extend(traits::predicates_for_generics( |idx, span| { let code = if span.is_dummy() { traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx) @@ -1415,6 +1418,32 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.param_env, impl_bounds, )); + + for obligation in obligations { + if self.infcx.next_trait_solver() { + ocx.register_obligation(obligation); + } else { + match self.infcx.evaluate_obligation_no_overflow(&obligation) { + EvaluationResult::EvaluatedToOk + | EvaluationResult::EvaluatedToOkModuloRegions => { + // No side-effects, no need to register obligations. + } + EvaluationResult::EvaluatedToOkModuloOpaqueTypes + | EvaluationResult::EvaluatedToAmbig + | EvaluationResult::EvaluatedToAmbigStackDependent => { + ocx.register_obligation(obligation); + } + EvaluationResult::EvaluatedToErr => { + result = ProbeResult::NoMatch; + possibly_unsatisfied_predicates.push(( + self.resolve_vars_if_possible(obligation.predicate), + None, + Some(obligation.cause.clone()), + )); + } + } + } + } } TraitCandidate(poly_trait_ref) => { // Some trait methods are excluded for arrays before 2021. @@ -1436,7 +1465,11 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { 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); + + let InferOk { value: normalized, obligations: normalize_obligations } = + self.at(cause, self.param_env).normalize(xform_self_ty); + xform_self_ty = normalized; + // FIXME: Make this `ocx.sup` once we define opaques more eagerly. match self.at(cause, self.param_env).sup( DefineOpaqueTypes::No, @@ -1451,6 +1484,33 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return ProbeResult::NoMatch; } } + + for obligation in normalize_obligations { + if self.infcx.next_trait_solver() { + ocx.register_obligation(obligation); + } else { + match self.infcx.evaluate_obligation_no_overflow(&obligation) { + EvaluationResult::EvaluatedToOk + | EvaluationResult::EvaluatedToOkModuloRegions => { + // No side-effects, no need to register obligations. + } + EvaluationResult::EvaluatedToOkModuloOpaqueTypes + | EvaluationResult::EvaluatedToAmbig + | EvaluationResult::EvaluatedToAmbigStackDependent => { + ocx.register_obligation(obligation); + } + EvaluationResult::EvaluatedToErr => { + result = ProbeResult::NoMatch; + possibly_unsatisfied_predicates.push(( + self.resolve_vars_if_possible(obligation.predicate), + None, + Some(obligation.cause.clone()), + )); + } + } + } + } + let obligation = traits::Obligation::new( self.tcx, cause.clone(), @@ -1458,21 +1518,36 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { 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) - { + if self.infcx.next_trait_solver() { 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), - )); + match self.infcx.evaluate_obligation_no_overflow(&obligation) { + EvaluationResult::EvaluatedToOk => { + // No side-effects, no need to register obligations. + } + EvaluationResult::EvaluatedToOkModuloRegions + | EvaluationResult::EvaluatedToOkModuloOpaqueTypes + | EvaluationResult::EvaluatedToAmbig + | EvaluationResult::EvaluatedToAmbigStackDependent => { + ocx.register_obligation(obligation); + } + EvaluationResult::EvaluatedToErr => { + 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), + )); + } + } } } } @@ -1488,7 +1563,10 @@ 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); + let InferOk { value: normalized, obligations: normalize_obligations } = + self.at(cause, self.param_env).normalize(xform_self_ty); + xform_self_ty = normalized; + // FIXME: Make this `ocx.sup` once we define opaques more eagerly. match self.at(cause, self.param_env).sup( DefineOpaqueTypes::No, @@ -1503,26 +1581,55 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { return ProbeResult::NoMatch; } } + + for obligation in normalize_obligations { + if self.infcx.next_trait_solver() { + ocx.register_obligation(obligation); + } else { + match self.infcx.evaluate_obligation_no_overflow(&obligation) { + EvaluationResult::EvaluatedToOk => { + // No side-effects, no need to register obligations. + } + EvaluationResult::EvaluatedToOkModuloRegions + | EvaluationResult::EvaluatedToOkModuloOpaqueTypes + | EvaluationResult::EvaluatedToAmbig + | EvaluationResult::EvaluatedToAmbigStackDependent => { + ocx.register_obligation(obligation); + } + EvaluationResult::EvaluatedToErr => { + result = ProbeResult::NoMatch; + possibly_unsatisfied_predicates.push(( + self.resolve_vars_if_possible(obligation.predicate), + None, + Some(obligation.cause.clone()), + )); + } + } + } + } } } // Evaluate those obligations to see if they might possibly hold. - 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), - )); + if let ProbeResult::Match = result { + 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), + )); + } } } diff --git a/tests/ui/impl-trait/issues/issue-84073.stderr b/tests/ui/impl-trait/issues/issue-84073.stderr index 0f4c6e83fbe70..ab119a8a4f456 100644 --- a/tests/ui/impl-trait/issues/issue-84073.stderr +++ b/tests/ui/impl-trait/issues/issue-84073.stderr @@ -1,8 +1,8 @@ error[E0275]: overflow assigning `_` to `Option<_>` - --> $DIR/issue-84073.rs:32:27 + --> $DIR/issue-84073.rs:32:22 | LL | Race::new(|race| race.when()); - | ^^^^ + | ^^^^ error: aborting due to 1 previous error diff --git a/tests/ui/missing-trait-bounds/issue-35677.fixed b/tests/ui/missing-trait-bounds/issue-35677.fixed deleted file mode 100644 index 6be68bb26df15..0000000000000 --- a/tests/ui/missing-trait-bounds/issue-35677.fixed +++ /dev/null @@ -1,11 +0,0 @@ -//@ run-rustfix -#![allow(dead_code)] -use std::collections::HashSet; -use std::hash::Hash; - -fn is_subset(this: &HashSet, other: &HashSet) -> bool where T: Eq, T: Hash { - this.is_subset(other) - //~^ ERROR the method -} - -fn main() {} diff --git a/tests/ui/missing-trait-bounds/issue-35677.rs b/tests/ui/missing-trait-bounds/issue-35677.rs index e2d13bbe2f6fb..88903ef73749d 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.rs +++ b/tests/ui/missing-trait-bounds/issue-35677.rs @@ -1,4 +1,3 @@ -//@ run-rustfix #![allow(dead_code)] use std::collections::HashSet; use std::hash::Hash; diff --git a/tests/ui/missing-trait-bounds/issue-35677.stderr b/tests/ui/missing-trait-bounds/issue-35677.stderr index 3bfdd4da6dac8..fa50444dcda06 100644 --- a/tests/ui/missing-trait-bounds/issue-35677.stderr +++ b/tests/ui/missing-trait-bounds/issue-35677.stderr @@ -1,5 +1,5 @@ error[E0599]: the method `is_subset` exists for reference `&HashSet`, but its trait bounds were not satisfied - --> $DIR/issue-35677.rs:7:10 + --> $DIR/issue-35677.rs:6:10 | LL | this.is_subset(other) | ^^^^^^^^^ method cannot be called on `&HashSet` due to unsatisfied trait bounds diff --git a/tests/ui/suggestions/derive-trait-for-method-call.stderr b/tests/ui/suggestions/derive-trait-for-method-call.stderr index ae3a0391eea24..9d6d29ec74eec 100644 --- a/tests/ui/suggestions/derive-trait-for-method-call.stderr +++ b/tests/ui/suggestions/derive-trait-for-method-call.stderr @@ -74,30 +74,22 @@ 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: trait bound `Instant: Default` was not satisfied - --> $DIR/derive-trait-for-method-call.rs:20:40 +note: the following trait bounds were not satisfied: + `Instant: Default` + `Vec: Clone` + --> $DIR/derive-trait-for-method-call.rs:20:9 | LL | impl Foo { - | ^^^^^^^ --------- - | | - | 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 { - | + | ^^^^^ ^^^^^^^ --------- + | | | + | | unsatisfied trait bound introduced here + | unsatisfied trait bound introduced here 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 49a4db7491ed8..148f997be44f2 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 @@ -7,11 +7,13 @@ LL | struct Foo(I); LL | Foo::<()>::f() | ^ function or associated item cannot be called on `Foo<()>` due to unsatisfied trait bounds | -note: trait bound `(): Iterator` was not satisfied - --> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:5:23 +note: trait bound `(): IteratorAlias` was not satisfied + --> $DIR/issue-108132-unmet-trait-alias-bound-on-generic-impl.rs:9:9 | -LL | trait IteratorAlias = Iterator; - | ------------- ^^^^^^^^ unsatisfied trait bound introduced here +LL | impl Foo { + | ^^^^^^^^^^^^^ ------ + | | + | unsatisfied trait bound introduced here error: aborting due to 1 previous error diff --git a/tests/ui/traits/track-obligations.stderr b/tests/ui/traits/track-obligations.stderr index 141f565077a5b..d945c85b17fa6 100644 --- a/tests/ui/traits/track-obligations.stderr +++ b/tests/ui/traits/track-obligations.stderr @@ -4,23 +4,26 @@ error[E0599]: the method `check` exists for struct `Client<()>`, but its trait b LL | struct ALayer(C); | ---------------- doesn't satisfy `ALayer<()>: ParticularServiceLayer<()>` ... -LL | struct AService; - | --------------- doesn't satisfy `>::Response = Res` -... LL | struct Client(C); | ---------------- method `check` not found for this struct ... LL | Client(()).check(); | ^^^^^ method cannot be called on `Client<()>` due to unsatisfied trait bounds | -note: trait bound `>::Response = Res` was not satisfied - --> $DIR/track-obligations.rs:24:21 +note: trait bound `ALayer<()>: ParticularServiceLayer<()>` was not satisfied + --> $DIR/track-obligations.rs:71:16 | -LL | impl ParticularService for T - | ----------------- - +LL | impl Client + | --------- LL | where -LL | T: Service, - | ^^^^^^^^^^^^^^ unsatisfied trait bound introduced here +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> + | |____________________________________________________________________^ error[E0271]: type mismatch resolving `>::Response == Res` --> $DIR/track-obligations.rs:87:11