Skip to content

Explicitly stated argument-type of a closure gets overwritten by its type alias #100800

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

Closed
BattyBoopers opened this issue Aug 20, 2022 · 5 comments · Fixed by #101753
Closed

Explicitly stated argument-type of a closure gets overwritten by its type alias #100800

BattyBoopers opened this issue Aug 20, 2022 · 5 comments · Fixed by #101753
Assignees
Labels
A-closures Area: Closures (`|…| { … }`) C-bug Category: This is a bug. F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` requires-nightly This issue requires a nightly compiler in some way.

Comments

@BattyBoopers
Copy link

BattyBoopers commented Aug 20, 2022

I tried this code:

#![feature(type_alias_impl_trait,)]

trait Anything {}
impl<T> Anything for T {}
type Input = impl Anything;
fn run<F: FnOnce(Input) -> ()>(f: F, i: Input) {
    f(i);
}

fn main() {
    run(|x: u32| {println!("{x}");}, 0);
}

The type of the closure's argument is explicitly stated and not inferred. Therefore, the closure-body should be aware of the type of its argument as it was stated (u32) and the code should compile correctly.

Instead, this code behaves as if the type was inferred to be its type alias (Input). This hides the Display implementation of u32 and results in an error:

error[E0277]: `Input` doesn't implement `std::fmt::Display`
  --> src/main.rs:11:30
   |
11 |     run(|x: u32| {println!("{x}");}, 0);
   |                              ^ `Input` cannot be formatted with the default formatter
   |
   = help: the trait `std::fmt::Display` is not implemented for `Input`
   = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
   = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)

Another way to look at this is that if

|x: u32| {println!("{x}");}

is valid on its own without requiring the inferring of any types, then doing

run(|x: u32| {println!("{x}");}, 0);

should not cause any changes in semantics inside the closure-body.

Meta

rustc --version --verbose:

rustc 1.65.0-nightly (0b79f758c 2022-08-18)
binary: rustc
commit-hash: 0b79f758c9aa6646606662a6d623a0752286cd17
commit-date: 2022-08-18
host: x86_64-unknown-linux-gnu
release: 1.65.0-nightly
LLVM version: 15.0.0
@BattyBoopers BattyBoopers added the C-bug Category: This is a bug. label Aug 20, 2022
@BattyBoopers
Copy link
Author

Anything? Not even anyone adding the appropriate tags? I can't do that myself.

@QuineDot
Copy link

QuineDot commented Sep 5, 2022

@rustbot label +A-closures +F-type_alias_impl_trait +requires-nightly

@rustbot rustbot added A-closures Area: Closures (`|…| { … }`) F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` requires-nightly This issue requires a nightly compiler in some way. labels Sep 5, 2022
@oli-obk oli-obk self-assigned this Sep 5, 2022
@oli-obk
Copy link
Contributor

oli-obk commented Sep 8, 2022

Triage: definitely a bug that should be fixed, but not a blocker for stabilization, as we can backwards compatibly fix it.

@oli-obk oli-obk removed their assignment Sep 8, 2022
@BattyBoopers
Copy link
Author

BattyBoopers commented Sep 9, 2022

Triage: definitely a bug that should be fixed, but not a blocker for stabilization, as we can backwards compatibly fix it.

I'm not so sure this is the case. This bug doesn't necessarily lead to a compile error, but actually changes the semantics of the code.
To make this more clear, I modified the example a bit:

#![feature(type_alias_impl_trait)]

trait Foo {
    fn foo(&self) {println!("A");}
}
impl<T> Foo for T {}

struct B;
impl B {
    fn foo(&self) {println!("B");}
}

type Input = impl Foo;
fn run1<F: FnOnce(Input)>(f: F, i: Input) {f(i)}
fn run2<F: FnOnce(B)>(f: F, i: B) {f(i)}

fn main() {
    run1(|x: B| {x.foo()}, B);
    run2(|x: B| {x.foo()}, B);
}

which prints

A
B

instead of

B
B

@oli-obk
Copy link
Contributor

oli-obk commented Sep 9, 2022

OK, that is very wrong obviously. Thanks!

@oli-obk oli-obk self-assigned this Sep 9, 2022
@oli-obk oli-obk moved this from Todo to In Progress in type alias impl trait stabilization Sep 9, 2022
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Sep 15, 2022
…ler-errors

Prefer explict closure sig types over expected ones

fixes rust-lang#100800

Previously we only checked that given closure arguments are equal to expected closure arguments, but now we choose the given closure arguments for the signature that is used when type checking the closure body, and keep the other signature for the type of the closure as seen outside of it.
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this issue Sep 15, 2022
…ler-errors

Prefer explict closure sig types over expected ones

fixes rust-lang#100800

Previously we only checked that given closure arguments are equal to expected closure arguments, but now we choose the given closure arguments for the signature that is used when type checking the closure body, and keep the other signature for the type of the closure as seen outside of it.
@bors bors closed this as completed in edf9e5e Sep 16, 2022
Repository owner moved this from In Progress to Done in type alias impl trait stabilization Sep 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`) C-bug Category: This is a bug. F-type_alias_impl_trait `#[feature(type_alias_impl_trait)]` requires-nightly This issue requires a nightly compiler in some way.
Development

Successfully merging a pull request may close this issue.

4 participants