Skip to content

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

Closed

Description

@Samzyre

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

Activity

  1. compiler-errors commented on Jan 17, 2023

    @compiler-errors
    Contributor

    I can take a look into this

  2. LastExceed commented on Jan 29, 2023

    @LastExceed
    Contributor

    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

  3. compiler-errors commented on Jan 29, 2023

    @compiler-errors
    Contributor

    Yea, it should be covered

  4. fasterthanlime commented on Jan 31, 2023

    @fasterthanlime
    Contributor

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

  5. fasterthanlime commented on Feb 2, 2023

    @fasterthanlime
    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

  6. added a commit that references this issue on Feb 19, 2023
    d2aef58
  7. LastExceed commented on Feb 21, 2023

    @LastExceed
    Contributor

    @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

Metadata

Metadata

Labels

C-bugCategory: This is a bug.

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions