Skip to content

Implicit and explicit HRTB are not equivalent #38714

Closed
@vickenty

Description

@vickenty
Contributor

A Fn trait bound with implicit lifetimes is not equivalent to the trait bound with explicit lifetimes.

fn foo<F>(f: F) where F: for<'a> Fn(&'a str) -> &'a str {}
fn bar<F>(f: F) where F: Fn(&str) -> &str {}

fn main() {
    foo(|a: &str| a); // Fails
    bar(|a: &str| a); // Works
}

(playpen: https://is.gd/nKZx1O)

I expected that foo and bar would be equivalent and that both calls would compile (or fail to compile the same way).

instead, calling bar compiles fine, but calling foo results in the following error:

rustc 1.14.0 (e8a012324 2016-12-16)
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
 --> <anon>:6:19
  |
6 |     foo(|a: &str| a); // Fails
  |                   ^
  |
note: ...the reference is valid for the lifetime 'a as defined on the block at 6:18...
 --> <anon>:6:19
  |
6 |     foo(|a: &str| a); // Fails
  |                   ^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the block at 6:18
 --> <anon>:6:19
  |
6 |     foo(|a: &str| a); // Fails
  |                   ^
help: consider using an explicit lifetime parameter as shown: fn main()
 --> <anon>:5:1
  |
5 | fn main() {
  | ^

error: aborting due to previous error

Somewhat related (but different) problem about a closure with annotated argument was reported in #22557

Activity

JDemler

JDemler commented on Feb 20, 2017

@JDemler
Contributor

I think I ran into the same problem. Alas, for me, it is not possible to use implicit lifetimes:
playpen

struct UsizeRef<'a> {
    a: &'a usize
}

type RefTo = Box<for<'r> Fn(&'r Vec<usize>) -> UsizeRef<'r>>;

//Compiles
fn ref_to<'a>(vec: &'a Vec<usize>) -> UsizeRef<'a> {
    UsizeRef{ a: &vec[0]}
}

fn main() {
    //Does not compile
    let a: RefTo = Box::new(|vec: &Vec<usize>| {
            UsizeRef{ a: &vec[0] }
        }
    );
}

results in:

rustc 1.15.1 (021bd294c 2017-02-08)
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
  --> <anon>:15:27
   |
15 |             UsizeRef{ a: &vec[0] }
   |                           ^^^^^^
   |
help: consider using an explicit lifetime parameter as shown: fn main()
  --> <anon>:12:1
   |
12 |   fn main() {
   |  _^ starting here...
13 | |     //Does not compile
14 | |     let a: RefTo = Box::new(|vec: &Vec<usize>| {
15 | |             UsizeRef{ a: &vec[0] }
16 | |         }
17 | |     );
18 | | }
   | |_^ ...ending here

error: aborting due to previous error
vickenty

vickenty commented on Feb 20, 2017

@vickenty
ContributorAuthor

@JDemler This problem only shows up if the closure parameter is typed explicitly. Your example compiles if the type annotation is removed: https://is.gd/e5ILB5

JDemler

JDemler commented on Feb 20, 2017

@JDemler
Contributor

Aha. Thank you. Didn't know that was possible!

added
T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.
on May 23, 2017
F001

F001 commented on Sep 2, 2017

@F001
Contributor

I ran into this issue too. The compiler panicked when I was testing @vickenty 's test case.

rustc -V
rustc 1.22.0-nightly (f861b6ee4 2017-09-01)

For the good case, if I declare the closure as a local variable, it also leads to compile error.

fn foo<F>(f: F) where F: for<'a> Fn(&'a str) -> &'a str {}
fn bar<F>(f: F) where F: Fn(&str) -> &str {}

fn main() {
//    foo(|a: &str| a); // Compiler panic
    bar(|a: &str| a); // Works

    let local = |a: &str| a;
    bar(local);  // compile failed
}
added
I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️
on Sep 3, 2017
arielb1

arielb1 commented on Sep 3, 2017

@arielb1
Contributor

This causes ICE: no representative region on beta.

The code not working with a local would be expected, because of the way higher-ranked inference works.

nikomatsakis

nikomatsakis commented on Sep 7, 2017

@nikomatsakis
Contributor

In what sense is this a regression? That is, which code specifically works and where...?

arielb1

arielb1 commented on Sep 7, 2017

@arielb1
Contributor
fn foo<F>(f: F) where F: for<'a> Fn(&'a str) -> &'a str {}
fn bar<F>(f: F) where F: Fn(&str) -> &str {}

fn main() {
    foo(|a: &str| a); // Compiler panic
    bar(|a: &str| a); // Works

    let local = |a: &str| a;
    bar(local);  // compile failed
}

Causes an ICE in beta, none in stable.

nikomatsakis

nikomatsakis commented on Sep 7, 2017

@nikomatsakis
Contributor

triage: P-high

Assigning to myself to investigate.

self-assigned this
on Sep 7, 2017

16 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

A-type-systemArea: Type systemC-bugCategory: This is a bug.I-ICEIssue: The compiler panicked, giving an Internal Compilation Error (ICE) ❄️P-highHigh priorityT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.regression-from-stable-to-nightlyPerformance or correctness regression from stable to nightly.

Type

No type

Projects

No projects

Relationships

None yet

    Development

    No branches or pull requests

      Participants

      @alexcrichton@nikomatsakis@vickenty@arielb1@F001

      Issue actions

        Implicit and explicit HRTB are not equivalent · Issue #38714 · rust-lang/rust