diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 68302e075e173..b255951baefa6 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -299,7 +299,7 @@ impl<'tcx> HirTyLowerer<'tcx> for FnCtxt<'_, 'tcx> { self.param_env.caller_bounds().iter().filter_map(|clause| { match clause.kind().skip_binder() { ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => { - Some((clause, span)) + Some((ty::set_aliases_to_non_rigid(tcx, clause).skip_norm_wip(), span)) } _ => None, } diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs index 6166560a671a0..b84c6d0aed42d 100644 --- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs +++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs @@ -90,7 +90,8 @@ pub(super) fn can_match_erased_ty<'tcx>( // deal with rigid aliases, making sure we do so correctly // everywhere is effort, so we're just using `No` everywhere // for now. This should change soon. - let outlives_ty = ty::set_aliases_to_non_rigid(tcx, outlives_ty).skip_normalization(); + let (outlives_ty, erased_ty) = + ty::set_aliases_to_non_rigid(tcx, (outlives_ty, erased_ty)).skip_normalization(); if outlives_ty == erased_ty { // pointless micro-optimization true diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs index 9a9801aa3f3f7..3c07a32471bdb 100644 --- a/compiler/rustc_infer/src/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -258,6 +258,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let erased_p_ty = self.tcx.erase_and_anonymize_regions( ty::set_aliases_to_non_rigid(self.tcx, p_ty).skip_norm_wip(), ); + let erased_ty = ty::set_aliases_to_non_rigid(self.tcx, erased_ty).skip_norm_wip(); (erased_p_ty == erased_ty).then_some(ty::Binder::dummy(ty::OutlivesPredicate(p_ty, r))) })); diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3d7aef0b273f1..8bbb5e9244c2e 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -2699,6 +2699,10 @@ impl<'tcx> TyCtxt<'tcx> { self.sess.opts.unstable_opts.disable_fast_paths } + pub fn disable_param_env_normalization_hack(self) -> bool { + self.sess.opts.unstable_opts.disable_param_env_normalization_hack + } + pub fn renormalize_rigid_aliases(self) -> bool { self.sess.opts.unstable_opts.renormalize_rigid_aliases } diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs index 61ec6751d0f30..2f44b4c102486 100644 --- a/compiler/rustc_session/src/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -2353,6 +2353,8 @@ options! { "disable various performance optimizations in trait solving"), disable_incr_comp_backend_caching: bool = (false, parse_bool, [TRACKED], "disable caching of compiled objects by the codegen backend during incremental compilation"), + disable_param_env_normalization_hack: bool = (false, parse_bool, [TRACKED], + "do not treat all aliases in the environment as rigid with `-Znext-solver`"), dual_proc_macros: bool = (false, parse_bool, [TRACKED], "load proc macros for both target and host, but only link to the target (default: no)"), dump_dep_graph: bool = (false, parse_bool, [UNTRACKED], diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index db4f66db9e64f..72950846ae844 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -249,6 +249,25 @@ fn pred_known_to_hold_modulo_regions<'tcx>( } } +fn set_projection_term_to_non_rigid<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: impl IntoIterator>, +) -> impl Iterator> { + predicates.into_iter().map(move |clause| { + if let ty::ClauseKind::Projection(projection_pred) = clause.kind().skip_binder() { + clause + .kind() + .rebind(ty::ProjectionPredicate { + projection_term: projection_pred.projection_term, + term: ty::set_aliases_to_non_rigid(tcx, projection_pred.term).skip_norm_wip(), + }) + .upcast(tcx) + } else { + clause + } + }) +} + #[instrument(level = "debug", skip(tcx, elaborated_env))] fn do_normalize_predicates<'tcx>( tcx: TyCtxt<'tcx>, @@ -272,10 +291,36 @@ fn do_normalize_predicates<'tcx>( let span = cause.span; let infcx = tcx.infer_ctxt().ignoring_regions().build(TypingMode::non_body_analysis()); let ocx = ObligationCtxt::new_with_diagnostics(&infcx); + // FIXME: `elaborated_env` is not really rigid. We do this to be + // consistent with the old solver. + let elaborated_env = if tcx.next_trait_solver_globally() + && !tcx.disable_param_env_normalization_hack() + { + let elaborated_env = ty::set_aliases_to_rigid(tcx, elaborated_env); + let elaborated_env = set_projection_term_to_non_rigid(tcx, elaborated_env.caller_bounds()); + ty::ParamEnv::new(tcx.mk_clauses_from_iter(elaborated_env)) + } else { + elaborated_env + }; let predicates = ocx.normalize(&cause, elaborated_env, Unnormalized::new_wip(predicates)); - // FIXME: opaque types in param env might be in defining scope but we're - // using non body analysis for here. So the rigidness marker is wrong. - let predicates = ty::set_aliases_to_non_rigid(tcx, predicates).skip_norm_wip(); + let predicates = if tcx.next_trait_solver_globally() { + if !tcx.disable_param_env_normalization_hack() { + let predicates: Vec<_> = set_projection_term_to_non_rigid(tcx, predicates).collect(); + // FIXME(type_alias_impl_trait): opaque types in param env might be + // in defining scope but we're using non body analysis here. + // So the rigidness marker is wrong. + ty::set_opaques_to_non_rigid(tcx, predicates).skip_norm_wip() + } else { + // Param env is used in different typing modes but itself + // is normalized in `non_body_analysis`. + // That not only makes the rigidness of opaques types wrong, + // other aliases can be indirectly affected as well. + // So we conservatively set everything to be non-rigid. + ty::set_aliases_to_non_rigid(tcx, predicates).skip_norm_wip() + } + } else { + predicates + }; let errors = ocx.evaluate_obligations_error_on_ambiguity(); if !errors.is_empty() { diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index 8b1401c0609f9..14fde5e399994 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -555,20 +555,67 @@ where } } +/// This function should ideally only be used if either the `TypingMode` +/// or the `ParamEnv` differs from the environment the aliases were normalized +/// in. +/// +/// Cases outside these two should consider whether the problem can be +/// fixed at the root instead. pub fn set_aliases_to_non_rigid(cx: I, value: T) -> ty::Unnormalized where T: TypeFoldable, { - if !value.has_rigid_aliases() { - return ty::Unnormalized::new(value); + let folded = set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::AllToNonRigid); + ty::Unnormalized::new(folded) +} + +pub fn set_opaques_to_non_rigid(cx: I, value: T) -> ty::Unnormalized +where + T: TypeFoldable, +{ + let folded = set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::OpaqueToNonRigid); + ty::Unnormalized::new(folded) +} + +pub fn set_aliases_to_rigid(cx: I, value: T) -> T +where + T: TypeFoldable, +{ + set_aliases_rigidness_with_mode(cx, value, RigidnessFoldMode::AllToRigid) +} + +fn set_aliases_rigidness_with_mode(cx: I, value: T, mode: RigidnessFoldMode) -> T +where + T: TypeFoldable, +{ + if !mode.needs_change(&value) { + return value; } - let mut folder = RigidnessFolder { cx }; - ty::Unnormalized::new(value.fold_with(&mut folder)) + let mut folder = RigidnessFolder { cx, mode }; + value.fold_with(&mut folder) +} + +enum RigidnessFoldMode { + AllToNonRigid, + AllToRigid, + OpaqueToNonRigid, +} + +impl RigidnessFoldMode { + fn needs_change>(&self, v: &T) -> bool { + match self { + RigidnessFoldMode::AllToRigid => v.has_non_rigid_aliases(), + RigidnessFoldMode::AllToNonRigid => v.has_rigid_aliases(), + RigidnessFoldMode::OpaqueToNonRigid => v.has_rigid_aliases() && v.has_opaque_types(), + } + } } +// Set aliases to be rigid or non-rigid according to the mode. struct RigidnessFolder { cx: I, + mode: RigidnessFoldMode, } impl TypeFolder for RigidnessFolder { @@ -578,42 +625,66 @@ impl TypeFolder for RigidnessFolder { } fn fold_binder>(&mut self, t: ty::Binder) -> ty::Binder { - if t.has_rigid_aliases() { t.super_fold_with(self) } else { t } + if self.mode.needs_change(&t) { t.super_fold_with(self) } else { t } } fn fold_ty(&mut self, t: I::Ty) -> I::Ty { - if !t.has_rigid_aliases() { + if !self.mode.needs_change(&t) { return t; } match t.kind() { - ty::Alias(ty::IsRigid::Yes, alias_ty) => { + ty::Alias(is_rigid, alias_ty) => { let alias_ty = alias_ty.fold_with(self); - I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty) + match self.mode { + RigidnessFoldMode::AllToRigid => { + I::Ty::new_alias(self.cx(), ty::IsRigid::Yes, alias_ty) + } + RigidnessFoldMode::AllToNonRigid => { + I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty) + } + RigidnessFoldMode::OpaqueToNonRigid => { + if let ty::AliasTyKind::Opaque { .. } = alias_ty.kind { + I::Ty::new_alias(self.cx(), ty::IsRigid::No, alias_ty) + } else { + I::Ty::new_alias(self.cx(), is_rigid, alias_ty) + } + } + } } _ => t.super_fold_with(self), } } fn fold_const(&mut self, c: I::Const) -> I::Const { - if !c.has_rigid_aliases() { + if !self.mode.needs_change(&c) { return c; } match c.kind() { - ty::ConstKind::Alias(ty::IsRigid::Yes, alias_const) => { + ty::ConstKind::Alias(is_rigid, alias_const) => { let alias_const = alias_const.fold_with(self); - I::Const::new_alias(self.cx, ty::IsRigid::No, alias_const) + match self.mode { + RigidnessFoldMode::AllToRigid => { + I::Const::new_alias(self.cx, ty::IsRigid::Yes, alias_const) + } + RigidnessFoldMode::AllToNonRigid => { + I::Const::new_alias(self.cx(), ty::IsRigid::No, alias_const) + } + RigidnessFoldMode::OpaqueToNonRigid => { + I::Const::new_alias(self.cx(), is_rigid, alias_const) + } + } } _ => c.super_fold_with(self), } } fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { - if p.has_rigid_aliases() { p.super_fold_with(self) } else { p } + if self.mode.needs_change(&p) { p.super_fold_with(self) } else { p } } fn fold_clauses(&mut self, c: I::Clauses) -> I::Clauses { - if c.has_rigid_aliases() { c.super_fold_with(self) } else { c } + if self.mode.needs_change(&c) { c.super_fold_with(self) } else { c } } } diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr index 2351b18fdfc90..f136f5ffc82b4 100644 --- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.current.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:36:5 + --> $DIR/false-positive-predicate-entailment-error.rs:41:5 | LL | / fn autobatch(self) -> impl Trait ... | @@ -8,7 +8,7 @@ LL | | F: Callback, | |_______________________________________^ the trait `MyFn` is not implemented for `F` | note: required for `F` to implement `Callback` - --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 | LL | impl> Callback for F { | ------- ^^^^^^^^^^^ ^ @@ -20,7 +20,7 @@ LL | F: Callback + MyFn, | +++++++++++ error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:36:5 + --> $DIR/false-positive-predicate-entailment-error.rs:41:5 | LL | / fn autobatch(self) -> impl Trait ... | @@ -29,7 +29,7 @@ LL | | F: Callback, | |_______________________________________^ the trait `MyFn` is not implemented for `F` | note: required for `F` to implement `Callback` - --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 | LL | impl> Callback for F { | ------- ^^^^^^^^^^^ ^ @@ -42,20 +42,20 @@ LL | F: Callback + MyFn, | +++++++++++ error[E0277]: the trait bound `F: Callback` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:42:12 + --> $DIR/false-positive-predicate-entailment-error.rs:48:12 | LL | F: Callback, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn` is not implemented for `F` | note: required for `F` to implement `Callback` - --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 | LL | impl> Callback for F { | ------- ^^^^^^^^^^^ ^ | | | unsatisfied trait bound introduced here note: the requirement `F: Callback` appears on the `impl`'s method `autobatch` but not on the corresponding trait's method - --> $DIR/false-positive-predicate-entailment-error.rs:25:8 + --> $DIR/false-positive-predicate-entailment-error.rs:30:8 | LL | trait ChannelSender { | ------------- in this trait @@ -68,13 +68,13 @@ LL | F: Callback + MyFn, | +++++++++++ error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:36:30 + --> $DIR/false-positive-predicate-entailment-error.rs:41:30 | LL | fn autobatch(self) -> impl Trait | ^^^^^^^^^^ the trait `MyFn` is not implemented for `F` | note: required for `F` to implement `Callback` - --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 | LL | impl> Callback for F { | ------- ^^^^^^^^^^^ ^ @@ -82,13 +82,13 @@ LL | impl> Callback for F { | unsatisfied trait bound introduced here error[E0277]: the trait bound `F: Callback` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:27:12 + --> $DIR/false-positive-predicate-entailment-error.rs:32:12 | LL | F: Callback; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn` is not implemented for `F` | note: required for `F` to implement `Callback` - --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 | LL | impl> Callback for F { | ------- ^^^^^^^^^^^ ^ @@ -96,7 +96,7 @@ LL | impl> Callback for F { | unsatisfied trait bound introduced here error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:36:5 + --> $DIR/false-positive-predicate-entailment-error.rs:41:5 | LL | / fn autobatch(self) -> impl Trait ... | @@ -105,7 +105,7 @@ LL | | F: Callback, | |_______________________________________^ the trait `MyFn` is not implemented for `F` | note: required for `F` to implement `Callback` - --> $DIR/false-positive-predicate-entailment-error.rs:14:21 + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 | LL | impl> Callback for F { | ------- ^^^^^^^^^^^ ^ @@ -118,13 +118,13 @@ LL | F: Callback + MyFn, | +++++++++++ error[E0277]: the trait bound `F: MyFn` is not satisfied - --> $DIR/false-positive-predicate-entailment-error.rs:42:12 + --> $DIR/false-positive-predicate-entailment-error.rs:48:12 | LL | F: Callback, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `MyFn` is not implemented for `F` | note: required by a bound in `Callback` - --> $DIR/false-positive-predicate-entailment-error.rs:10:20 + --> $DIR/false-positive-predicate-entailment-error.rs:15:20 | LL | trait Callback: MyFn { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Callback` diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.next.stderr b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.next.stderr new file mode 100644 index 0000000000000..90569d9aecd4b --- /dev/null +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.next.stderr @@ -0,0 +1,107 @@ +error[E0277]: the trait bound `F: MyFn` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:41:5 + | +LL | / fn autobatch(self) -> impl Trait +... | +LL | | where +LL | | F: Callback, + | |_______________________________________^ the trait `MyFn` is not implemented for `F` + | +note: required for `F` to implement `Callback` + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 + | +LL | impl> Callback for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here +help: consider further restricting type parameter `F` with trait `MyFn` + | +LL | F: Callback + MyFn, + | +++++++++++ + +error[E0277]: the trait bound `F: MyFn` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:41:5 + | +LL | / fn autobatch(self) -> impl Trait +... | +LL | | where +LL | | F: Callback, + | |_______________________________________^ the trait `MyFn` is not implemented for `F` + | +note: required for `F` to implement `Callback` + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 + | +LL | impl> Callback for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider further restricting type parameter `F` with trait `MyFn` + | +LL | F: Callback + MyFn, + | +++++++++++ + +error[E0277]: the trait bound `F: MyFn` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:41:5 + | +LL | / fn autobatch(self) -> impl Trait +... | +LL | | where +LL | | F: Callback, + | |_______________________________________^ the trait `MyFn` is not implemented for `F` + | +note: required for `F` to implement `Callback` + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 + | +LL | impl> Callback for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` +help: consider further restricting type parameter `F` with trait `MyFn` + | +LL | F: Callback + MyFn, + | +++++++++++ + +error[E0277]: the trait bound `F: MyFn` is not satisfied + | +note: required for `F` to implement `Callback` + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 + | +LL | impl> Callback for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `F: MyFn` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:41:30 + | +LL | fn autobatch(self) -> impl Trait + | ^^^^^^^^^^ the trait `MyFn` is not implemented for `F` + | +note: required for `F` to implement `Callback` + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 + | +LL | impl> Callback for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + +error[E0277]: the trait bound `F: MyFn` is not satisfied + --> $DIR/false-positive-predicate-entailment-error.rs:41:30 + | +LL | fn autobatch(self) -> impl Trait + | ^^^^^^^^^^ the trait `MyFn` is not implemented for `F` + | +note: required for `F` to implement `Callback` + --> $DIR/false-positive-predicate-entailment-error.rs:19:21 + | +LL | impl> Callback for F { + | ------- ^^^^^^^^^^^ ^ + | | + | unsatisfied trait bound introduced here + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs index cbe6c32b8901c..044765233f56d 100644 --- a/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs +++ b/tests/ui/impl-trait/in-trait/false-positive-predicate-entailment-error.rs @@ -1,7 +1,12 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] check-pass + +// This was fixed by lazy norm of param env with the next solver. +// But it regressed again as we switched back to be consistent with +// the old solver. See #158643. + +//[next]~^^^^^^^^ ERROR: the trait bound `F: MyFn` is not satisfied trait MyFn { type Output; @@ -34,10 +39,11 @@ impl ChannelSender for Sender { type CallbackArg = i32; fn autobatch(self) -> impl Trait - //[current]~^ ERROR the trait bound `F: MyFn` is not satisfied - //[current]~| ERROR the trait bound `F: MyFn` is not satisfied - //[current]~| ERROR the trait bound `F: MyFn` is not satisfied - //[current]~| ERROR the trait bound `F: MyFn` is not satisfied + //~^ ERROR the trait bound `F: MyFn` is not satisfied + //~| ERROR the trait bound `F: MyFn` is not satisfied + //~| ERROR the trait bound `F: MyFn` is not satisfied + //~| ERROR the trait bound `F: MyFn` is not satisfied + //[next]~| ERROR the trait bound `F: MyFn` is not satisfied where F: Callback, //[current]~^ ERROR the trait bound `F: MyFn` is not satisfied diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-1.rs b/tests/ui/traits/next-solver/normalize/normalize-param-env-1.rs index 6f5fdd561f4e4..ecac4f9dfbbc5 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-1.rs +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-1.rs @@ -1,6 +1,9 @@ -//@ check-pass //@ compile-flags: -Znext-solver -// Issue 108933 + +// Regression test for #108933. +// This was fixed by lazy norm of param env with the next solver. +// But it regressed again as we switched back to be consistent with +// the old solver. See #158643. trait Add { type Sum; @@ -24,6 +27,7 @@ where } fn g() +//~^ ERROR: the trait bound `T: Trait<()>` is not satisfied where T: Trait, >::Output: Sized, diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-1.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-1.stderr new file mode 100644 index 0000000000000..05377b998d2d7 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-1.stderr @@ -0,0 +1,13 @@ +error[E0277]: the trait bound `T: Trait<()>` is not satisfied + --> $DIR/normalize-param-env-1.rs:29:1 + | +LL | / fn g() +LL | | +LL | | where +LL | | T: Trait, +LL | | >::Output: Sized, + | |____________________________________^ the trait `Trait<()>` is not implemented for `T` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr index 553a2157074f3..f5ff41fc17aae 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-2.stderr @@ -1,88 +1,37 @@ -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc == _` - --> $DIR/normalize-param-env-2.rs:22:5 +error[E0276]: impl has stricter requirements than trait + --> $DIR/normalize-param-env-2.rs:24:22 | LL | / fn f() LL | | where LL | | Self::Assoc: A, - | |__________________________^ - -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc == _` - --> $DIR/normalize-param-env-2.rs:24:22 - | -LL | Self::Assoc: A, - | ^^^^ + | |__________________________- definition of `f` from trait +... +LL | Self::Assoc: A, + | ^^^^ impl has extra requirement `<() as A>::Assoc: A` -error[E0283]: type annotations needed +error[E0277]: the trait bound `<() as A>::Assoc: A` is not satisfied --> $DIR/normalize-param-env-2.rs:24:22 | LL | Self::Assoc: A, - | ^^^^ cannot infer type + | ^^^^ the trait `A` is not implemented for `<() as A>::Assoc` | -note: multiple `impl`s or `where` clauses satisfying `_: A` found +help: the trait `A` is implemented for `()` --> $DIR/normalize-param-env-2.rs:19:1 | LL | impl A for () { | ^^^^^^^^^^^^^^^^^^^ -... -LL | Self::Assoc: A, - | ^^^^ -note: the requirement `_: A` appears on the `impl`'s associated function `f` but not on the corresponding trait's associated function - --> $DIR/normalize-param-env-2.rs:12:8 - | -LL | trait A { - | - in this trait -... -LL | fn f() - | ^ this trait's associated function doesn't have the requirement `_: A` -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc == _` - --> $DIR/normalize-param-env-2.rs:22:5 - | -LL | / fn f() -LL | | where -LL | | Self::Assoc: A, - | |__________________________^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc: A` - --> $DIR/normalize-param-env-2.rs:24:22 - | -LL | Self::Assoc: A, - | ^^^^ - -error[E0275]: overflow evaluating whether `<() as A>::Assoc` is well-formed - --> $DIR/normalize-param-env-2.rs:24:22 - | -LL | Self::Assoc: A, - | ^^^^ - -error[E0275]: overflow evaluating the requirement `(): A` - --> $DIR/normalize-param-env-2.rs:27:10 +error[E0277]: the trait bound `<() as A>::Assoc: A` is not satisfied + --> $DIR/normalize-param-env-2.rs:27:18 | LL | <() as A>::f(); - | ^^ - -error[E0275]: overflow evaluating the requirement `<() as A>::Assoc == _` - --> $DIR/normalize-param-env-2.rs:27:9 - | -LL | <() as A>::f(); - | ^^^^^^^^^^^^^^^^^ - -error[E0283]: type annotations needed - --> $DIR/normalize-param-env-2.rs:27:9 + | ^ the trait `A` is not implemented for `<() as A>::Assoc` | -LL | <() as A>::f(); - | ^^^^^^^^^^^^^^^^^ cannot infer type - | -note: multiple `impl`s or `where` clauses satisfying `_: A` found +help: the trait `A` is implemented for `()` --> $DIR/normalize-param-env-2.rs:19:1 | LL | impl A for () { | ^^^^^^^^^^^^^^^^^^^ -... -LL | Self::Assoc: A, - | ^^^^ note: required by a bound in `A::f` --> $DIR/normalize-param-env-2.rs:14:22 | @@ -92,7 +41,7 @@ LL | where LL | Self::Assoc: A, | ^^^^ required by this bound in `A::f` -error: aborting due to 9 previous errors +error: aborting due to 3 previous errors -Some errors have detailed explanations: E0275, E0283. -For more information about an error, try `rustc --explain E0275`. +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-3.rs b/tests/ui/traits/next-solver/normalize/normalize-param-env-3.rs index 9d895df5d3ee4..5bfd25318f527 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-3.rs +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-3.rs @@ -1,6 +1,9 @@ -//@ check-pass //@ compile-flags: -Znext-solver -// Issue 100177 + +// Regression test for #100177. +// This was fixed by lazy norm of param env with the next solver. +// But it regressed again as we switched back to be consistent with +// the old solver. See #158643. trait GenericTrait {} @@ -20,6 +23,8 @@ impl Sender for T { type Msg = (); fn send() + //~^ ERROR: the trait bound `C: Channel<()>` is not satisfied + //~| ERROR: the trait bound `C: Channel<()>` is not satisfied where C: Channel, { diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-3.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-3.stderr new file mode 100644 index 0000000000000..3c70f1221aa0e --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-3.stderr @@ -0,0 +1,25 @@ +error[E0277]: the trait bound `C: Channel<()>` is not satisfied + --> $DIR/normalize-param-env-3.rs:25:5 + | +LL | / fn send() +LL | | +LL | | +LL | | where +LL | | C: Channel, + | |______________________________^ the trait `Channel<()>` is not implemented for `C` + +error[E0277]: the trait bound `C: Channel<()>` is not satisfied + --> $DIR/normalize-param-env-3.rs:25:5 + | +LL | / fn send() +LL | | +LL | | +LL | | where +LL | | C: Channel, + | |______________________________^ the trait `Channel<()>` is not implemented for `C` + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr deleted file mode 100644 index aea394c6ec58a..0000000000000 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.next.stderr +++ /dev/null @@ -1,35 +0,0 @@ -error[E0275]: overflow evaluating the requirement `::Assoc == _` - --> $DIR/normalize-param-env-4.rs:17:1 - | -LL | / fn foo() -LL | | where -LL | | ::Assoc: Trait, - | |_______________________________^ - -error[E0275]: overflow evaluating the requirement `::Assoc: Trait` - --> $DIR/normalize-param-env-4.rs:19:26 - | -LL | ::Assoc: Trait, - | ^^^^^ - -error[E0275]: overflow evaluating whether `::Assoc` is well-formed - --> $DIR/normalize-param-env-4.rs:19:26 - | -LL | ::Assoc: Trait, - | ^^^^^ - -error[E0275]: overflow evaluating the requirement `T: Trait` - --> $DIR/normalize-param-env-4.rs:32:19 - | -LL | impls_trait::(); - | ^ - | -note: required by a bound in `impls_trait` - --> $DIR/normalize-param-env-4.rs:15:19 - | -LL | fn impls_trait() {} - | ^^^^^ required by this bound in `impls_trait` - -error: aborting due to 4 previous errors - -For more information about this error, try `rustc --explain E0275`. diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.rs b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.rs index ed7f6899bdee6..9a4191bcc8b78 100644 --- a/tests/ui/traits/next-solver/normalize/normalize-param-env-4.rs +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-4.rs @@ -1,8 +1,10 @@ //@ revisions: current next //@ ignore-compare-mode-next-solver (explicit revisions) //@[next] compile-flags: -Znext-solver -//@[next] known-bug: #92505 -//@[current] check-pass +//@ check-pass + +// Issue #92505. +// Now that we eager norm param env in the next solver, it compiles. trait Trait { type Assoc; diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-5.rs b/tests/ui/traits/next-solver/normalize/normalize-param-env-5.rs new file mode 100644 index 0000000000000..3b9dd9e230940 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-5.rs @@ -0,0 +1,39 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#246 +// Fixed by eager norm and marking param env as rigid. + +struct MarkedStruct; +pub trait MarkerTrait {} +impl MarkerTrait for MarkedStruct {} + +struct ChainStruct; +trait ChainTrait {} +impl ChainTrait for ChainStruct where MarkedStruct: MarkerTrait {} + +pub struct FooStruct; +pub trait FooTrait { + type Output; +} +pub struct FooOut; +impl FooTrait for FooStruct +where + ChainStruct: ChainTrait, +{ + type Output = FooOut; +} +type FooOutAlias = ::Output; + +pub trait Trait { + type Output; +} + +pub fn foo() +where + FooOut: Trait, + >::Output: MarkerTrait, +{ +} + +fn main() {} diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-6.rs b/tests/ui/traits/next-solver/normalize/normalize-param-env-6.rs new file mode 100644 index 0000000000000..5756b76d7131c --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-6.rs @@ -0,0 +1,70 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#246 +// Fixed by eager norm and marking param env as rigid. + +#![feature(rustc_attrs)] +#![rustc_no_implicit_bounds] +// makes it work: +// #![recursion_limit = "512"] + +pub trait Trait { + type K; +} + +// two different types +pub struct T1; +pub struct T2; + +// a type that's easy to make really large +pub struct Growing(T); +// for which proving that it implements foo grows with that size +pub trait Foo { + type Output; +} +impl Foo for Growing { + type Output = ::Output; +} +impl Foo for T2 { + type Output = T1; +} +// a simple way to do this proof +pub type Eval = ::Output; + +// a trivial trait bound for one of the types +pub trait Trivial {} +impl Trivial for T1 {} + +// and one for which one of the possible impls diverges +pub trait Diverges {} +impl Diverges for I {} +impl Diverges for I +where + R: Trivial, // move this bound down + Growing: Diverges, +{ +} + +// Our large type +type LargeToEval = Growing>>>; + +impl Trait for K +where + (): Diverges, + T1: Trivial, + Eval: Trivial, +{ + type K = K; +} + +fn foo() +where + Eval: Trivial, + Eval<::K>: Trivial, +{ +} + +fn main() { + foo() +} diff --git a/tests/ui/traits/next-solver/normalize/normalize-param-env-7.rs b/tests/ui/traits/next-solver/normalize/normalize-param-env-7.rs new file mode 100644 index 0000000000000..8ba7b389f23c6 --- /dev/null +++ b/tests/ui/traits/next-solver/normalize/normalize-param-env-7.rs @@ -0,0 +1,655 @@ +//@ compile-flags: -Znext-solver +//@ check-pass + +// Regression test for trait-system-refactor-initiative#246 +// There're some smaller intermediate minimizations in the issue comments +// but they may not catch the same problem as in the full version. +// +// Fixed by eager norm and marking param env as rigid. See #158643. + +use std::ops::{BitAnd, BitOr, BitXor, Neg, Not, Shl, Shr}; +pub struct B0; + +impl Clone for B0 { + fn clone(&self) -> B0 { + loop {} + } +} + +impl Copy for B0 {} + +impl Default for B0 { + fn default() -> B0 { + loop {} + } +} + +pub struct B1; + +impl Clone for B1 { + fn clone(&self) -> B1 { + loop {} + } +} + +impl Copy for B1 {} + +impl Default for B1 { + fn default() -> B1 { + loop {} + } +} + +impl Bit for B0 { + const U8: u8 = 0; + const BOOL: bool = false; +} +impl Bit for B1 { + const U8: u8 = 1; + const BOOL: bool = true; +} + +pub type U0 = UTerm; +pub type U1 = UInt; + +pub type U2 = UInt, B0>; + +pub trait NonZero {} + +pub trait Ord {} +pub trait Bit: Copy + Default + 'static { + const U8: u8; + const BOOL: bool; +} +pub trait Unsigned: Copy + Default + 'static { +} + +pub type Shleft = >::Output; + +pub type Sum = >::Output; +pub type Diff = >::Output; +pub type Prod = >::Output; +pub type Quot = >::Output; + +pub type Gcf = >::Output; +pub type Add1 = >::Output; +pub type Sub1 = >::Output; + +pub type Compare = >::Output; +pub type Length = ::Output; + +pub type Minimum = >::Output; +pub type Maximum = >::Output; + +pub trait Trim { + type Output; +} +pub type TrimOut = ::Output; +pub trait TrimTrailingZeros { + type Output; +} + +pub trait Invert { + type Output; +} + +pub trait PrivateInvert { + type Output; +} +pub type PrivateInvertOut = >::Output; +pub struct InvertedUTerm; +pub struct InvertedUInt { + msb: IU, + lsb: B, +} + +pub trait PrivateSub { + type Output; +} +pub type PrivateSubOut = >::Output; + +pub trait InvertedUnsigned {} +impl InvertedUnsigned for InvertedUTerm {} +impl InvertedUnsigned for InvertedUInt {} + +impl Invert for UInt +where + U: PrivateInvert>, +{ + type Output = PrivateInvertOut>; +} +impl PrivateInvert for UTerm { + type Output = IU; +} +impl PrivateInvert for UInt +where + U: PrivateInvert>, +{ + type Output = PrivateInvertOut>; +} +impl Invert for InvertedUTerm { + type Output = UTerm; +} +impl Invert for InvertedUInt +where + IU: PrivateInvert>, +{ + type Output = >>::Output; +} +impl PrivateInvert for InvertedUTerm { + type Output = U; +} +impl PrivateInvert for InvertedUInt +where + IU: PrivateInvert>, +{ + type Output = >>::Output; +} +impl TrimTrailingZeros for InvertedUTerm { + type Output = InvertedUTerm; +} +impl TrimTrailingZeros for InvertedUInt { + type Output = Self; +} +impl TrimTrailingZeros for InvertedUInt +where + IU: TrimTrailingZeros, +{ + type Output = ::Output; +} +impl Trim for U +where + U: Invert, + ::Output: TrimTrailingZeros, + <::Output as TrimTrailingZeros>::Output: Invert, +{ + type Output = <<::Output as TrimTrailingZeros>::Output as Invert>::Output; +} +pub trait PrivateCmp { + type Output; +} +pub type PrivateCmpOut = >::Output; +pub trait PrivateSetBit { + type Output; +} +pub type PrivateSetBitOut = >::Output; +pub trait PrivateDiv { + type Quotient; + type Remainder; +} +pub type PrivateDivQuot = <() as PrivateDiv>::Quotient; +pub type PrivateDivRem = <() as PrivateDiv>::Remainder; +pub trait PrivateDivIf { + type Quotient; + type Remainder; +} +pub type PrivateDivIfQuot = + <() as PrivateDivIf>::Quotient; +pub type PrivateDivIfRem = + <() as PrivateDivIf>::Remainder; + +pub trait PrivateMin { + type Output; +} +pub type PrivateMinOut = >::Output; +pub trait PrivateMax { + type Output; +} +pub type PrivateMaxOut = >::Output; + +pub trait Cmp { + type Output; +} + +pub trait Len { + type Output; +} + +pub trait Min { + type Output; +} +pub trait Max { + type Output; +} + +pub trait Gcd { + type Output; +} + +pub struct UTerm; + +impl Clone for UTerm { + fn clone(&self) -> UTerm { + loop {} + } +} + +impl Copy for UTerm {} + +impl Default for UTerm { + fn default() -> UTerm { + loop {} + } +} + +impl Unsigned for UTerm { +} +pub struct UInt { + pub(crate) msb: U, + pub(crate) lsb: B, +} + +impl Clone for UInt { + fn clone(&self) -> UInt { + loop {} + } +} + +impl Copy for UInt {} + +impl Default for UInt { + fn default() -> UInt { + loop {} + } +} + +impl Unsigned for UInt { +} +impl NonZero for UInt {} + +impl Len for UTerm { + type Output = U0; +} +impl Len for UInt +where + U: Len, + Length: Add, + Add1>: Unsigned, +{ + type Output = Add1>; +} + +impl Add for UTerm { + type Output = UInt; + fn add(self, _: B1) -> Self::Output { + loop {} + } +} + +impl Add for UInt +where + U: Add, + Add1: Unsigned, +{ + type Output = UInt, B0>; + fn add(self, _: B1) -> Self::Output { + loop {} + } +} +impl Add for UTerm { + type Output = U; + fn add(self, rhs: U) -> Self::Output { + loop {} + } +} + +impl Add> for UInt +where + Ul: Add, +{ + type Output = UInt, B1>; + fn add(self, rhs: UInt) -> Self::Output { + loop {} + } +} + +impl Sub for UInt { + type Output = UTerm; + fn sub(self, _: B1) -> Self::Output { + loop {} + } +} +impl Sub for UInt +where + U: Sub, + Sub1: Unsigned, +{ + type Output = UInt, B1>; + fn sub(self, _: B1) -> Self::Output { + loop {} + } +} + +impl Sub for UInt +where + UInt: PrivateSub, + PrivateSubOut, Ur>: Trim, +{ + type Output = TrimOut, Ur>>; + fn sub(self, rhs: Ur) -> Self::Output { + loop {} + } +} +impl PrivateSub for U { + type Output = U; +} + +impl PrivateSub> for UInt +where + Ul: PrivateSub, +{ + type Output = UInt, B0>; +} + +impl Shl for UInt { + type Output = UInt; + fn shl(self, _: UTerm) -> Self::Output { + loop {} + } +} + +impl Shl> for UInt +where + UInt: Sub, + UInt, B0>: Shl>>, +{ + type Output = Shleft, B0>, Sub1>>; + fn shl(self, rhs: UInt) -> Self::Output { + loop {} + } +} + +impl Mul for UTerm { + type Output = UTerm; + fn mul(self, _: U) -> Self::Output { + loop {} + } +} +impl Mul> for UInt +where + Ul: Mul>, +{ + type Output = UInt>, B0>; + fn mul(self, rhs: UInt) -> Self::Output { + loop {} + } +} +impl Mul> for UInt +where + Ul: Mul>, + UInt>, B0>: Add>, +{ + type Output = Sum>, B0>, UInt>; + fn mul(self, rhs: UInt) -> Self::Output { + loop {} + } +} + +impl Cmp> for UTerm { + type Output = Less; +} +impl Cmp> for UInt +where + Ul: PrivateCmp, +{ + type Output = PrivateCmpOut; +} +impl Cmp> for UInt +where + Ul: PrivateCmp, +{ + type Output = PrivateCmpOut; +} + +impl Cmp> for UInt +where + Ul: PrivateCmp, +{ + type Output = PrivateCmpOut; +} + +impl PrivateCmp, SoFar> for UInt +where + Ul: Unsigned, + Ur: Unsigned, + SoFar: Ord, + Ul: PrivateCmp, +{ + type Output = PrivateCmpOut; +} + +impl PrivateCmp, SoFar> for UTerm { + type Output = Less; +} + +impl PrivateCmp for UTerm { + type Output = SoFar; +} + +type Even = UInt; +type Odd = UInt; + +impl Gcd for U0 { + type Output = Y; +} + +impl Gcd> for Even +where + Xp: Gcd>, + Even: NonZero, +{ + type Output = Gcf>; +} +impl Gcd> for Odd +where + Odd: Max> + Min>, + Odd: Max>, + Maximum, Odd>: Sub, Odd>>, + Diff, Odd>, Minimum, Odd>>: Gcd, Odd>>, +{ + type Output = + Gcf, Odd>, Minimum, Odd>>, Minimum, Odd>>; +} + +pub trait GetBit { + type Output; +} + +pub type GetBitOut = >::Output; +impl GetBit for UInt { + type Output = Bn; +} +impl GetBit> for UInt +where + UInt: Copy + Sub, + Un: GetBit>>, +{ + type Output = GetBitOut>>; +} + +pub trait SetBit { + type Output; +} +pub type SetBitOut = >::Output; + +impl SetBit for N +where + N: PrivateSetBit, + PrivateSetBitOut: Trim, +{ + type Output = TrimOut>; +} + +impl PrivateSetBit for UTerm +where + U1: Shl, +{ + type Output = Shleft; +} + +impl Div> for UInt +where + UInt: Len, + Length>: Sub, + (): PrivateDiv, UInt, U0, U0, Sub1>>>, +{ + type Output = PrivateDivQuot, UInt, U0, U0, Sub1>>>; + fn div(self, rhs: UInt) -> Self::Output { + loop {} + } +} + +impl PrivateDiv for () +where + N: GetBit, + UInt>: Trim, + TrimOut>>: Cmp, + (): PrivateDivIf< + N, + D, + Q, + TrimOut>>, + I, + Compare>>, D>, + >, +{ + type Quotient = PrivateDivIfQuot< + N, + D, + Q, + TrimOut>>, + I, + Compare>>, D>, + >; + type Remainder = PrivateDivIfRem< + N, + D, + Q, + TrimOut>>, + I, + Compare>>, D>, + >; +} +impl PrivateDiv, I> for () +where + N: GetBit, + UInt, GetBitOut>: Cmp, + (): PrivateDivIf< + N, + D, + Q, + UInt, GetBitOut>, + I, + Compare, GetBitOut>, D>, + >, +{ + type Quotient = PrivateDivIfQuot< + N, + D, + Q, + UInt, GetBitOut>, + I, + Compare, GetBitOut>, D>, + >; + type Remainder = PrivateDivIfRem< + N, + D, + Q, + UInt, GetBitOut>, + I, + Compare, GetBitOut>, D>, + >; +} + +impl PrivateDivIf, Less> for () +where + UInt: Sub, + (): PrivateDiv>>, +{ + type Quotient = PrivateDivQuot>>; + type Remainder = PrivateDivRem>>; +} +impl PrivateDivIf, Equal> for () +where + UInt: Copy + Sub, + Q: SetBit, B1>, + (): PrivateDiv, B1>, U0, Sub1>>, +{ + type Quotient = PrivateDivQuot, B1>, U0, Sub1>>; + type Remainder = PrivateDivRem, B1>, U0, Sub1>>; +} + +impl PrivateDivIf for () { + type Quotient = Q; + type Remainder = R; +} +impl PrivateDivIf for () +where + Q: SetBit, +{ + type Quotient = SetBitOut; + type Remainder = U0; +} + +impl PrivateMin for UInt { + type Output = UInt; +} + +impl Min for UInt +where + U: Unsigned, + B: Bit, + Ur: Unsigned, + UInt: Cmp + PrivateMin, Ur>>, +{ + type Output = PrivateMinOut, Ur, Compare, Ur>>; +} + +impl PrivateMax for UInt { + type Output = UInt; +} + +impl Max for UInt +where + U: Unsigned, + B: Bit, + Ur: Unsigned, + UInt: Cmp + PrivateMax, Ur>>, +{ + type Output = PrivateMaxOut, Ur, Compare, Ur>>; +} + +pub struct Greater; + +pub struct Less; + +pub struct Equal; + +impl Ord for Greater {} + +impl Ord for Equal {} + +use std::ops::{Add, Div, Mul, Rem, Sub}; + +pub trait EncodingSize { + type EncodedPolynomialSize; +} +impl EncodingSize for D +where + D: Mul + Gcd, + Prod: Div>, + Quot, Gcf>: Div, +{ + type EncodedPolynomialSize = D; +} + +pub fn foo

() +where + U2: Mul

, + Prod: Add + Div

, + ::EncodedPolynomialSize: Mul

, + Sum, U0>: Sub, Output = U0>, +{ +} + +fn main() {} diff --git a/tests/ui/typeck/issue-116864.current.stderr b/tests/ui/typeck/issue-116864.current.stderr new file mode 100644 index 0000000000000..b3fbf6b0e570f --- /dev/null +++ b/tests/ui/typeck/issue-116864.current.stderr @@ -0,0 +1,108 @@ +error[E0277]: expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + --> $DIR/issue-116864.rs:28:1 + | +LL | / async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) +... | +LL | | where +LL | | BAZ: Baz, + | |__________________________^ expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + | + = note: expected a closure with signature `for<'any> fn(&'any i32)` + found a closure with signature `fn(&::Param)` +note: required for `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` to implement `for<'any> FnMutFut<&'any i32, ()>` + --> $DIR/issue-116864.rs:20:20 + | +LL | impl FnMutFut for F + | ^^^^^^^^^^^^^^ ^ +LL | where +LL | F: FnMut(P) -> FUT, + | --------------- unsatisfied trait bound introduced here + +error[E0277]: expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + --> $DIR/issue-116864.rs:28:81 + | +LL | async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) + | ^ expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + | + = note: expected a closure with signature `for<'any> fn(&'any i32)` + found a closure with signature `fn(&::Param)` +note: required for `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` to implement `for<'any> FnMutFut<&'any i32, ()>` + --> $DIR/issue-116864.rs:20:20 + | +LL | impl FnMutFut for F + | ^^^^^^^^^^^^^^ ^ +LL | where +LL | F: FnMut(P) -> FUT, + | --------------- unsatisfied trait bound introduced here +note: required by a bound in `foo` + --> $DIR/issue-116864.rs:28:40 + | +LL | async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` + +error[E0277]: expected an `FnMut(&i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + --> $DIR/issue-116864.rs:36:5 + | +LL | cb(&1i32).await; + | ^^^^^^^^^ expected an `FnMut(&i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + | + = note: expected a closure with signature `fn(&i32)` + found a closure with signature `fn(&::Param)` +note: required for `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` to implement `FnMutFut<&i32, ()>` + --> $DIR/issue-116864.rs:20:20 + | +LL | impl FnMutFut for F + | ^^^^^^^^^^^^^^ ^ +LL | where +LL | F: FnMut(P) -> FUT, + | --------------- unsatisfied trait bound introduced here + +error[E0308]: mismatched types + --> $DIR/issue-116864.rs:36:8 + | +LL | cb(&1i32).await; + | -- ^^^^^ expected `&::Param`, found `&i32` + | | + | arguments to this function are incorrect + | + = note: expected reference `&::Param` + found reference `&i32` + = help: consider constraining the associated type `::Param` to `i32` + = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html +note: type parameter defined here + --> $DIR/issue-116864.rs:28:35 + | +LL | async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: call `Into::into` on this expression to convert `&i32` into `&::Param` + | +LL | cb((&1i32).into()).await; + | + ++++++++ + +error[E0277]: expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + --> $DIR/issue-116864.rs:28:81 + | +LL | async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) + | ^ expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + | + = note: expected a closure with signature `for<'any> fn(&'any i32)` + found a closure with signature `fn(&::Param)` +note: required for `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` to implement `for<'any> FnMutFut<&'any i32, ()>` + --> $DIR/issue-116864.rs:20:20 + | +LL | impl FnMutFut for F + | ^^^^^^^^^^^^^^ ^ +LL | where +LL | F: FnMut(P) -> FUT, + | --------------- unsatisfied trait bound introduced here +note: required by a bound in `foo` + --> $DIR/issue-116864.rs:28:40 + | +LL | async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `foo` + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0277, E0308. +For more information about an error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/issue-116864.next.stderr b/tests/ui/typeck/issue-116864.next.stderr new file mode 100644 index 0000000000000..e7d951dcff260 --- /dev/null +++ b/tests/ui/typeck/issue-116864.next.stderr @@ -0,0 +1,23 @@ +error[E0277]: expected an `FnOnce(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + --> $DIR/issue-116864.rs:28:1 + | +LL | / async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) +... | +LL | | where +LL | | BAZ: Baz, + | |__________________________^ expected an `FnOnce(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + | + = note: expected a closure with signature `for<'any> fn(&'any i32)` + found a closure with signature `fn(&::Param)` +note: required for `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` to implement `for<'any> FnMutFut<&'any i32, ()>` + --> $DIR/issue-116864.rs:20:20 + | +LL | impl FnMutFut for F + | ^^^^^^^^^^^^^^ ^ +LL | where +LL | F: FnMut(P) -> FUT, + | --- unsatisfied trait bound introduced here + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/typeck/issue-116864.rs b/tests/ui/typeck/issue-116864.rs index 6cbe56b2f926a..568b56bfc44ee 100644 --- a/tests/ui/typeck/issue-116864.rs +++ b/tests/ui/typeck/issue-116864.rs @@ -1,7 +1,12 @@ -//@ compile-flags: -Znext-solver -//@ check-pass +//@ revisions: current next +//@[next] compile-flags: -Znext-solver //@ edition: 2021 +// This was fixed by lazy norm of param env with the next solver. +// But it regressed again as we switched back to be consistent with +// the old solver. See #158643. + + use std::future::Future; trait Baz { @@ -21,10 +26,16 @@ where } async fn foo(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>) +//[next]~^ ERROR: expected an `FnOnce(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` +//[current]~^^ ERROR: expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` +//[current]~| ERROR: expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` +//[current]~| ERROR: expected an `FnMut(&'any i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` where BAZ: Baz, { cb(&1i32).await; + //[current]~^ ERROR: expected an `FnMut(&i32)` closure, found `impl for<'any> FnMutFut<&'any BAZ::Param, ()>` + //[current]~| ERROR: mismatched types } fn main() {