diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs index 7a3d615862cba..37e418321b421 100644 --- a/compiler/rustc_middle/src/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -163,7 +163,13 @@ impl FlagComputation { &ty::Projection(data) => { self.add_flags(TypeFlags::HAS_TY_PROJECTION); + // Check if this projection type captures any late-bound variables in its substs + let old_outer = std::mem::replace(&mut self.outer_exclusive_binder, ty::INNERMOST); self.add_projection_ty(data); + if self.outer_exclusive_binder > ty::INNERMOST { + self.add_flags(TypeFlags::HAS_LATE_IN_PROJECTION); + } + self.outer_exclusive_binder = self.outer_exclusive_binder.max(old_outer); } &ty::Opaque(_, substs) => { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 4922d07ae1c5d..73b70e57f5faa 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -209,6 +209,14 @@ pub trait TypeFoldable<'tcx>: fmt::Debug + Clone { fn still_further_specializable(&self) -> bool { self.has_type_flags(TypeFlags::STILL_FURTHER_SPECIALIZABLE) } + + // Indicates that this value has projection types which capture late-bound variables, + // which is a sign that the projection types within need further normalization. This + // is because we do not replace projections with inference variables when they capture + // late-bound variables. + fn has_late_bound_vars_in_projection(&self) -> bool { + self.has_type_flags(TypeFlags::HAS_LATE_IN_PROJECTION) + } } /// This trait is implemented for every folding traversal. There is a fold diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs index 62c6c8454797a..fea9dabb5695b 100644 --- a/compiler/rustc_trait_selection/src/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -344,34 +344,57 @@ impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { pending_obligation.stalled_on.truncate(0); + let infcx = self.selcx.infcx(); let obligation = &mut pending_obligation.obligation; debug!(?obligation, "process_obligation pre-resolve"); - if obligation.predicate.has_infer_types_or_consts() { - obligation.predicate = - self.selcx.infcx().resolve_vars_if_possible(obligation.predicate); - } - - debug!(?obligation, ?obligation.cause, "process_obligation"); + let mut predicate_changed = false; - let infcx = self.selcx.infcx(); + if obligation.predicate.has_late_bound_vars_in_projection() { + let mut obligations = Vec::new(); + let predicate = crate::traits::project::try_normalize_with_depth_to( + self.selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + obligation.predicate, + &mut obligations, + ); + if predicate != obligation.predicate { + if obligations.is_empty() { + debug!( + "progress_changed_obligations: late-bound predicate updated, fast path: {} => {}", + obligation.predicate, predicate + ); + // Optimization, since we don't need to return with Changed if we're + // just updating the predicate to a new normalized form. + predicate_changed = true; + obligation.predicate = predicate; + } else { + debug!( + "progress_changed_obligations: late-bound predicate updated, slow path: {} => {}, additional obligations: {:?}", + obligation.predicate, predicate, obligations + ); + obligations.push(obligation.with(predicate)); + return ProcessResult::Changed(mk_pending(obligations)); + } + } else { + debug!( + "progress_changed_obligations: late-bound predicate not updated: {}", + obligation.predicate + ); + } + } - if obligation.predicate.has_projections() { - let mut obligations = Vec::new(); - let predicate = crate::traits::project::try_normalize_with_depth_to( - self.selcx, - obligation.param_env, - obligation.cause.clone(), - obligation.recursion_depth + 1, - obligation.predicate, - &mut obligations, - ); - if predicate != obligation.predicate { - obligations.push(obligation.with(predicate)); - return ProcessResult::Changed(mk_pending(obligations)); + if !predicate_changed { + obligation.predicate = + self.selcx.infcx().resolve_vars_if_possible(obligation.predicate); } } + + debug!(?obligation, ?obligation.cause, "process_obligation"); + let binder = obligation.predicate.kind(); match binder.no_bound_vars() { None => match binder.skip_binder() { diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index e26f0033156bc..96eccb8b46f86 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -107,6 +107,9 @@ bitflags! { /// Does this value have `InferConst::Fresh`? const HAS_CT_FRESH = 1 << 19; + + // Does this value have any late-bound vars in any projection type substs? + const HAS_LATE_IN_PROJECTION = 1 << 20; } } diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs index b3213451d76c4..9c854a17decff 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/_impl.rs @@ -474,7 +474,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) { if !ty.references_error() { let lang_item = self.tcx.require_lang_item(LangItem::Sized, None); - self.require_type_meets(ty, span, code, lang_item); + self.require_type_meets( + // We normalize this type because we possibly got it from HIR + self.normalize_associated_types_in(span, ty), + span, + code, + lang_item, + ); } } diff --git a/src/test/ui/associated-types/issue-59324.rs b/src/test/ui/associated-types/issue-59324.rs index 162f9e00edd81..9e68e9e77515b 100644 --- a/src/test/ui/associated-types/issue-59324.rs +++ b/src/test/ui/associated-types/issue-59324.rs @@ -15,9 +15,9 @@ pub trait ThriftService: { fn get_service( //~^ ERROR the trait bound `Bug: Foo` is not satisfied + //~| ERROR the trait bound `Bug: Foo` is not satisfied &self, ) -> Self::AssocType; - //~^ the trait bound `Bug: Foo` is not satisfied } fn with_factory(factory: dyn ThriftService<()>) {} diff --git a/src/test/ui/associated-types/issue-59324.stderr b/src/test/ui/associated-types/issue-59324.stderr index 45d2dfb53757b..2f430d3055e19 100644 --- a/src/test/ui/associated-types/issue-59324.stderr +++ b/src/test/ui/associated-types/issue-59324.stderr @@ -6,7 +6,7 @@ LL | | LL | | LL | | Service::OnlyFoo> ... | -LL | | +LL | | ) -> Self::AssocType; LL | | } | |_^ the trait `Foo` is not implemented for `Bug` | @@ -23,7 +23,7 @@ LL | | LL | | LL | | Service::OnlyFoo> ... | -LL | | +LL | | ) -> Self::AssocType; LL | | } | |_^ the trait `Foo` is not implemented for `Bug` | @@ -37,6 +37,7 @@ error[E0277]: the trait bound `Bug: Foo` is not satisfied | LL | / fn get_service( LL | | +LL | | LL | | &self, LL | | ) -> Self::AssocType; | |_________________________^ the trait `Foo` is not implemented for `Bug` @@ -47,10 +48,10 @@ LL | pub trait ThriftService: | +++++ error[E0277]: the trait bound `Bug: Foo` is not satisfied - --> $DIR/issue-59324.rs:19:10 + --> $DIR/issue-59324.rs:16:8 | -LL | ) -> Self::AssocType; - | ^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug` +LL | fn get_service( + | ^^^^^^^^^^^ the trait `Foo` is not implemented for `Bug` | help: consider further restricting this bound | diff --git a/src/test/ui/generic-associated-types/issue-91139.rs b/src/test/ui/generic-associated-types/issue-91139.rs index 78b2b63dadc5e..5c4a7cf6ffc60 100644 --- a/src/test/ui/generic-associated-types/issue-91139.rs +++ b/src/test/ui/generic-associated-types/issue-91139.rs @@ -1,13 +1,4 @@ -// revisions: migrate nll -//[nll]compile-flags: -Z borrowck=mir - -// Since we are testing nll (and migration) explicitly as a separate -// revisions, don't worry about the --compare-mode=nll on this test. - -// ignore-compare-mode-nll - -//[nll] check-pass -//[migrate] check-fail +// check-pass #![feature(generic_associated_types)] @@ -25,7 +16,6 @@ impl Foo for () { fn foo() { let _: for<'a> fn(<() as Foo>::Type<'a>, &'a T) = |_, _| (); - //[migrate]~^ the parameter type `T` may not live long enough } pub fn main() {} diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs index fe319e6c8515c..8dc3895366489 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.rs @@ -7,7 +7,6 @@ trait SomeTrait<'a> { fn give_me_ice() { callee:: >::Associated>(); //~^ ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277] - //~| ERROR the trait bound `T: SomeTrait<'_>` is not satisfied [E0277] } fn callee>() { diff --git a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr index 13b68b072403a..aaf45dc7ad564 100644 --- a/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr +++ b/src/test/ui/higher-rank-trait-bounds/normalize-under-binder/issue-85455.stderr @@ -9,17 +9,6 @@ help: consider restricting type parameter `T` LL | fn give_me_ice>() { | +++++++++++++++ -error[E0277]: the trait bound `T: SomeTrait<'_>` is not satisfied - --> $DIR/issue-85455.rs:8:14 - | -LL | callee:: >::Associated>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `SomeTrait<'_>` is not implemented for `T` - | -help: consider restricting type parameter `T` - | -LL | fn give_me_ice>() { - | +++++++++++++++ - -error: aborting due to 2 previous errors +error: aborting due to previous error For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr index 43471f980b2af..a8eb53a50e38b 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use9.stderr @@ -10,12 +10,13 @@ note: previous use here LL | fn two(t: T, u: U) -> Two { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `A: Foo` is not satisfied +error[E0277]: the trait bound `A: Foo` is not satisfied in `(A, B, ::Bar)` --> $DIR/generic_duplicate_param_use9.rs:7:18 | LL | type Two = impl Debug; - | ^^^^^^^^^^ the trait `Foo` is not implemented for `A` + | ^^^^^^^^^^ within `(A, B, ::Bar)`, the trait `Foo` is not implemented for `A` | + = note: required because it appears within the type `(A, B, ::Bar)` help: consider restricting type parameter `A` | LL | type Two = impl Debug; @@ -27,7 +28,7 @@ error[E0277]: `A` doesn't implement `Debug` LL | type Two = impl Debug; | ^^^^^^^^^^ `A` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: required because of the requirements on the impl of `Debug` for `(A, B, _)` + = note: required because of the requirements on the impl of `Debug` for `(A, B, ::Bar)` help: consider restricting type parameter `A` | LL | type Two = impl Debug; @@ -39,7 +40,7 @@ error[E0277]: `B` doesn't implement `Debug` LL | type Two = impl Debug; | ^^^^^^^^^^ `B` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: required because of the requirements on the impl of `Debug` for `(A, B, _)` + = note: required because of the requirements on the impl of `Debug` for `(A, B, ::Bar)` help: consider restricting type parameter `B` | LL | type Two = impl Debug; diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.rs b/src/test/ui/type-alias-impl-trait/issue-89686.rs index f058653dde338..92b676cbfcf1f 100644 --- a/src/test/ui/type-alias-impl-trait/issue-89686.rs +++ b/src/test/ui/type-alias-impl-trait/issue-89686.rs @@ -5,7 +5,8 @@ use std::future::Future; type G<'a, T> = impl Future; -//~^ ERROR: the trait bound `T: Trait` is not satisfied +//~^ ERROR as Future>::Output == () +//~| ERROR the trait bound `T: Trait` is not satisfied trait Trait { type F: Future; diff --git a/src/test/ui/type-alias-impl-trait/issue-89686.stderr b/src/test/ui/type-alias-impl-trait/issue-89686.stderr index 0df5a809ebb47..19ed9a7476c1b 100644 --- a/src/test/ui/type-alias-impl-trait/issue-89686.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-89686.stderr @@ -1,3 +1,22 @@ +error[E0271]: type mismatch resolving ` as Future>::Output == ()` + --> $DIR/issue-89686.rs:7:17 + | +LL | type G<'a, T> = impl Future; + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found associated type +... +LL | async move { self.f().await } + | ------------------ the found `async` block + | + ::: $SRC_DIR/core/src/future/mod.rs:LL:COL + | +LL | pub const fn from_generator(gen: T) -> impl Future + | ------------------------------- the found opaque type + | + = note: expected unit type `()` + found associated type ` as Future>::Output` + = help: consider constraining the associated type ` as Future>::Output` to `()` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html + error[E0277]: the trait bound `T: Trait` is not satisfied --> $DIR/issue-89686.rs:7:17 | @@ -9,6 +28,7 @@ help: consider restricting type parameter `T` LL | type G<'a, T: Trait> = impl Future; | +++++++ -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0271, E0277. +For more information about an error, try `rustc --explain E0271`.