Add feature gate, not working yet
This commit is contained in:
parent
33c245b9e9
commit
3b05779626
5 changed files with 116 additions and 14 deletions
|
@ -390,6 +390,8 @@ declare_features! (
|
||||||
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
|
(unstable, associated_type_defaults, "1.2.0", Some(29661)),
|
||||||
/// Allows `async || body` closures.
|
/// Allows `async || body` closures.
|
||||||
(unstable, async_closure, "1.37.0", Some(62290)),
|
(unstable, async_closure, "1.37.0", Some(62290)),
|
||||||
|
/// Allows async functions to be called from `dyn Trait`.
|
||||||
|
(incomplete, async_fn_in_dyn_trait, "CURRENT_RUSTC_VERSION", Some(133119)),
|
||||||
/// Allows `#[track_caller]` on async functions.
|
/// Allows `#[track_caller]` on async functions.
|
||||||
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
|
(unstable, async_fn_track_caller, "1.73.0", Some(110011)),
|
||||||
/// Allows `for await` loops.
|
/// Allows `for await` loops.
|
||||||
|
|
|
@ -461,6 +461,7 @@ symbols! {
|
||||||
async_drop_slice,
|
async_drop_slice,
|
||||||
async_drop_surface_drop_in_place,
|
async_drop_surface_drop_in_place,
|
||||||
async_fn,
|
async_fn,
|
||||||
|
async_fn_in_dyn_trait,
|
||||||
async_fn_in_trait,
|
async_fn_in_trait,
|
||||||
async_fn_kind_helper,
|
async_fn_kind_helper,
|
||||||
async_fn_kind_upvars,
|
async_fn_kind_upvars,
|
||||||
|
|
|
@ -11,6 +11,7 @@ use rustc_abi::BackendRepr;
|
||||||
use rustc_errors::FatalError;
|
use rustc_errors::FatalError;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
|
use rustc_middle::bug;
|
||||||
use rustc_middle::query::Providers;
|
use rustc_middle::query::Providers;
|
||||||
use rustc_middle::ty::{
|
use rustc_middle::ty::{
|
||||||
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
|
self, EarlyBinder, ExistentialPredicateStableCmpExt as _, GenericArgs, Ty, TyCtxt,
|
||||||
|
@ -901,23 +902,59 @@ fn contains_illegal_impl_trait_in_trait<'tcx>(
|
||||||
fn_def_id: DefId,
|
fn_def_id: DefId,
|
||||||
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
ty: ty::Binder<'tcx, Ty<'tcx>>,
|
||||||
) -> Option<MethodViolationCode> {
|
) -> Option<MethodViolationCode> {
|
||||||
// This would be caught below, but rendering the error as a separate
|
let ty = tcx.liberate_late_bound_regions(fn_def_id, ty);
|
||||||
// `async-specific` message is better.
|
|
||||||
if tcx.asyncness(fn_def_id).is_async() {
|
if tcx.asyncness(fn_def_id).is_async() {
|
||||||
return Some(MethodViolationCode::AsyncFn);
|
// FIXME(async_fn_in_dyn_trait): Think of a better way to unify these code paths
|
||||||
|
// to issue an appropriate feature suggestion when users try to use AFIDT.
|
||||||
|
// Obviously we must only do this once AFIDT is finished enough to actually be usable.
|
||||||
|
if tcx.features().async_fn_in_dyn_trait() {
|
||||||
|
let ty::Alias(ty::Projection, proj) = *ty.kind() else {
|
||||||
|
bug!("expected async fn in trait to return an RPITIT");
|
||||||
|
};
|
||||||
|
assert!(tcx.is_impl_trait_in_trait(proj.def_id));
|
||||||
|
|
||||||
|
// FIXME(async_fn_in_dyn_trait): We should check that this bound is legal too,
|
||||||
|
// and stop relying on `async fn` in the definition.
|
||||||
|
for bound in tcx.item_bounds(proj.def_id).instantiate(tcx, proj.args) {
|
||||||
|
if let Some(violation) = bound
|
||||||
|
.visit_with(&mut IllegalRpititVisitor { tcx, allowed: Some(proj) })
|
||||||
|
.break_value()
|
||||||
|
{
|
||||||
|
return Some(violation);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(RPITIT): Perhaps we should use a visitor here?
|
|
||||||
ty.skip_binder().walk().find_map(|arg| {
|
|
||||||
if let ty::GenericArgKind::Type(ty) = arg.unpack()
|
|
||||||
&& let ty::Alias(ty::Projection, proj) = ty.kind()
|
|
||||||
&& tcx.is_impl_trait_in_trait(proj.def_id)
|
|
||||||
{
|
|
||||||
Some(MethodViolationCode::ReferencesImplTraitInTrait(tcx.def_span(proj.def_id)))
|
|
||||||
} else {
|
|
||||||
None
|
None
|
||||||
|
} else {
|
||||||
|
// Rendering the error as a separate `async-specific` message is better.
|
||||||
|
Some(MethodViolationCode::AsyncFn)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ty.visit_with(&mut IllegalRpititVisitor { tcx, allowed: None }).break_value()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct IllegalRpititVisitor<'tcx> {
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
allowed: Option<ty::AliasTy<'tcx>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalRpititVisitor<'tcx> {
|
||||||
|
type Result = ControlFlow<MethodViolationCode>;
|
||||||
|
|
||||||
|
fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
|
||||||
|
if let ty::Alias(ty::Projection, proj) = *ty.kind()
|
||||||
|
&& Some(proj) != self.allowed
|
||||||
|
&& self.tcx.is_impl_trait_in_trait(proj.def_id)
|
||||||
|
{
|
||||||
|
ControlFlow::Break(MethodViolationCode::ReferencesImplTraitInTrait(
|
||||||
|
self.tcx.def_span(proj.def_id),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
ty.super_visit_with(self)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn provide(providers: &mut Providers) {
|
pub(crate) fn provide(providers: &mut Providers) {
|
||||||
|
|
14
tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs
Normal file
14
tests/ui/feature-gates/feature-gate-async-fn-in-dyn-trait.rs
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
trait Foo {
|
||||||
|
async fn bar(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn takes_dyn_trait(x: &dyn Foo) {
|
||||||
|
//~^ ERROR the trait `Foo` cannot be made into an object
|
||||||
|
x.bar().await;
|
||||||
|
//~^ ERROR the trait `Foo` cannot be made into an object
|
||||||
|
//~| ERROR the trait `Foo` cannot be made into an object
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
|
@ -0,0 +1,48 @@
|
||||||
|
error[E0038]: the trait `Foo` cannot be made into an object
|
||||||
|
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:7:30
|
||||||
|
|
|
||||||
|
LL | async fn takes_dyn_trait(x: &dyn Foo) {
|
||||||
|
| ^^^^^^^ `Foo` cannot be made into an object
|
||||||
|
|
|
||||||
|
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>
|
||||||
|
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
|
||||||
|
|
|
||||||
|
LL | trait Foo {
|
||||||
|
| --- this trait cannot be made into an object...
|
||||||
|
LL | async fn bar(&self);
|
||||||
|
| ^^^ ...because method `bar` is `async`
|
||||||
|
= help: consider moving `bar` to another trait
|
||||||
|
|
||||||
|
error[E0038]: the trait `Foo` cannot be made into an object
|
||||||
|
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:7
|
||||||
|
|
|
||||||
|
LL | x.bar().await;
|
||||||
|
| ^^^ `Foo` cannot be made into an object
|
||||||
|
|
|
||||||
|
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>
|
||||||
|
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
|
||||||
|
|
|
||||||
|
LL | trait Foo {
|
||||||
|
| --- this trait cannot be made into an object...
|
||||||
|
LL | async fn bar(&self);
|
||||||
|
| ^^^ ...because method `bar` is `async`
|
||||||
|
= help: consider moving `bar` to another trait
|
||||||
|
|
||||||
|
error[E0038]: the trait `Foo` cannot be made into an object
|
||||||
|
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:9:5
|
||||||
|
|
|
||||||
|
LL | x.bar().await;
|
||||||
|
| ^^^^^^^ `Foo` cannot be made into an object
|
||||||
|
|
|
||||||
|
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>
|
||||||
|
--> $DIR/feature-gate-async-fn-in-dyn-trait.rs:4:14
|
||||||
|
|
|
||||||
|
LL | trait Foo {
|
||||||
|
| --- this trait cannot be made into an object...
|
||||||
|
LL | async fn bar(&self);
|
||||||
|
| ^^^ ...because method `bar` is `async`
|
||||||
|
= help: consider moving `bar` to another trait
|
||||||
|
|
||||||
|
error: aborting due to 3 previous errors
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0038`.
|
Loading…
Add table
Add a link
Reference in a new issue