mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 00:34:06 +00:00
Duplicate ~const
bounds with a non-const one in effects desugaring
This commit is contained in:
parent
34bc5716b5
commit
f0f89d6d43
@ -1088,7 +1088,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
|
||||
self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Const, assoc_name)
|
||||
});
|
||||
|
||||
let (bound, next_cand) = match (matching_candidates.next(), const_candidates.next()) {
|
||||
let (mut bound, mut next_cand) = match (matching_candidates.next(), const_candidates.next())
|
||||
{
|
||||
(Some(bound), _) => (bound, matching_candidates.next()),
|
||||
(None, Some(bound)) => (bound, const_candidates.next()),
|
||||
(None, None) => {
|
||||
@ -1103,6 +1104,37 @@ 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.
|
||||
while let Some(mut bound2) = next_cand {
|
||||
debug!(?bound2);
|
||||
let tcx = self.tcx();
|
||||
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().or_else(|| const_candidates.next());
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(bound2) = next_cand {
|
||||
debug!(?bound2);
|
||||
|
||||
|
@ -43,6 +43,33 @@ impl<'tcx> Bounds<'tcx> {
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
span: Span,
|
||||
polarity: ty::ImplPolarity,
|
||||
) {
|
||||
self.push_trait_bound_inner(tcx, trait_ref, span, polarity);
|
||||
|
||||
// if we have a host param, we push an unconst trait bound in addition
|
||||
// to the const one.
|
||||
// FIXME(effects) we should find a better way than name matching
|
||||
if tcx.features().effects && trait_ref.skip_binder().args.host_effect_param().is_some() {
|
||||
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(
|
||||
&mut self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
trait_ref: ty::PolyTraitRef<'tcx>,
|
||||
span: Span,
|
||||
polarity: ty::ImplPolarity,
|
||||
) {
|
||||
self.clauses.push((
|
||||
trait_ref
|
||||
|
@ -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::{Span, DUMMY_SP};
|
||||
use rustc_span::{sym, 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,11 +38,38 @@ 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;
|
||||
result.predicates =
|
||||
tcx.arena.alloc_from_iter(result.predicates.iter().copied().chain(std::iter::once((
|
||||
ty::TraitRef::identity(tcx, def_id).to_predicate(tcx),
|
||||
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),
|
||||
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
|
||||
|
@ -221,14 +221,14 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
|
||||
let item_def_id = tcx.hir().ty_param_owner(def_id);
|
||||
let generics = tcx.generics_of(item_def_id);
|
||||
let index = generics.param_def_id_to_index[&def_id.to_def_id()];
|
||||
// HACK(eddyb) should get the original `Span`.
|
||||
let span = tcx.def_span(def_id);
|
||||
ty::GenericPredicates {
|
||||
parent: None,
|
||||
predicates: tcx.arena.alloc_from_iter(
|
||||
self.param_env.caller_bounds().iter().filter_map(|predicate| {
|
||||
match predicate.kind().skip_binder() {
|
||||
ty::ClauseKind::Trait(data) if data.self_ty().is_param(index) => {
|
||||
// HACK(eddyb) should get the original `Span`.
|
||||
let span = tcx.def_span(def_id);
|
||||
Some((predicate, span))
|
||||
}
|
||||
_ => None,
|
||||
|
@ -79,6 +79,10 @@ impl GenericParamDef {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_host_effect(&self) -> bool {
|
||||
matches!(self.kind, GenericParamDefKind::Const { is_host_effect: true, .. })
|
||||
}
|
||||
|
||||
pub fn default_value<'tcx>(
|
||||
&self,
|
||||
tcx: TyCtxt<'tcx>,
|
||||
|
@ -1,14 +1,12 @@
|
||||
error[E0277]: the trait bound `T: Foo` is not satisfied
|
||||
--> $DIR/assoc-type-const-bound-usage.rs:12:6
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/assoc-type-const-bound-usage.rs:12:5
|
||||
|
|
||||
LL | <T as Foo>::Assoc::foo();
|
||||
| ^ the trait `Foo` is not implemented for `T`
|
||||
| ^^^^^^^^^^^^^^^^^^^^^^^^ expected `host`, found `true`
|
||||
|
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | const fn foo<T: ~const Foo + Foo>() {
|
||||
| +++++
|
||||
= note: expected constant `host`
|
||||
found constant `true`
|
||||
|
||||
error: aborting due to previous error
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
504
tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
Normal file
504
tests/ui/rfcs/rfc-2632-const-trait-impl/effects/minicore.rs
Normal file
@ -0,0 +1,504 @@
|
||||
#![crate_type = "lib"]
|
||||
#![feature(no_core, lang_items, unboxed_closures, auto_traits, intrinsics, rustc_attrs)]
|
||||
#![feature(fundamental)]
|
||||
#![feature(const_trait_impl, effects, const_mut_refs)]
|
||||
#![allow(internal_features)]
|
||||
#![no_std]
|
||||
#![no_core]
|
||||
|
||||
// known-bug: #110395
|
||||
|
||||
#[lang = "sized"]
|
||||
trait Sized {}
|
||||
#[lang = "copy"]
|
||||
trait Copy {}
|
||||
|
||||
#[lang = "add"]
|
||||
#[const_trait]
|
||||
trait Add<Rhs = Self> {
|
||||
type Output;
|
||||
|
||||
fn add(self, rhs: Rhs) -> Self::Output;
|
||||
}
|
||||
|
||||
// FIXME we shouldn't need to have to specify `Rhs`.
|
||||
impl const Add<i32> for i32 {
|
||||
type Output = i32;
|
||||
fn add(self, rhs: i32) -> i32 {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
fn foo() {
|
||||
let x = 42_i32 + 43_i32;
|
||||
}
|
||||
|
||||
const fn bar() {
|
||||
let x = 42_i32 + 43_i32;
|
||||
}
|
||||
|
||||
|
||||
#[lang = "Try"]
|
||||
#[const_trait]
|
||||
trait Try: FromResidual {
|
||||
type Output;
|
||||
type Residual;
|
||||
|
||||
#[lang = "from_output"]
|
||||
fn from_output(output: Self::Output) -> Self;
|
||||
|
||||
#[lang = "branch"]
|
||||
fn branch(self) -> ControlFlow<Self::Residual, Self::Output>;
|
||||
}
|
||||
|
||||
// FIXME
|
||||
// #[const_trait]
|
||||
trait FromResidual<R = <Self as Try>::Residual> {
|
||||
#[lang = "from_residual"]
|
||||
fn from_residual(residual: R) -> Self;
|
||||
}
|
||||
|
||||
enum ControlFlow<B, C = ()> {
|
||||
#[lang = "Continue"]
|
||||
Continue(C),
|
||||
#[lang = "Break"]
|
||||
Break(B),
|
||||
}
|
||||
|
||||
#[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> {
|
||||
type Output;
|
||||
|
||||
extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
|
||||
}
|
||||
|
||||
struct ConstFnMutClosure<CapturedData, Function> {
|
||||
data: CapturedData,
|
||||
func: Function,
|
||||
}
|
||||
|
||||
#[lang = "tuple_trait"]
|
||||
pub trait Tuple {}
|
||||
|
||||
macro_rules! impl_fn_mut_tuple {
|
||||
($($var:ident)*) => {
|
||||
impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
|
||||
FnOnce<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
|
||||
where
|
||||
Function: ~const Fn(($(&mut $var),*), ClosureArguments) -> ClosureReturnValue,
|
||||
Function: ~const Destruct,
|
||||
{
|
||||
type Output = ClosureReturnValue;
|
||||
|
||||
extern "rust-call" fn call_once(mut self, args: ClosureArguments) -> Self::Output {
|
||||
self.call_mut(args)
|
||||
}
|
||||
}
|
||||
impl<'a, $($var,)* ClosureArguments: Tuple, Function, ClosureReturnValue> const
|
||||
FnMut<ClosureArguments> for ConstFnMutClosure<($(&'a mut $var),*), Function>
|
||||
where
|
||||
Function: ~const Fn(($(&mut $var),*), ClosureArguments)-> ClosureReturnValue,
|
||||
Function: ~const Destruct,
|
||||
{
|
||||
extern "rust-call" fn call_mut(&mut self, args: ClosureArguments) -> Self::Output {
|
||||
#[allow(non_snake_case)]
|
||||
let ($($var),*) = &mut self.data;
|
||||
(self.func)(($($var),*), args)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
//impl_fn_mut_tuple!(A);
|
||||
//impl_fn_mut_tuple!(A B);
|
||||
//impl_fn_mut_tuple!(A B C);
|
||||
//impl_fn_mut_tuple!(A B C D);
|
||||
//impl_fn_mut_tuple!(A B C D E);
|
||||
|
||||
#[lang = "receiver"]
|
||||
trait Receiver {}
|
||||
|
||||
impl<T: ?Sized> Receiver for &T {}
|
||||
|
||||
impl<T: ?Sized> Receiver for &mut T {}
|
||||
|
||||
#[lang = "destruct"]
|
||||
#[const_trait]
|
||||
trait Destruct {}
|
||||
|
||||
#[lang = "freeze"]
|
||||
unsafe auto trait Freeze {}
|
||||
|
||||
#[lang = "drop"]
|
||||
#[const_trait]
|
||||
trait Drop {
|
||||
fn drop(&mut self);
|
||||
}
|
||||
|
||||
/*
|
||||
#[const_trait]
|
||||
trait Residual<O> {
|
||||
type TryType: ~const Try<Output = O, Residual = Self> + Try<Output = O, Residual = Self>;
|
||||
}
|
||||
*/
|
||||
|
||||
const fn size_of<T>() -> usize {
|
||||
42
|
||||
}
|
||||
|
||||
impl Copy for u8 {}
|
||||
|
||||
impl usize {
|
||||
#[rustc_allow_incoherent_impl]
|
||||
const fn repeat_u8(x: u8) -> usize {
|
||||
usize::from_ne_bytes([x; size_of::<usize>()])
|
||||
}
|
||||
#[rustc_allow_incoherent_impl]
|
||||
const fn from_ne_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[rustc_do_not_const_check] // hooked by const-eval
|
||||
const fn panic_display() {
|
||||
panic_fmt();
|
||||
}
|
||||
|
||||
fn panic_fmt() {}
|
||||
|
||||
#[lang = "index"]
|
||||
#[const_trait]
|
||||
trait Index<Idx: ?Sized> {
|
||||
type Output: ?Sized;
|
||||
|
||||
fn index(&self, index: Idx) -> &Self::Output;
|
||||
}
|
||||
|
||||
|
||||
#[const_trait]
|
||||
unsafe trait SliceIndex<T: ?Sized> {
|
||||
type Output: ?Sized;
|
||||
fn index(self, slice: &T) -> &Self::Output;
|
||||
}
|
||||
|
||||
impl<T, I> const Index<I> for [T]
|
||||
where
|
||||
I: ~const SliceIndex<[T]>,
|
||||
{
|
||||
type Output = I::Output;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: I) -> &I::Output {
|
||||
index.index(self)
|
||||
}
|
||||
}
|
||||
/* FIXME
|
||||
impl<T, I, const N: usize> const Index<I> for [T; N]
|
||||
where
|
||||
[T]: ~const Index<I>,
|
||||
{
|
||||
type Output = <[T] as Index<I>>::Output;
|
||||
|
||||
#[inline]
|
||||
// FIXME: make `Self::Output` act like `<Self as ~const Index<I>>::Output`
|
||||
fn index(&self, index: I) -> &<[T] as Index<I>>::Output {
|
||||
Index::index(self as &[T], index)
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[lang = "unsize"]
|
||||
trait Unsize<T: ?Sized> {
|
||||
}
|
||||
|
||||
#[lang = "coerce_unsized"]
|
||||
trait CoerceUnsized<T: ?Sized> {
|
||||
}
|
||||
|
||||
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
|
||||
|
||||
|
||||
#[lang = "deref"]
|
||||
// #[const_trait] FIXME
|
||||
trait Deref {
|
||||
#[lang = "deref_target"]
|
||||
type Target: ?Sized;
|
||||
|
||||
fn deref(&self) -> &Self::Target;
|
||||
}
|
||||
|
||||
|
||||
impl<T: ?Sized> /* const */ Deref for &T {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ?Sized> /* const */ Deref for &mut T {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &T {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
enum Option<T> {
|
||||
#[lang = "None"]
|
||||
None,
|
||||
#[lang = "Some"]
|
||||
Some(T),
|
||||
}
|
||||
|
||||
impl<T> Option<T> {
|
||||
const fn as_ref(&self) -> Option<&T> {
|
||||
match *self {
|
||||
Some(ref x) => Some(x),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
const fn as_mut(&mut self) -> Option<&mut T> {
|
||||
match *self {
|
||||
Some(ref mut x) => Some(x),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
use Option::*;
|
||||
|
||||
/*
|
||||
const fn as_deref<T>(opt: &Option<T>) -> Option<&T::Target>
|
||||
where
|
||||
T: ~const Deref,
|
||||
{
|
||||
match opt {
|
||||
Option::Some(t) => Option::Some(t.deref()),
|
||||
Option::None => Option::None,
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#[const_trait]
|
||||
trait Into<T>: Sized {
|
||||
fn into(self) -> T;
|
||||
}
|
||||
|
||||
#[const_trait]
|
||||
trait From<T>: Sized {
|
||||
fn from(value: T) -> Self;
|
||||
}
|
||||
|
||||
impl<T, U> const Into<U> for T
|
||||
where
|
||||
U: ~const From<T>,
|
||||
{
|
||||
fn into(self) -> U {
|
||||
U::from(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> const From<T> for T {
|
||||
fn from(t: T) -> T {
|
||||
t
|
||||
}
|
||||
}
|
||||
|
||||
enum Result<T, E> {
|
||||
Ok(T),
|
||||
Err(E),
|
||||
}
|
||||
use Result::*;
|
||||
|
||||
fn from_str(s: &str) -> Result<bool, ()> {
|
||||
match s {
|
||||
"true" => Ok(true),
|
||||
"false" => Ok(false),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "eq"]
|
||||
#[const_trait]
|
||||
trait PartialEq<Rhs: ?Sized = Self> {
|
||||
fn eq(&self, other: &Rhs) -> bool;
|
||||
fn ne(&self, other: &Rhs) -> bool {
|
||||
!self.eq(other)
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME(effects): again, this should not error without Rhs specified
|
||||
impl PartialEq<str> for str {
|
||||
fn eq(&self, other: &str) -> bool {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#[lang = "not"]
|
||||
#[const_trait]
|
||||
trait Not {
|
||||
type Output;
|
||||
fn not(self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl const Not for bool {
|
||||
type Output = bool;
|
||||
fn not(self) -> bool {
|
||||
!self
|
||||
}
|
||||
}
|
||||
|
||||
impl Copy for bool {}
|
||||
impl<'a> Copy for &'a str {}
|
||||
|
||||
#[lang = "pin"]
|
||||
#[fundamental]
|
||||
#[repr(transparent)]
|
||||
struct Pin<P> {
|
||||
pointer: P,
|
||||
}
|
||||
|
||||
impl<P> Pin<P> {
|
||||
#[lang = "new_unchecked"]
|
||||
const unsafe fn new_unchecked(pointer: P) -> Pin<P> {
|
||||
Pin { pointer }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: ?Sized> Pin<&'a T> {
|
||||
const fn get_ref(self) -> &'a T {
|
||||
self.pointer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<P: Deref> Pin<P> {
|
||||
/* const */ fn as_ref(&self) -> Pin<&P::Target>
|
||||
where
|
||||
P: /* ~const */ Deref,
|
||||
{
|
||||
unsafe { Pin::new_unchecked(&*self.pointer) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl<'a, T: ?Sized> Pin<&'a mut T> {
|
||||
const unsafe fn get_unchecked_mut(self) -> &'a mut T {
|
||||
self.pointer
|
||||
}
|
||||
}
|
||||
/* FIXME lol
|
||||
impl<T> Option<T> {
|
||||
const fn as_pin_ref(self: Pin<&Self>) -> Option<Pin<&T>> {
|
||||
match Pin::get_ref(self).as_ref() {
|
||||
Some(x) => unsafe { Some(Pin::new_unchecked(x)) },
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
const fn as_pin_mut(self: Pin<&mut Self>) -> Option<Pin<&mut T>> {
|
||||
unsafe {
|
||||
match Pin::get_unchecked_mut(self).as_mut() {
|
||||
Some(x) => Some(Pin::new_unchecked(x)),
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
impl<P: /* ~const */ Deref> /* const */ Deref for Pin<P> {
|
||||
type Target = P::Target;
|
||||
fn deref(&self) -> &P::Target {
|
||||
Pin::get_ref(Pin::as_ref(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> /* const */ Deref for Option<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: Receiver> Receiver for Pin<P> {}
|
||||
|
||||
impl<T: Clone> Clone for RefCell<T> {
|
||||
fn clone(&self) -> RefCell<T> {
|
||||
RefCell::new(self.borrow().clone())
|
||||
}
|
||||
}
|
||||
|
||||
struct RefCell<T: ?Sized> {
|
||||
borrow: UnsafeCell<()>,
|
||||
value: UnsafeCell<T>,
|
||||
}
|
||||
impl<T> RefCell<T> {
|
||||
const fn new(value: T) -> RefCell<T> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized> RefCell<T> {
|
||||
fn borrow(&self) -> Ref<'_, T> {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "unsafe_cell"]
|
||||
#[repr(transparent)]
|
||||
struct UnsafeCell<T: ?Sized> {
|
||||
value: T,
|
||||
}
|
||||
|
||||
struct Ref<'b, T: ?Sized + 'b> {
|
||||
value: *const T,
|
||||
borrow: &'b UnsafeCell<()>,
|
||||
}
|
||||
|
||||
impl<T: ?Sized> Deref for Ref<'_, T> {
|
||||
type Target = T;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &T {
|
||||
loop {}
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "clone"]
|
||||
#[rustc_trivial_field_reads]
|
||||
#[const_trait]
|
||||
trait Clone: Sized {
|
||||
fn clone(&self) -> Self;
|
||||
fn clone_from(&mut self, source: &Self)
|
||||
where
|
||||
Self: ~const Destruct,
|
||||
{
|
||||
*self = source.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[lang = "structural_peq"]
|
||||
trait StructuralPartialEq {}
|
||||
|
||||
#[lang = "structural_teq"]
|
||||
trait StructuralEq {}
|
||||
|
||||
const fn drop<T: ~const Destruct>(_: T) {}
|
@ -0,0 +1,32 @@
|
||||
error[E0369]: cannot add `i32` to `i32`
|
||||
--> $DIR/minicore.rs:33:20
|
||||
|
|
||||
LL | let x = 42_i32 + 43_i32;
|
||||
| ------ ^ ------ i32
|
||||
| |
|
||||
| i32
|
||||
|
||||
error[E0369]: cannot add `i32` to `i32`
|
||||
--> $DIR/minicore.rs:37:20
|
||||
|
|
||||
LL | let x = 42_i32 + 43_i32;
|
||||
| ------ ^ ------ i32
|
||||
| |
|
||||
| i32
|
||||
|
||||
error[E0600]: cannot apply unary operator `!` to type `bool`
|
||||
--> $DIR/minicore.rs:343:9
|
||||
|
|
||||
LL | !self.eq(other)
|
||||
| ^^^^^^^^^^^^^^^ cannot apply unary operator `!`
|
||||
|
||||
error[E0600]: cannot apply unary operator `!` to type `bool`
|
||||
--> $DIR/minicore.rs:365:9
|
||||
|
|
||||
LL | !self
|
||||
| ^^^^^ cannot apply unary operator `!`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
Some errors have detailed explanations: E0369, E0600.
|
||||
For more information about an error, try `rustc --explain E0369`.
|
11
tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs
Normal file
11
tests/ui/rfcs/rfc-2632-const-trait-impl/effects/project.rs
Normal file
@ -0,0 +1,11 @@
|
||||
// check-pass
|
||||
#![feature(const_trait_impl, effects)]
|
||||
|
||||
pub trait Owo<X = <Self as Uwu>::T> {}
|
||||
|
||||
#[const_trait]
|
||||
pub trait Uwu: Owo {
|
||||
type T;
|
||||
}
|
||||
|
||||
fn main() {}
|
@ -1,35 +1,21 @@
|
||||
error[E0277]: the trait bound `T: ~const Bar` is not satisfied
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/trait-where-clause-const.rs:21:5
|
||||
|
|
||||
LL | T::b();
|
||||
| ^ the trait `Bar` is not implemented for `T`
|
||||
| ^^^^^^ expected `host`, found `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<T: ~const Foo + Bar + Bar>() {
|
||||
| +++++
|
||||
= note: expected constant `host`
|
||||
found constant `true`
|
||||
|
||||
error[E0277]: the trait bound `T: ~const Bar` is not satisfied
|
||||
--> $DIR/trait-where-clause-const.rs:23:12
|
||||
error[E0308]: mismatched types
|
||||
--> $DIR/trait-where-clause-const.rs:23:5
|
||||
|
|
||||
LL | T::c::<T>();
|
||||
| ^ the trait `Bar` is not implemented for `T`
|
||||
| ^^^^^^^^^^^ expected `host`, found `true`
|
||||
|
|
||||
note: required by a bound in `Foo::c`
|
||||
--> $DIR/trait-where-clause-const.rs:16:13
|
||||
|
|
||||
LL | fn c<T: ~const Bar>();
|
||||
| ^^^^^^^^^^ required by this bound in `Foo::c`
|
||||
help: consider further restricting this bound
|
||||
|
|
||||
LL | const fn test1<T: ~const Foo + Bar + Bar>() {
|
||||
| +++++
|
||||
= note: expected constant `host`
|
||||
found constant `true`
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
For more information about this error, try `rustc --explain E0277`.
|
||||
For more information about this error, try `rustc --explain E0308`.
|
||||
|
Loading…
Reference in New Issue
Block a user