Skip to content
New issue

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

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

Already on GitHub? # to your account

spurious "unused type parameter" error on struct with closure field #37249

Closed
dwrensha opened this issue Oct 18, 2016 · 5 comments
Closed

spurious "unused type parameter" error on struct with closure field #37249

dwrensha opened this issue Oct 18, 2016 · 5 comments

Comments

@dwrensha
Copy link
Contributor

I expect the following code to typecheck:

struct Foo<F, S> where F: Fn(S) -> () {
    f: F
}

but instead it gives the following error:

error[E0392]: parameter `S` is never used
 --> src/main.rs:1:15
  |
1 | struct Foo<F, S> where F: Fn(S) -> ()
  |               ^ unused type parameter
  |
  = help: consider removing `S` or using a marker such as `std::marker::PhantomData`

Removing S from the parameter list does not help:

struct Foo<F> where F: Fn(S) -> () {
    f: F
}
error[E0412]: type name `S` is undefined or not in scope
 --> src/main.rs:1:27
  |
1 | struct Foo<F> where F: Fn(S) -> ()
  |                           ^ undefined or not in scope
  |
  = help: no candidates by the name of `S` found in your project; maybe you misspelled the name or forgot to import an external crate?

Note that there is no error if I box the closure:

struct Foo<S> {
    f: Box<Fn(S) -> ()>,
}
@TimNN
Copy link
Contributor

TimNN commented Oct 18, 2016

This seems to be intentional: #23246 (comment)

@dwrensha
Copy link
Contributor Author

Sure, adding a PhantomData field gets the code to typecheck:

struct Foo<F, S> where F: Fn(S) {
    f: F,
    marker: ::std::marker::PhantomData<Fn(S)>,
}

but why should that be necessary? It looks redundant to me.

@dwrensha
Copy link
Contributor Author

This typechecks, as I would expect:

struct Foo<F, T> where F: Fn() -> T {
    f: F,
}

Why does this succeed while my other examples fail?

@bluss
Copy link
Member

bluss commented Oct 18, 2016

The return type is an associated type of the FnOnce trait (super of Fn). So T is used just like any other equivalent matching with an associated type. Example, this will compile:

struct Foo<I, T> where I: Iterator<Item=T> { iter: I }

(unfortunately the regular trait syntax for closures is unstable, so you can't skip the type parameter and just use F::Output instead of T.)

@arielb1
Copy link
Contributor

arielb1 commented Oct 18, 2016

@dwrensha

A Rust function can easily take references with different lifetimes, e.g. consider Foo { f: |a| { let _x: &u32 = a; } }. In that case, Foo will have the type Foo<[closure], &'α T> for any α, which would be problematic.

Not a bug.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants