rust-lang/rust — pull request #19891 by nikomatsakis (2014-12-15 21:32:16+00:00)
Title: Implement unique types per fn item, rather than having all fn items have fn pointer type

This is part of the coercion RFC but also makes sense given unboxed closures. The idea is that every fn item has its own type. This type can be coerced to a fn pointer but is not a fn pointer. This PR does almost all the end-user visible changes, but leaves one thing undone: the representation of an instance of a "fn item type" is still a fn pointer at runtime. A later PR will have to change them to zero-sized values (I'll open an isssue on this).

This is a [breaking-change]. In general, the coercion rules ensure that code which used to take a `fn()` type continus to work, but there are some patterns that need to be changed to insert explicit coercions.

Example 1:

Right now coercions are not propagated into if/match arms. Therefore you (often) have to insert them manually:

```rust
fn foo(x: int) -> int { x }
fn bar(x: int) -> int { x + 1}

// old:
// if some_cond { foo } else { bar }

// new:
if some_cond { foo as fn(int) -> int } else { bar as fn(int) -> int }
```

We plan to fix this so that coercions propagate through if/match, and therefore these coercions should either become unnecessary or (eventually) be something you place at the top-level:

```rust
let x: fn(int) -> int = if cond { foo } else { bar }; // does not work yet
```

Example 2:

Generic functions are another place where coercions often fail to trigger. Example:

```rust
fn foo(x: int) -> int { x }

fn optional() -> Option int> {
// Old:
// Some(foo) // here the type argument on `Some` is inferred to be the fn item type

// New:
Some(foo as fn(int) -> int)
}
```

This one may or may not get fixed going forward; inserting coercions in cases like these involves subtle changes to program semantics that may not be appropriate.

r? @nick29581