Skip to content

Commit 6136058

Browse files
committed
fix(core): remove TAIT usage to work around false "cycle detected" errors
Work-around for [rust-lang/rust#99793][1]. [1]: rust-lang/rust#99793
1 parent e3c5024 commit 6136058

File tree

3 files changed

+50
-24
lines changed

3 files changed

+50
-24
lines changed

doc/toolchain_limitations.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -627,6 +627,25 @@ const _: () = tokenlock::with_branded_token(|token| {
627627
```
628628

629629

630+
### `[tag:rust_99793_tait]` False-positive "cycle detected" in `const fn` with TAIT
631+
632+
*Upstream issue:* [rust-lang/rust#99793](https://github.com/rust-lang/rust/issues/99793) (possibly related)
633+
634+
```rust
635+
#![feature(type_alias_impl_trait)]
636+
type Unit<T> = impl Copy;
637+
fn unit<T>(x: T) -> Unit<T> { core::mem::forget(x) }
638+
```
639+
640+
```rust,compile_fail,E0391
641+
#![feature(type_alias_impl_trait)]
642+
type Unit<T> = impl Copy;
643+
// error[E0391]: cycle detected when computing type of
644+
// `main::_doctest_main_lib_rs_647_0::Unit::{opaque#0}
645+
const fn unit<T>(x: T) -> Unit<T> { core::mem::forget(x) }
646+
```
647+
648+
630649
## Unsized types
631650

632651
### `[tag:unsized_maybe_uninit]` `MaybeUninit<T>` requires `T: Sized`

src/r3_core/src/bind.rs

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1196,10 +1196,7 @@ macro_rules! impl_fn_bind {
11961196
{
11971197
type Output = Output;
11981198

1199-
// This opaque type must be defined outside this trait to
1200-
// prevent the unintended capturing of `$BinderI`.
1201-
// [ref:opaque_type_extraneous_capture]
1202-
type BoundFn = BoundFn<T, Output, $( $RuntimeBinderI, )*>;
1199+
type BoundFn = BoundFn<T, $( $RuntimeBinderI, )*>;
12031200

12041201
fn bind(
12051202
self,
@@ -1209,42 +1206,50 @@ macro_rules! impl_fn_bind {
12091206
Binder::register_dependency(&binder, ctx);
12101207

12111208
let intermediate = Binder::into_runtime_binder(binder);
1212-
bind_inner(self, intermediate)
1209+
BoundFn {
1210+
func: self,
1211+
runtime_binders: intermediate,
1212+
}
12131213
}
12141214
}
12151215

1216-
type BoundFn<T, Output, $( $RuntimeBinderI, )*>
1217-
where
1218-
$( $RuntimeBinderI: RuntimeBinder, )*
1219-
T: for<'call> FnOnce($( $RuntimeBinderI::Target<'call>, )*)
1220-
-> Output + Copy + Send + 'static,
1221-
= impl FnOnce() -> Output + Copy + Send + 'static;
1222-
1223-
const fn bind_inner<
1224-
T,
1225-
Output,
1226-
$( $RuntimeBinderI, )*
1227-
>(
1216+
// This opaque type must be defined outside the above `impl` to
1217+
// prevent the unintended capturing of `$BinderI`.
1218+
// [ref:opaque_type_extraneous_capture]
1219+
// type BoundFn<T, Output, $( $RuntimeBinderI, )*>
1220+
// where
1221+
// $( $RuntimeBinderI: RuntimeBinder, )*
1222+
// T: for<'call> FnOnce($( $RuntimeBinderI::Target<'call>, )*)
1223+
// -> Output + Copy + Send + 'static,
1224+
// = impl FnOnce() -> Output + Copy + Send + 'static;
1225+
1226+
// FIXME: This is supposed to be a TAIT like the one above, but
1227+
// [ref:rust_99793_tait] prevents that
1228+
#[derive(Copy, Clone)]
1229+
pub struct BoundFn<T, $( $RuntimeBinderI, )*> {
12281230
func: T,
1229-
runtime_binders: ( $( $RuntimeBinderI, )* ),
1230-
) -> BoundFn<T, Output, $( $RuntimeBinderI, )*>
1231+
runtime_binders: ($( $RuntimeBinderI, )*),
1232+
}
1233+
1234+
impl<T, Output, $( $RuntimeBinderI, )*> FnOnce<()> for BoundFn<T, $( $RuntimeBinderI, )*>
12311235
where
12321236
$( $RuntimeBinderI: RuntimeBinder, )*
1233-
T: for<'call> FnOnce($( $RuntimeBinderI::Target<'call>, )*)
1234-
-> Output + Copy + Send + 'static,
1237+
T: for<'call> FnOnce($( $RuntimeBinderI::Target<'call>, )*) -> Output,
12351238
{
1239+
type Output = Output;
1240+
12361241
#[inline]
1237-
move || {
1242+
extern "rust-call" fn call_once(self, (): ()) -> Output {
12381243
// Safety: `runtime_binders` was created by the corresponding
12391244
// type's `into_runtime_binder` method.
12401245
// `CfgBindRegistry::finalize` checks that the borrowing
12411246
// rules regarding the materialization output are observed.
12421247
// If the check fails, so does the compilation, and this
12431248
// runtime code will never be executed.
12441249
let ($( $fieldI, )*) = unsafe {
1245-
<( $( $RuntimeBinderI, )* ) as RuntimeBinder>::materialize(runtime_binders)
1250+
<( $( $RuntimeBinderI, )* ) as RuntimeBinder>::materialize(self.runtime_binders)
12461251
};
1247-
func($( $fieldI, )*)
1252+
(self.func)($( $fieldI, )*)
12481253
}
12491254
}
12501255
}; // const _

src/r3_core/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#![feature(const_nonnull_new)]
2828
#![feature(const_result_drop)]
2929
#![feature(const_slice_index)]
30+
#![feature(unboxed_closures)] // `impl FnOnce`
3031
#![feature(const_option_ext)]
3132
#![feature(const_trait_impl)]
3233
#![feature(const_ptr_write)]
@@ -48,6 +49,7 @@
4849
#![feature(decl_macro)]
4950
#![feature(never_type)] // `!`
5051
#![feature(const_try)]
52+
#![feature(fn_traits)] // `impl FnOnce`
5153
#![feature(let_else)]
5254
#![feature(doc_cfg)] // `#[doc(cfg(...))]`
5355
#![cfg_attr(test, feature(is_sorted))]

0 commit comments

Comments
 (0)