From e44b11f6952659e7cb4e66ee3b5ff47bb7bc6c31 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sun, 7 Jan 2024 22:53:50 +0000 Subject: [PATCH 1/2] ~const trait or projection bounds do not imply non-const bounds --- compiler/rustc_hir_analysis/src/bounds.rs | 18 ---- .../src/collect/predicates_of.rs | 38 ++------ .../assoc-type-const-bound-usage.rs | 2 +- .../assoc-type-const-bound-usage.stderr | 16 ++-- .../const-fns-are-early-bound.rs | 86 +++++++++++++++++++ .../effects/minicore.rs | 17 ++-- .../effects/project.rs | 9 +- .../effects/project.stderr | 65 ++++++++++++++ .../trait-where-clause-const.stderr | 34 +++++--- .../unsatisfied-const-trait-bound.rs | 2 +- .../unsatisfied-const-trait-bound.stderr | 10 +-- 11 files changed, 214 insertions(+), 83 deletions(-) create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs create mode 100644 tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs index b6688e0ce29e0..b69f679880dbf 100644 --- a/compiler/rustc_hir_analysis/src/bounds.rs +++ b/compiler/rustc_hir_analysis/src/bounds.rs @@ -45,24 +45,6 @@ impl<'tcx> Bounds<'tcx> { polarity: ty::ImplPolarity, ) { self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - - // push a non-const (`host = true`) version of the bound if it is `~const`. - if tcx.features().effects - && let Some(host_effect_idx) = tcx.generics_of(trait_ref.def_id()).host_effect_index - && trait_ref.skip_binder().args.const_at(host_effect_idx) != tcx.consts.true_ - { - let generics = tcx.generics_of(trait_ref.def_id()); - let Some(host_index) = generics.host_effect_index else { return }; - let trait_ref = trait_ref.map_bound(|mut trait_ref| { - trait_ref.args = - tcx.mk_args_from_iter(trait_ref.args.iter().enumerate().map(|(n, arg)| { - if host_index == n { tcx.consts.true_.into() } else { arg } - })); - trait_ref - }); - - self.push_trait_bound_inner(tcx, trait_ref, span, polarity); - } } fn push_trait_bound_inner( diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 41520718aa8d1..ab9ed6ef98d9f 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -11,7 +11,7 @@ use rustc_hir::intravisit::{self, Visitor}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{GenericPredicates, ImplTraitInTraitData, ToPredicate}; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_span::{Span, DUMMY_SP}; /// Returns a list of all type predicates (explicit and implicit) for the definition with /// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus @@ -38,38 +38,12 @@ pub(super) fn predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredic // an obligation and instead be skipped. Otherwise we'd use // `tcx.def_span(def_id);` let span = rustc_span::DUMMY_SP; - let non_const_bound = if tcx.features().effects && tcx.has_attr(def_id, sym::const_trait) { - // when `Self` is a const trait, also add `Self: Trait<.., true>` as implied bound, - // because only implementing `Self: Trait<.., false>` is currently not possible. - Some(( - ty::TraitRef::new( - tcx, - def_id, - ty::GenericArgs::for_item(tcx, def_id, |param, _| { - if param.is_host_effect() { - tcx.consts.true_.into() - } else { - tcx.mk_param_from_def(param) - } - }), - ) - .to_predicate(tcx), + + result.predicates = + tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once(( + ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), span, - )) - } else { - None - }; - result.predicates = tcx.arena.alloc_from_iter( - result - .predicates - .iter() - .copied() - .chain(std::iter::once(( - ty::TraitRef::identity(tcx, def_id).to_predicate(tcx), - span, - ))) - .chain(non_const_bound), - ); + )))); } debug!("predicates_of(def_id={:?}) = {:?}", def_id, result); result diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs index f41c1051fceaa..16b717bc18131 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.rs @@ -9,7 +9,7 @@ trait Foo { } const fn foo() { - ::Assoc::foo(); + ::Assoc::foo(); } fn main() {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr index 1b88839984f4d..268e337ee93e6 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/assoc-type-const-bound-usage.stderr @@ -6,15 +6,17 @@ LL | type Assoc: ~const Foo; | = note: this item cannot have `~const` trait bounds -error[E0308]: mismatched types - --> $DIR/assoc-type-const-bound-usage.rs:12:5 +error[E0277]: the trait bound `T: Foo` is not satisfied + --> $DIR/assoc-type-const-bound-usage.rs:12:6 | -LL | ::Assoc::foo(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true` +LL | ::Assoc::foo(); + | ^ the trait `Foo` is not implemented for `T` | - = note: expected constant `host` - found constant `true` +help: consider further restricting this bound + | +LL | const fn foo() { + | +++++ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs new file mode 100644 index 0000000000000..f3480fcc9eed4 --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-fns-are-early-bound.rs @@ -0,0 +1,86 @@ +// check-pass + +#![crate_type = "lib"] +#![allow(internal_features)] +#![no_std] +#![no_core] +#![feature( + auto_traits, + const_trait_impl, + effects, + lang_items, + no_core, + staged_api, + unboxed_closures +)] +#![stable(feature = "minicore", since = "1.0.0")] + +fn test() { + fn is_const_fn(_: F) + where + F: const FnOnce<()>, + { + } + + const fn foo() {} + + is_const_fn(foo); +} + +/// ---------------------------------------------------------------------- /// +/// Const fn trait definitions + +#[const_trait] +#[lang = "fn"] +#[rustc_paren_sugar] +trait Fn: ~const FnMut { + extern "rust-call" fn call(&self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_mut"] +#[rustc_paren_sugar] +trait FnMut: ~const FnOnce { + extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output; +} + +#[const_trait] +#[lang = "fn_once"] +#[rustc_paren_sugar] +trait FnOnce { + #[lang = "fn_once_output"] + type Output; + + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +/// ---------------------------------------------------------------------- /// +/// All this other stuff needed for core. Unrelated to test. + +#[lang = "destruct"] +#[const_trait] +trait Destruct {} + +#[lang = "freeze"] +unsafe auto trait Freeze {} + +#[lang = "drop"] +#[const_trait] +trait Drop { + fn drop(&mut self); +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[lang = "tuple_trait"] +trait Tuple {} + +#[lang = "receiver"] +trait Receiver {} + +impl Receiver for &T {} + +impl Receiver for &mut T {} diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs index 59fb48e794cc3..84d9bcd7ac9f0 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs @@ -40,7 +40,7 @@ const fn bar() { #[lang = "Try"] #[const_trait] -trait Try: FromResidual { +trait Try: FromResidual { type Output; type Residual; @@ -53,7 +53,7 @@ trait Try: FromResidual { // FIXME // #[const_trait] -trait FromResidual::Residual> { +trait FromResidual::Residual> { #[lang = "from_residual"] fn from_residual(residual: R) -> Self; } @@ -519,9 +519,14 @@ extern "rust-intrinsic" { called_in_const: F, called_at_rt: G, ) -> RET - /* where clauses enforced by built-in method confirmation: where - F: const FnOnce, - G: FnOnce, - */; + F: const FnOnce, + G: FnOnce; +} + +fn test_const_eval_select() { + const fn const_fn() {} + fn rt_fn() {} + + unsafe { const_eval_select((), const_fn, rt_fn); } } diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs index b30d7743edfc4..e22eed3e0ef57 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs @@ -1,7 +1,12 @@ -// check-pass +// known-bug: #110395 +// FIXME: effects + #![feature(const_trait_impl, effects)] -pub trait Owo::T> {} +// This fails because `~const Uwu` doesn't imply (non-const) `Uwu`. + +// FIXME: #[const_trait] +pub trait Owo::T> {} #[const_trait] pub trait Uwu: Owo { diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr new file mode 100644 index 0000000000000..eac3ee9e4e22b --- /dev/null +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.stderr @@ -0,0 +1,65 @@ +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:12:1 + | +LL | pub trait Uwu: Owo { + | ^^^^^^^^^^^^^^^^^^ the trait `Uwu` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:12:1 + | +LL | / pub trait Uwu: Owo { +LL | | type T; +LL | | } + | |_^ the trait `Uwu` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:12:16 + | +LL | pub trait Uwu: Owo { + | ^^^ the trait `Uwu` is not implemented for `Self` + | +note: required by a bound in `Owo` + --> $DIR/project.rs:9:15 + | +LL | pub trait Owo::T> {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `Owo` +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:13:5 + | +LL | type T; + | ^^^^^^ the trait `Uwu` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error[E0277]: the trait bound `Self: Uwu` is not satisfied + --> $DIR/project.rs:13:5 + | +LL | type T; + | ^^^^^^^ the trait `Uwu` is not implemented for `Self` + | +help: consider further restricting `Self` + | +LL | pub trait Uwu: Owo + Uwu { + | +++++ + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr index 2a9647da7823d..0141dcfb06f6b 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/trait-where-clause-const.stderr @@ -1,21 +1,35 @@ -error[E0308]: mismatched types +error[E0277]: the trait bound `T: ~const Bar` is not satisfied --> $DIR/trait-where-clause-const.rs:21:5 | LL | T::b(); - | ^^^^^^ expected `host`, found `true` + | ^ the trait `~const Bar` is not implemented for `T` | - = note: expected constant `host` - found constant `true` +note: required by a bound in `Foo::b` + --> $DIR/trait-where-clause-const.rs:15:24 + | +LL | fn b() where Self: ~const Bar; + | ^^^^^^^^^^ required by this bound in `Foo::b` +help: consider further restricting this bound + | +LL | const fn test1() { + | ++++++++++++ -error[E0308]: mismatched types - --> $DIR/trait-where-clause-const.rs:23:5 +error[E0277]: the trait bound `T: ~const Bar` is not satisfied + --> $DIR/trait-where-clause-const.rs:23:12 | LL | T::c::(); - | ^^^^^^^^^^^ expected `host`, found `true` + | ^ the trait `~const Bar` is not implemented for `T` + | +note: required by a bound in `Foo::c` + --> $DIR/trait-where-clause-const.rs:16:13 + | +LL | fn c(); + | ^^^^^^^^^^ required by this bound in `Foo::c` +help: consider further restricting this bound | - = note: expected constant `host` - found constant `true` +LL | const fn test1() { + | ++++++++++++ error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0308`. +For more information about this error, try `rustc --explain E0277`. diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs index 62a7b31237842..8f441410c1784 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.rs @@ -30,4 +30,4 @@ fn accept0(_: Container<{ T::make() }>) {} // FIXME(effects): Instead of suggesting `+ const Trait`, suggest // changing `~const Trait` to `const Trait`. const fn accept1(_: Container<{ T::make() }>) {} -//~^ ERROR the trait bound `T: const Trait` is not satisfied +//~^ ERROR mismatched types diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr index 2fb4fc1aa2b8e..258f95b5c4a89 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/unsatisfied-const-trait-bound.stderr @@ -7,16 +7,14 @@ LL | fn accept0(_: Container<{ T::make() }>) {} = note: expected constant `false` found constant `true` -error[E0277]: the trait bound `T: const Trait` is not satisfied +error[E0308]: mismatched types --> $DIR/unsatisfied-const-trait-bound.rs:32:50 | LL | const fn accept1(_: Container<{ T::make() }>) {} - | ^ the trait `const Trait` is not implemented for `T` - | -help: consider further restricting this bound + | ^^^^^^^^^ expected `false`, found `host` | -LL | const fn accept1(_: Container<{ T::make() }>) {} - | +++++++++++++ + = note: expected constant `false` + found constant `host` error[E0277]: the trait bound `Ty: const Trait` is not satisfied --> $DIR/unsatisfied-const-trait-bound.rs:20:15 From 760673e97d48e131b87ec738cb7106c5f8abe55e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Mon, 8 Jan 2024 01:07:14 +0000 Subject: [PATCH 2/2] Remove logic in one_bound in astconv that prefers non-const bounds --- .../rustc_hir_analysis/src/astconv/mod.rs | 35 ++----------------- .../const-impl-trait.rs | 2 ++ .../const-impl-trait.stderr | 21 +++++------ 3 files changed, 13 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 092df257dbfae..70f0c9bc4325b 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -1032,7 +1032,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.trait_defines_associated_item_named(r.def_id(), assoc_kind, assoc_name) }); - let Some(mut bound) = matching_candidates.next() else { + let Some(bound) = matching_candidates.next() else { let reported = self.complain_about_assoc_item_not_found( all_candidates, &ty_param_name.to_string(), @@ -1046,38 +1046,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { }; debug!(?bound); - // look for a candidate that is not the same as our first bound, disregarding - // whether the bound is const. - let mut next_cand = matching_candidates.next(); - while let Some(mut bound2) = next_cand { - debug!(?bound2); - if bound2.bound_vars() != bound.bound_vars() { - break; - } - - let generics = tcx.generics_of(bound.def_id()); - let Some(host_index) = generics.host_effect_index else { break }; - - // always return the bound that contains the host param. - if let ty::ConstKind::Param(_) = bound2.skip_binder().args.const_at(host_index).kind() { - (bound, bound2) = (bound2, bound); - } - - let unconsted_args = bound - .skip_binder() - .args - .iter() - .enumerate() - .map(|(n, arg)| if host_index == n { tcx.consts.true_.into() } else { arg }); - - if unconsted_args.eq(bound2.skip_binder().args.iter()) { - next_cand = matching_candidates.next(); - } else { - break; - } - } - - if let Some(bound2) = next_cand { + if let Some(bound2) = matching_candidates.next() { debug!(?bound2); let assoc_kind_str = assoc_kind_str(assoc_kind); diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs index 14d306fc31f6b..9d579e67a4be4 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs @@ -1,4 +1,6 @@ // known-bug: #110395 +// Broken until we have `&T: const Deref` impl in stdlib + #![allow(incomplete_features)] #![feature( associated_type_bounds, diff --git a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr index d0ca1b19ad17d..d4be71f2f4661 100644 --- a/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr +++ b/tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr @@ -1,5 +1,5 @@ error[E0277]: can't compare `()` with `()` - --> $DIR/const-impl-trait.rs:35:17 + --> $DIR/const-impl-trait.rs:37:17 | LL | assert!(cmp(&())); | --- ^^^ no implementation for `() == ()` @@ -9,23 +9,20 @@ LL | assert!(cmp(&())); = help: the trait `const PartialEq` is not implemented for `()` = help: the trait `PartialEq` is implemented for `()` note: required by a bound in `cmp` - --> $DIR/const-impl-trait.rs:12:23 + --> $DIR/const-impl-trait.rs:14:23 | LL | const fn cmp(a: &impl ~const PartialEq) -> bool { | ^^^^^^^^^^^^^^^^ required by this bound in `cmp` -error[E0277]: can't compare `&impl ~const PartialEq` with `&impl ~const PartialEq` - --> $DIR/const-impl-trait.rs:13:7 +error[E0369]: binary operation `==` cannot be applied to type `&impl ~const PartialEq` + --> $DIR/const-impl-trait.rs:15:7 | LL | a == a - | ^^ no implementation for `&impl ~const PartialEq == &impl ~const PartialEq` - | - = help: the trait `~const PartialEq<&impl ~const PartialEq>` is not implemented for `&impl ~const PartialEq` -help: consider dereferencing both sides of the expression - | -LL | *a == *a - | + + + | - ^^ - &impl ~const PartialEq + | | + | &impl ~const PartialEq error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0277, E0369. +For more information about an error, try `rustc --explain E0277`.