Skip to content

Commit 3b05779

Browse files
Add feature gate, not working yet
1 parent 33c245b commit 3b05779

5 files changed

Lines changed: 113 additions & 11 deletions

File tree

‎compiler/rustc_feature/src/unstable.rs‎

Lines changed: 2 additions & 0 deletions
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‎

Lines changed: 1 addition & 0 deletions
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‎

Lines changed: 48 additions & 11 deletions
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,ExistentialPredicateStableCmpExtas _,GenericArgs,Ty,TyCtxt,
@@ -901,23 +902,59 @@ 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-
returnSome(MethodViolationCode::AsyncFn);
908+
// FIXME(async_fn_in_dyn_trait): Think of a better way to unify these code paths
909+
// to issue an appropriate feature suggestion when users try to use AFIDT.
910+
// Obviously we must only do this once AFIDT is finished enough to actually be usable.
911+
if tcx.features().async_fn_in_dyn_trait(){
912+
let ty::Alias(ty::Projection, proj) = *ty.kind()else{
913+
bug!("expected async fn in trait to return an RPITIT");
914+
};
915+
assert!(tcx.is_impl_trait_in_trait(proj.def_id));
916+
917+
// FIXME(async_fn_in_dyn_trait): We should check that this bound is legal too,
918+
// and stop relying on `async fn` in the definition.
919+
for bound in tcx.item_bounds(proj.def_id).instantiate(tcx, proj.args){
920+
ifletSome(violation) = bound
921+
.visit_with(&mutIllegalRpititVisitor{ tcx,allowed:Some(proj)})
922+
.break_value()
923+
{
924+
returnSome(violation);
925+
}
926+
}
927+
928+
None
929+
}else{
930+
// Rendering the error as a separate `async-specific` message is better.
931+
Some(MethodViolationCode::AsyncFn)
932+
}
933+
}else{
934+
ty.visit_with(&mutIllegalRpititVisitor{ tcx,allowed:None}).break_value()
908935
}
936+
}
937+
938+
structIllegalRpititVisitor<'tcx>{
939+
tcx:TyCtxt<'tcx>,
940+
allowed:Option<ty::AliasTy<'tcx>>,
941+
}
942+
943+
impl<'tcx>TypeVisitor<TyCtxt<'tcx>>forIllegalRpititVisitor<'tcx>{
944+
typeResult = ControlFlow<MethodViolationCode>;
909945

910-
// FIXME(RPITIT): Perhaps we should use a visitor here?
911-
ty.skip_binder().walk().find_map(|arg| {
912-
iflet 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)
946+
fnvisit_ty(&mutself,ty:Ty<'tcx>) -> Self::Result{
947+
iflet ty::Alias(ty::Projection, proj) = *ty.kind()
948+
&& Some(proj) != self.allowed
949+
&& self.tcx.is_impl_trait_in_trait(proj.def_id)
915950
{
916-
Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
951+
ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
952+
self.tcx.def_span(proj.def_id),
953+
))
917954
}else{
918-
None
955+
ty.super_visit_with(self)
919956
}
920-
})
957+
}
921958
}
922959

923960
pub(crate)fnprovide(providers:&mutProviders){
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
//@ edition: 2021
2+
3+
traitFoo{
4+
asyncfnbar(&self);
5+
}
6+
7+
asyncfntakes_dyn_trait(x:&dynFoo){
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+
fnmain(){}
Lines changed: 48 additions & 0 deletions
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)