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

Confusing lifetime inference error / error messages #30387

Closed
Tracked by #42516
jld opened this issue Dec 15, 2015 · 3 comments
Closed
Tracked by #42516

Confusing lifetime inference error / error messages #30387

jld opened this issue Dec 15, 2015 · 3 comments
Labels
A-diagnostics Area: Messages for errors, warnings, and lints

Comments

@jld
Copy link
Contributor

jld commented Dec 15, 2015

I'm not sure whether this is code that ought to be valid but the lifetime inference isn't clever enough for, or if it's invalid but subtyping makes it hard to give a good error message about why. This part is reduced from code in the regex crate (specifically Captures):

use std::ops::Index;
struct StrHolder<'a>(&'a str);
impl<'a> Index<&'a str> for StrHolder<'a> {
    type Output = str;
    fn index<'b>(&'b self, _name: &str) -> &'b str { self.0 }
}

And this tries to use it:

pub fn problem(s: &str) -> usize {
    let sh = StrHolder(s);
    sh["whatever"].len()
}

Which leads to this:

bounds_thing.rs:10:24: 10:25 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements [E0495]
bounds_thing.rs:10     let sh = StrHolder(s);
                                          ^
bounds_thing.rs:10:14: 10:23 note: first, the lifetime cannot outlive the expression at 10:13...
bounds_thing.rs:10     let sh = StrHolder(s);
                                ^~~~~~~~~
bounds_thing.rs:10:14: 10:23 note: ...so that a type/lifetime parameter is in scope here
bounds_thing.rs:10     let sh = StrHolder(s);
                                ^~~~~~~~~
bounds_thing.rs:10:24: 10:25 note: but, the lifetime must be valid for the expression at 10:23...
bounds_thing.rs:10     let sh = StrHolder(s);
                                          ^
bounds_thing.rs:10:24: 10:25 note: ...so that auto-reference is valid at the time of borrow
bounds_thing.rs:10     let sh = StrHolder(s);
                                          ^

If the impl started like this (which is the PR I'm going to send to regex) then it would work, because there wouldn't be a constraint between the index string and the region parameter on problem (in addition to Index requiring the returned str to have the same lifetime as the StrHolder):

impl<'a, 'i> Index<&'i str> for StrHolder<'a>

The weird part is that making this change, to explicitly coerce the &'static str literal to an unspecified maybe-shorter lifetime, also fixes it:

    sh["whatever" as &str].len()

And this is why I'm wondering if it's more than just a quality-of-error-message issue.

@eefriedman
Copy link
Contributor

You're tying up the lifetimes in a way which doesn't make sense... the following works:

struct StrHolder<'a>(&'a str);
impl<'a, 'b> Index<&'b str> for StrHolder<'a> {
    type Output = str;
    fn index(&self, _name: &str) -> &str { self.0 }
}

@jld
Copy link
Contributor Author

jld commented Dec 18, 2015

In the original context, the impl with the not-quite-right lifetimes was in an external crate I didn't write; I eventually figured out what was going on after enough trial-and-error (and I just now got around to filing rust-lang/regex#143), but it would be nice if the errors could be made clearer.

Also, the fact that explicitly casting a &str to &str (at a point in the code that isn't in any of the error messages, even) affects whether there's a type error makes me wonder if something more is going on here — I can see that it's not conceptually different from needing explicit casts with borrowed/boxed traits, but normally the borrow checker can figure out how to infer them for regions.

@steveklabnik steveklabnik added the A-diagnostics Area: Messages for errors, warnings, and lints label Dec 18, 2015
@steveklabnik steveklabnik removed the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Mar 9, 2017
@Mark-Simulacrum
Copy link
Member

I can't seem to reproduce today, with the below code, so I am going to close. If you can provide an example which reproduces today, please let us know and we'll reopen,

use std::ops::Index;
struct StrHolder<'a>(&'a str);
impl<'a> Index<&'a str> for StrHolder<'a> {
    type Output = str;
    fn index<'b>(&'b self, _name: &str) -> &'b str { self.0 }
}

pub fn problem(s: &str) -> usize {
    let sh = StrHolder(s);
    sh["whatever"].len()
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints
Projects
None yet
Development

No branches or pull requests

4 participants