Skip to content

Commit 5be4f26

Browse files
Add feature gate, not working yet
1 parent 9081ffc commit 5be4f26

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
@@ -390,6 +390,8 @@ declare_features! (
390390
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
391391
/// Allows `async || body` closures.
392392
(unstable, async_closure, "1.37.0", Some(62290)),
393+
/// Allows async functions to be called from `dyn Trait`.
394+
(incomplete, async_fn_in_dyn_trait, "CURRENT_RUSTC_VERSION", Some(133119)),
393395
/// Allows `#[track_caller]` on async functions.
394396
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
395397
/// Allows `for await` loops.

compiler/rustc_span/src/symbol.rs

+1
Original file line numberDiff line numberDiff line change
@@ -461,6 +461,7 @@ symbols! {
461461
async_drop_slice,
462462
async_drop_surface_drop_in_place,
463463
async_fn,
464+
async_fn_in_dyn_trait,
464465
async_fn_in_trait,
465466
async_fn_kind_helper,
466467
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,
@@ -901,23 +902,56 @@ fn contains_illegal_impl_trait_in_trait<'tcx>(
901902
fn_def_id: DefId,
902903
ty: ty::Binder<'tcx, Ty<'tcx>>,
903904
) -> Option<MethodViolationCode> {
904-
// This would be caught below, but rendering the error as a separate
905-
// `async-specific` message is better.
905+
let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
906+
906907
if tcx.asyncness(fn_def_id).is_async() {
907-
return Some(MethodViolationCode::AsyncFn);
908+
if tcx.features().async_fn_in_dyn_trait() {
909+
let ty::Alias(ty::Projection, proj) = *ty.kind() else {
910+
bug!("expected async fn in trait to return an RPITIT");
911+
};
912+
assert!(tcx.is_impl_trait_in_trait(proj.def_id));
913+
914+
// FIXME(async_fn_in_dyn_trait): We should check that this bound is legal too,
915+
// and stop relying on `async fn` in the definition.
916+
for bound in tcx.item_bounds(proj.def_id).instantiate(tcx, proj.args) {
917+
if let Some(violation) = bound
918+
.visit_with(&mut IllegalRpititVisitor { tcx, allowed: Some(proj) })
919+
.break_value()
920+
{
921+
return Some(violation);
922+
}
923+
}
924+
925+
None
926+
} else {
927+
// Rendering the error as a separate `async-specific` message is better.
928+
Some(MethodViolationCode::AsyncFn)
929+
}
930+
} else {
931+
ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
908932
}
933+
}
934+
935+
struct IllegalRpititVisitor<'tcx> {
936+
tcx: TyCtxt<'tcx>,
937+
allowed: Option<ty::AliasTy<'tcx>>,
938+
}
939+
940+
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
941+
type Result = ControlFlow<MethodViolationCode>;
909942

910-
// FIXME(RPITIT): Perhaps we should use a visitor here?
911-
ty.skip_binder().walk().find_map(|arg| {
912-
if let ty::GenericArgKind::Type(ty) = arg.unpack()
913-
&& let ty::Alias(ty::Projection, proj) = ty.kind()
914-
&& tcx.is_impl_trait_in_trait(proj.def_id)
943+
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
944+
if let ty::Alias(ty::Projection, proj) = *ty.kind()
945+
&& Some(proj) != self.allowed
946+
&& self.tcx.is_impl_trait_in_trait(proj.def_id)
915947
{
916-
Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
948+
ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
949+
self.tcx.def_span(proj.def_id),
950+
))
917951
} else {
918-
None
952+
ty.super_visit_with(self)
919953
}
920-
})
954+
}
921955
}
922956

923957
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)