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 ambiguity not reported when it may exist? #21878

Closed
alexcrichton opened this Issue Feb 3, 2015 · 10 comments

Comments

Projects
None yet
8 participants
@alexcrichton
Copy link
Member

alexcrichton commented Feb 3, 2015

trait Foo {}
impl Foo for () {}
impl Foo for i32 {}

struct Error;
impl Error {
    fn foo(&self) -> ! { loop {} }
}

fn bar<T: Foo>() -> Result<T, Error> { loop {} }

fn main() {
    // what type does `_` have? is it `()` or is it `i32`?
    let _ = bar().unwrap_or_else(|e| e.foo());
}

This code compiles, but I find it somewhat surprising as I have no type annotations on _ so the compiler shouldn't know what type it is (I presume it selects one of () or i32 perhaps).

This issue is motivated by docopt/docopt.rs#89 and isn't necessarily a bug per se, but it does seem somewhat surprising so I just want to make sure it is intended.

@alexcrichton

This comment has been minimized.

Copy link
Member Author

alexcrichton commented Feb 3, 2015

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Feb 3, 2015

(it seems like the compiler must be deducing the type is (), since removing that impl causes the compile to fail and removing the other causes it to succeed...)

(Update:: but then again, explicitly instantiating bar to i32 via bar::<i32> within main causes the compiler to choose i32 for the type. So, it seems like it is committing early on for some reason even though it should not be, AFAICT.)

@kmcallister kmcallister changed the title Ambiguity not reported when it may exist? Type ambiguity not reported when it may exist? Feb 3, 2015

@P1start

This comment has been minimized.

Copy link
Contributor

P1start commented Feb 3, 2015

()-ness confirmed:

use std::default::Default;

trait Foo: Default { fn foo(); }
impl Foo for () { fn foo() { println!("()"); } }
impl Foo for i32 { fn foo() { println!("i32"); } }

struct Error;
impl Error {
    fn foo(&self) -> ! { loop {} }
}

fn bar<T: Foo>() -> Result<T, Error> { loop {} }

fn baz<T: Foo>(_: &T) { <T as Foo>::foo(); }

fn main() {
    let mut a = Default::default();
    |&mut:| a = bar().unwrap_or_else(|e| e.foo());
    baz(&a); // ()
}

Smaller case:

trait Foo { fn foo(&self) -> Self; }

fn foo<T: Foo>(x: T) -> T { x.foo() }

fn main() {
    // foo(x) and x.foo() should be equivalent, but aren’t

    // Bad:
    let _ = foo(loop {}); // error: the trait `Foo` is not implemented for the type `()`
    // Good:
    let _ = loop {}.foo(); // error: the type of this value must be known in this context
}
@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Feb 3, 2015

This is probably because of the implicit fallback for bottom variables to ().

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Feb 3, 2015

(from discussion with @nikomatsakis , this may have been injected by PR #17603 )

@pnkfelix

This comment has been minimized.

Copy link
Member

pnkfelix commented Feb 5, 2015

deciding what to do with this ticket is a 1.0 polish issue. (We would like to investigate consequences of removing the fallback to (), in particular)

@pnkfelix pnkfelix added the P-medium label Feb 5, 2015

@pnkfelix pnkfelix added this to the 1.0 milestone Feb 5, 2015

@pnkfelix pnkfelix removed the I-nominated label Feb 5, 2015

@edwardw

This comment has been minimized.

Copy link
Contributor

edwardw commented Feb 6, 2015

It so happened that I fiddled with numeric and bot type fallbacks when trying to solve type inference issue for the new range expression. That branch reports the following error for the given testcase:

error: unable to infer enough type information about _; type annotations required [E0282]
let _ = bar().unwrap_or_else(|e| e.foo());

I'm looking into it now.

edwardw added a commit to edwardw/rust that referenced this issue Feb 6, 2015

Make bottom type fallback lazy
PR rust-lang#17603 introduced bottom type fallback but did it a bit too
eagerly. This patch makes the fallback lazy so that `typeck` can run
its cause and detect as many type errors as possible with regard to
diverging types.

Closes rust-lang#21878

@nikomatsakis nikomatsakis self-assigned this Apr 2, 2015

@steveklabnik steveklabnik removed this from the 1.0 milestone May 21, 2015

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Jul 14, 2016

Unassigning @nikomatsakis from ancient bug.

@brson

This comment has been minimized.

Copy link
Contributor

brson commented Jul 14, 2016

Nominating for close.

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Aug 4, 2016

Agreed, no bug here. TL;DR inference fallback can be surprising. Also not so relevant with !.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.