Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

~const trait and projection bounds do not imply their non-const counterparts #119721

Merged
merged 2 commits into from
Jan 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 2 additions & 33 deletions compiler/rustc_hir_analysis/src/astconv/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand All @@ -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);
Expand Down
18 changes: 0 additions & 18 deletions compiler/rustc_hir_analysis/src/bounds.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
38 changes: 6 additions & 32 deletions compiler/rustc_hir_analysis/src/collect/predicates_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ trait Foo {
}

const fn foo<T: ~const Foo>() {
<T as Foo>::Assoc::foo();
<T as /* FIXME: ~const */ Foo>::Assoc::foo();
}

fn main() {}
compiler-errors marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -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 | <T as Foo>::Assoc::foo();
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true`
LL | <T as /* FIXME: ~const */ Foo>::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<T: ~const Foo + 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`.
Original file line number Diff line number Diff line change
@@ -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>(_: 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<Args: Tuple>: ~const FnMut<Args> {
extern "rust-call" fn call(&self, args: Args) -> Self::Output;
}

#[const_trait]
#[lang = "fn_mut"]
#[rustc_paren_sugar]
trait FnMut<Args: Tuple>: ~const FnOnce<Args> {
extern "rust-call" fn call_mut(&mut self, args: Args) -> Self::Output;
}

#[const_trait]
#[lang = "fn_once"]
#[rustc_paren_sugar]
trait FnOnce<Args: Tuple> {
#[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<T: ?Sized> Receiver for &T {}

impl<T: ?Sized> Receiver for &mut T {}
2 changes: 2 additions & 0 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// known-bug: #110395
// Broken until we have `&T: const Deref` impl in stdlib

#![allow(incomplete_features)]
#![feature(
associated_type_bounds,
Expand Down
21 changes: 9 additions & 12 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/const-impl-trait.stderr
Original file line number Diff line number Diff line change
@@ -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 `() == ()`
Expand All @@ -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`.
17 changes: 11 additions & 6 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const fn bar() {

#[lang = "Try"]
#[const_trait]
trait Try: FromResidual {
trait Try: FromResidual<Self::Residual> {
type Output;
type Residual;

Expand All @@ -53,7 +53,7 @@ trait Try: FromResidual {

// FIXME
// #[const_trait]
trait FromResidual<R = <Self as Try>::Residual> {
trait FromResidual<R = <Self as /* FIXME: ~const */ Try>::Residual> {
#[lang = "from_residual"]
fn from_residual(residual: R) -> Self;
}
Expand Down Expand Up @@ -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<Arg, Output = RET>,
G: FnOnce<Arg, Output = RET>,
*/;
F: const FnOnce<ARG, Output = RET>,
G: FnOnce<ARG, Output = RET>;
}

fn test_const_eval_select() {
const fn const_fn() {}
fn rt_fn() {}

unsafe { const_eval_select((), const_fn, rt_fn); }
}
9 changes: 7 additions & 2 deletions tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
// check-pass
// known-bug: #110395
// FIXME: effects

#![feature(const_trait_impl, effects)]

pub trait Owo<X = <Self as Uwu>::T> {}
// This fails because `~const Uwu` doesn't imply (non-const) `Uwu`.

// FIXME: #[const_trait]
pub trait Owo<X = <Self as /* FIXME: ~const */ Uwu>::T> {}

#[const_trait]
pub trait Uwu: Owo {
Expand Down
Loading
Loading