Unexpected behaviour when calling associated async function of a trait with default implementations
Samzyre opened this issue · 6 comments
I tried this code:
https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=e1f645e0ffe95f137fc42c12e783488b
#![feature(async_fn_in_trait)]
trait AsyncTrait {
async fn default_impl() -> &'static str {
"A"
}
async fn call_default_impl() -> &'static str {
Self::default_impl().await
}
}
trait SyncTrait {
fn default_impl() -> &'static str {
"A"
}
fn call_default_impl() -> &'static str {
Self::default_impl()
}
}
struct AsyncType;
impl AsyncTrait for AsyncType {
async fn default_impl() -> &'static str {
"B"
}
}
struct SyncType;
impl SyncTrait for SyncType {
fn default_impl() -> &'static str {
"B"
}
}
#[tokio::main]
async fn main() {
let a = AsyncType::call_default_impl().await;
let b = SyncType::call_default_impl();
println!("{a}, {b}");
}I expected to see this happen:
SyncType::call_default_impl calls default_impl from impl SyncTrait for SyncType.
My expectation was the same for AsyncType::call_default_impl of the same pattern.
Instead, this happened:
AsyncType::call_default_impl calls default_impl from the trait's default implementation,
instead of the one in impl AsyncTrait for AsyncType.
So the code prints A, B
Meta
rustc --version --verbose:
rustc 1.68.0-nightly (afaf3e07a 2023-01-14)
binary: rustc
commit-hash: afaf3e07aaa7ca9873bdb439caec53faffa4230c
commit-date: 2023-01-14
host: x86_64-pc-windows-msvc
release: 1.68.0-nightly
LLVM version: 15.0.6
I can take a look into this
Yea, it should be covered
I've made an MVCE for essentially the same issue, if that can be helpful: https://github.com/fasterthanlime/gh-107528
For anyone hitting this: seems like this a decent workaround for the time being is to go through a freestanding function that takes an &impl Trait:
bearcove/loona@2cae637#diff-b543f39ca4defdc86457f06aaef64e5fdad5fda92c91b4a98f486e7ab7b3b052R81-R87
@compiler-errors #108203 didn't fully fix this. the bug still persists when using polymorphic indirection via specialization:
#![feature(async_fn_in_trait)]
#![feature(min_specialization)]
struct MyStruct;
trait MyTrait<T> {
async fn foo(_: T);
}
impl<T> MyTrait<T> for MyStruct {
default async fn foo(_: T) {
println!("default");
}
}
impl MyTrait<i32> for MyStruct {
async fn foo(_: i32) {
println!("specialized");
}
}
#[tokio::main]
async fn main() {
MyStruct::foo(42).await;
indirection(42).await;
}
async fn indirection<T>(x: T) {
//explicit type coercion is currently necessary because of https://github.com/rust-lang/rust/issues/67918
<MyStruct as MyTrait<T>>::foo(x).await;
}(note that <MyStruct as MyTrait<i32>>::foo(42).await works just fine, so #67918 probably isn't at fault)
output is
specialized
default
should be
specialized
specialized