Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unexpected behaviour when calling associated async function of a trait with default implementations #107002

Closed
Samzyre opened this issue Jan 17, 2023 · 6 comments · Fixed by #108203
Assignees
Labels
C-bug Category: This is a bug.

Comments

@Samzyre
Copy link

Samzyre commented Jan 17, 2023

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
@Samzyre Samzyre added the C-bug Category: This is a bug. label Jan 17, 2023
@compiler-errors
Copy link
Member

I can take a look into this

@LastExceed
Copy link

LastExceed commented Jan 29, 2023

there is more to this, not sure if it's covered by #107013: if the implementations of default_impl vary in their number of await points, then the program can crash with all sorts of errors (segfault, stackoverflow, etc) - example

@compiler-errors
Copy link
Member

Yea, it should be covered

@fasterthanlime
Copy link
Contributor

I've made an MVCE for essentially the same issue, if that can be helpful: https://github.com/fasterthanlime/gh-107528

fasterthanlime added a commit to bearcove/loona that referenced this issue Feb 2, 2023
@fasterthanlime
Copy link
Contributor

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

@LastExceed
Copy link

@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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment