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

if b { x } else { y } requires identical types for x and y #4025

Closed
ben0x539 opened this issue Nov 23, 2012 · 10 comments
Closed

if b { x } else { y } requires identical types for x and y #4025

ben0x539 opened this issue Nov 23, 2012 · 10 comments
Assignees
Labels
E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.

Comments

@ben0x539
Copy link
Contributor

This fails:

fn print(b: bool, s1: &str, s2: &str) {
    io::println(if b { s1 } else { s2 });
}
foo.rs:2:33: 2:39 error: mismatched types: expected `&/str` but found `&/str` (lifetime mismatch)
foo.rs:2     io::println(if b { s1 } else { s2 });
                                          ^~~~~~
foo.rs:1:38: 3:1 note: the anonymous lifetime #1 defined on the block at 1:38...
[...]
foo.rs:1:38: 3:1 note: ...does not necessarily outlive the anonymous lifetime #2 defined on the block at 1:38
[...]

while this works (giving the two borrowed pointers the same lifetime):

fn print(b: bool, s1: &r/str, s2: &r/str) {
    io::println(if b { s1 } else { s2 });
}

as does this (not returning the pointers through if {} else {}):

fn print(b: bool, s1: &str, s2: &str) {
    let mut s: &str;
    if b { s = s1; } else { s = s2; }
    io::println(s);
}

@nikomatsakis suggested the first example should work and that the type checker
should be content if the types of the two arms of the if{}else{} expression
have a common supertype, rather than requiring them to be the same.

@catamorphism
Copy link
Contributor

I agree -- the type of the if should be the most specific supertype (LUB) of the types of the consequent and alternative.

@bblum
Copy link
Contributor

bblum commented Dec 2, 2012

I believe this is the idea of "intersection types".

I remember discussing this with another PL researcher at CMU during another project of mine, especially w.r.t. the case of the intersected type being a function (in which the subtyping has to contravary in the argument). Our conclusion was that simply switching between intersection and union isn't actually sound (unless the subtyping relation is a total ordering, which in rust it's not). I haven't seen any literature on the subject but could maybe remember the counterexample if I had to.

@catamorphism
Copy link
Contributor

Maybe I'm missing something, but I don't think this requires intersection types, just subtyping? I don't think Rust allows subtyping on function types anyway, though I could be wrong!

@nikomatsakis
Copy link
Contributor

This is a simple matter of subtyping and yes Rust does support subtyping on function types.

@catamorphism
Copy link
Contributor

Nominating for milestone 1, well-defined

@graydon
Copy link
Contributor

graydon commented Jul 18, 2013

Updated example, still fails:

fn print<'a,'b>(b: bool, s1: &'a str, s2: &'b str) {
    println(if b { s1 } else { s2 });
}

fn main() {}

@pcwalton suggests that @nikomatsakis is rewriting the inference pass to use subtyping in even-fewer places than currently used, so this is probably never going to work. Paging @nikomatsakis for confirmation.

@graydon
Copy link
Contributor

graydon commented Jul 18, 2013

accepted for well-defined milestone

@nikomatsakis
Copy link
Contributor

Couple of things:

  1. I changed the type rule for if in the code to compute the type of the if as the LUB of the then/else types. This is why the first example works.
  2. I ... don't know why the second example fails. That seems like a bug.
  3. This is independent from how we do inference.

@ghost ghost assigned nikomatsakis Jul 19, 2013
@nikomatsakis
Copy link
Contributor

@graydon for me this example type checks:

fn print<'a,'b>(b: bool, s1: &'a str, s2: &'b str) {
    println(if b { s1 } else { s2 });
}

fn main() {}

@alexcrichton
Copy link
Member

This appears to have been fixed (both cases in the original code). Including a test in #8485

@huonw huonw closed this as completed in 12099ce Sep 3, 2013
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
E-needs-test Call for participation: An issue has been fixed and does not reproduce, but no test has been added.
Projects
None yet
Development

No branches or pull requests

6 participants