Skip to content

Commit bffa448

Browse files
Add feature gate, not working yet
1 parent c2df7bd commit bffa448

File tree

5 files changed

+110
-11
lines changed

5 files changed

+110
-11
lines changed

compiler/rustc_feature/src/unstable.rs

+2
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ declare_features! (
384384
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
385385
/// Allows `async || body` closures.
386386
(unstable, async_closure, "1.37.0", Some(62290)),
387+
/// Allows async functions to be called from `dyn Trait`.
388+
(incomplete, async_fn_in_dyn_trait, "CURRENT_RUSTC_VERSION", Some(133119)),
387389
/// Allows `#[track_caller]` on async functions.
388390
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
389391
/// Allows `for await` loops.

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,7 @@ symbols! {
453453
async_drop_slice,
454454
async_drop_surface_drop_in_place,
455455
async_fn,
456+
async_fn_in_dyn_trait,
456457
async_fn_in_trait,
457458
async_fn_kind_helper,
458459
async_fn_kind_upvars,

compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs

+45-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_abi::BackendRepr;
1111
use rustc_errors::FatalError;
1212
use rustc_hir as hir;
1313
use rustc_hir::def_id::DefId;
14+
use rustc_middle::bug;
1415
use rustc_middle::query::Providers;
1516
use rustc_middle::ty::{
1617
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
@@ -905,23 +906,56 @@ fn contains_illegal_impl_trait_in_trait<'tcx>(
905906
fn_def_id: DefId,
906907
ty: ty::Binder<'tcx, Ty<'tcx>>,
907908
) -> Option<MethodViolationCode> {
908-
// This would be caught below, but rendering the error as a separate
909-
// `async-specific` message is better.
909+
let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
910+
910911
if tcx.asyncness(fn_def_id).is_async() {
911-
return Some(MethodViolationCode::AsyncFn);
912+
if tcx.features().async_fn_in_dyn_trait() {
913+
let ty::Alias(ty::Projection, proj) = *ty.kind() else {
914+
bug!("expected async fn in trait to return an RPITIT");
915+
};
916+
assert!(tcx.is_impl_trait_in_trait(proj.def_id));
917+
918+
// FIXME(async_fn_in_dyn_trait): We should check that this bound is legal too,
919+
// and stop relying on `async fn` in the definition.
920+
for bound in tcx.item_bounds(proj.def_id).instantiate(tcx, proj.args) {
921+
if let Some(violation) = bound
922+
.visit_with(&mut IllegalRpititVisitor { tcx, allowed: Some(proj) })
923+
.break_value()
924+
{
925+
return Some(violation);
926+
}
927+
}
928+
929+
None
930+
} else {
931+
// Rendering the error as a separate `async-specific` message is better.
932+
Some(MethodViolationCode::AsyncFn)
933+
}
934+
} else {
935+
ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
912936
}
937+
}
938+
939+
struct IllegalRpititVisitor<'tcx> {
940+
tcx: TyCtxt<'tcx>,
941+
allowed: Option<ty::AliasTy<'tcx>>,
942+
}
943+
944+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
945+
type Result = ControlFlow<MethodViolationCode>;
913946

914-
// FIXME(RPITIT): Perhaps we should use a visitor here?
915-
ty.skip_binder().walk().find_map(|arg| {
916-
if let ty::GenericArgKind::Type(ty) = arg.unpack()
917-
&& let ty::Alias(ty::Projection, proj) = ty.kind()
918-
&& tcx.is_impl_trait_in_trait(proj.def_id)
947+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
948+
if let ty::Alias(ty::Projection, proj) = *ty.kind()
949+
&& Some(proj) != self.allowed
950+
&& self.tcx.is_impl_trait_in_trait(proj.def_id)
919951
{
920-
Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
952+
ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
953+
self.tcx.def_span(proj.def_id),
954+
))
921955
} else {
922-
None
956+
ty.super_visit_with(self)
923957
}
924-
})
958+
}
925959
}
926960

927961
pub(crate) fn provide(providers: &mut Providers) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ edition: 2021
2+
3+
trait Foo {
4+
async fn bar(&self);
5+
}
6+
7+
async fn takes_dyn_trait(x: &dyn Foo) {
8+
//~^ ERROR the trait `Foo` cannot be made into an object
9+
x.bar().await;
10+
//~^ ERROR the trait `Foo` cannot be made into an object
11+
//~| ERROR the trait `Foo` cannot be made into an object
12+
}
13+
14+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
error[E0038]: the trait `Foo` cannot be made into an object
2+
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:7:30
3+
|
4+
LL | async fn takes_dyn_trait(x: &dyn Foo) {
5+
| ^^^^^^^ `Foo` cannot be made into an object
6+
|
7+
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
8+
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
9+
|
10+
LL | trait Foo {
11+
| --- this trait cannot be made into an object...
12+
LL | async fn bar(&self);
13+
| ^^^ ...because method `bar` is `async`
14+
= help: consider moving `bar` to another trait
15+
16+
error[E0038]: the trait `Foo` cannot be made into an object
17+
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:7
18+
|
19+
LL | x.bar().await;
20+
| ^^^ `Foo` cannot be made into an object
21+
|
22+
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
23+
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
24+
|
25+
LL | trait Foo {
26+
| --- this trait cannot be made into an object...
27+
LL | async fn bar(&self);
28+
| ^^^ ...because method `bar` is `async`
29+
= help: consider moving `bar` to another trait
30+
31+
error[E0038]: the trait `Foo` cannot be made into an object
32+
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:5
33+
|
34+
LL | x.bar().await;
35+
| ^^^^^^^ `Foo` cannot be made into an object
36+
|
37+
note: for a trait to be "dyn-compatible" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
38+
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
39+
|
40+
LL | trait Foo {
41+
| --- this trait cannot be made into an object...
42+
LL | async fn bar(&self);
43+
| ^^^ ...because method `bar` is `async`
44+
= help: consider moving `bar` to another trait
45+
46+
error: aborting due to 3 previous errors
47+
48+
For more information about this error, try `rustc --explain E0038`.

0 commit comments

Comments
 (0)