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

Type inference fails to determine closure argument type #12679

Open
edwardw opened this issue Mar 4, 2014 · 14 comments
Open

Type inference fails to determine closure argument type #12679

edwardw opened this issue Mar 4, 2014 · 14 comments
Labels
A-closures Area: Closures (`|…| { … }`) A-inference Area: Type inference C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.

Comments

@edwardw
Copy link
Contributor

edwardw commented Mar 4, 2014

The following fails to compile:

pub fn main() {
  let mut xs = HashMap::<(u32, u32), u32>::new();
  let new_el = |&_| 30;  // error: the type of this value must be known in this context

  xs.insert((1,1), 10);
  xs.insert((2,2), 20);
  xs.find_or_insert_with((3,3), new_el);

  println!("{}", xs);
}

The argument type must be explicitly spelled out:

let new_el = |_: &(u32, u32)| 30;

Should the type inference work here?

@huonw
Copy link
Member

huonw commented Mar 4, 2014

What happens of you write the definition of new_el inline at the point-of-use?

@edwardw
Copy link
Contributor Author

edwardw commented Mar 4, 2014

If writing inline at the point of use, it works:

xs.find_or_insert_with((3,3), |_| 30);

@steveklabnik
Copy link
Member

This API is gone now, and I am bad with the new Entry API. @gankro ?

@steveklabnik steveklabnik added the A-closures Area: Closures (`|…| { … }`) label Jan 23, 2015
@Gankra
Copy link
Contributor

Gankra commented Jan 23, 2015

use std::collections::HashMap;

pub fn main() {
  let mut xs = HashMap::<(u32, u32), u32>::new();
  let new_el = |v| v.insert(30);  // error: the type of this value must be known in this context

  xs.insert((1,1), 10);
  xs.insert((2,2), 20);
  xs.entry((3,3)).get().unwrap_or_else(new_el);

  println!("{}", xs);
}
<anon>:5:20: 5:32 error: the type of this value must be known in this context
<anon>:5   let new_el = |v| v.insert(30);  // error: the type of this value must be known in this context
                            ^~~~~~~~~~~~
<anon>:5:16: 5:32 error: can't infer the "kind" of the closure, explicitly annotate it. e.g. `|&:| {}`
<anon>:5   let new_el = |v| v.insert(30);  // error: the type of this value must be known in this context
                        ^~~~~~~~~~~~~~~~
<anon>:11:18: 11:20 error: the trait `core::fmt::String` is not implemented for the type `std::collections::hash::map::HashMap<(u32, u32), u32>`
<anon>:11   println!("{}", xs);
                           ^~
note: in expansion of format_args!
<std macros>:2:42: 2:75 note: expansion site
<std macros>:1:1: 2:77 note: in expansion of println!
<anon>:11:3: 11:22 note: expansion site
error: aborting due to 3 previous errors
playpen: application terminated with error code 101
Program ended.

Seems to basically do the same thing.

@eefriedman
Copy link
Contributor

Another related testcase:

#![feature(std_misc)]
use std::collections::HashMap;
use std::collections::hash_map::VacantEntry;
pub fn main() {
  let mut xs = HashMap::<(u32, u32), u32>::new();
  let new_el = |v:VacantEntry<(u32, u32),u32>| v.insert(30);
  xs.insert((1,1), 10);
  xs.insert((2,2), 20);
  xs.entry((3,3)).get().unwrap_or_else(new_el);
  println!("{:?}", xs);
}

gives error: cannot infer an appropriate lifetime for lifetime parameter 'a due to conflicting requirements

@arcnmx
Copy link
Contributor

arcnmx commented Aug 6, 2015

Have another related/simplified test case:

(|x| x.count())(0u8..5)

fails to resolve, while the following works:

(|x: ::std::ops::Range<_>| x.count())(0u8..5)

@steveklabnik
Copy link
Member

Triage: this issue is kind of a general one, with lots of cases. I'm not sure how much of this is intended to get resolved, and how much of this is scatted across other issues on the tracker.

@steveklabnik
Copy link
Member

#27828 has another instance of this.

@Mark-Simulacrum Mark-Simulacrum added the A-inference Area: Type inference label May 22, 2017
@Mark-Simulacrum Mark-Simulacrum added the C-enhancement Category: An issue proposing an enhancement or a PR with one. label Jul 20, 2017
@estebank
Copy link
Contributor

estebank commented Aug 10, 2018

Current output:

error[E0282]: type annotations needed
 --> src/main.rs:4:16
  |
4 |   let new_el = |&_| 30;  // error: the type of this value must be known in this context
  |       ------   ^^^^^^^ cannot infer type for `[closure@src/main.rs:4:16: 4:23]`
  |       |
  |       consider giving `new_el` a type

Edit: current output:

error[E0282]: type annotations needed for the closure `fn(&_) -> i32`
 --> src/main.rs:4:16
  |
4 |   let new_el = |&_| 30;  // error: the type of this value must be known in this context
  |                ^^^^^^^ cannot infer type for `[closure@src/main.rs:4:16: 4:23]`
  |
help: give this closure an explicit return type without `_` placeholders
  |
4 |   let new_el = |&_| -> i32 { 30 };  // error: the type of this value must be known in this context
  |                     ^^^^^^^^    ^

@sweihub

This comment has been minimized.

@sweihub

This comment has been minimized.

@estebank

This comment has been minimized.

@Lancern
Copy link

Lancern commented Dec 31, 2021

It's the last day of 2021, and I still met a similar problem. The following code snippet works:

fn set_callback<F>(_: F)
where
    F: FnOnce(&mut [u8])
{ }

fn foo() {
    set_callback(|_| ());
}

But the following does not:

fn set_callback<F>(_: Option<F>)
where
    F: FnOnce(&mut [u8])
{ }

fn foo() {
    set_callback(Some(|_| ()));
}

bors added a commit to rust-lang-ci/rust that referenced this issue Jul 25, 2022
@estebank
Copy link
Contributor

Current output for the last example:

error[E0308]: mismatched types
 --> f71.rs:7:5
  |
7 |     set_callback(Some(|_| ()));
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ one type is more general than the other
  |
  = note: expected trait `for<'a> FnOnce<(&'a mut [u8],)>`
             found trait `FnOnce<(&mut [u8],)>`
note: this closure does not fulfill the lifetime requirements
 --> f71.rs:7:23
  |
7 |     set_callback(Some(|_| ()));
  |                       ^^^
note: the lifetime requirement is introduced here
 --> f71.rs:3:8
  |
3 |     F: FnOnce(&mut [u8])
  |        ^^^^^^^^^^^^^^^^^
help: consider specifying the type of the closure parameters
  |
7 |     set_callback(Some(|_: &_| ()));
  |                       ~~~~~~~

error: implementation of `FnOnce` is not general enough
 --> f71.rs:7:5
  |
7 |     set_callback(Some(|_| ()));
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ implementation of `FnOnce` is not general enough
  |
  = note: closure with signature `fn(&'2 mut [u8])` must implement `FnOnce<(&'1 mut [u8],)>`, for any lifetime `'1`...
  = note: ...but it actually implements `FnOnce<(&'2 mut [u8],)>`, for some specific lifetime `'2`

@jieyouxu jieyouxu added T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue. labels Dec 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-closures Area: Closures (`|…| { … }`) A-inference Area: Type inference C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-types Relevant to the types team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests