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

'static lifetime elision in associated constants should mirror normal non-associated constants #51370

Open
Boscop opened this issue Jun 5, 2018 · 4 comments
Labels
A-associated-items Area: Associated items (types, constants & functions) A-lifetimes Area: Lifetimes / regions C-feature-request Category: A feature request, i.e: not implemented / a PR. needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Boscop
Copy link

Boscop commented Jun 5, 2018

https://play.rust-lang.org/?gist=8fb655fdb61666de91bd38bfedb537b6&version=stable&mode=debug

const A: &str = "A"; // defaults to 'static

trait Foo {
	const S: &str; // should behave the same
}

impl Foo for () {
	const S: &str = "bar";
}

fn main() {}
error[E0106]: missing lifetime specifier
 --> src/main.rs:4:11
  |
4 |     const S: &str; // should behave the same
  |              ^ expected lifetime parameter

error[E0106]: missing lifetime specifier
 --> src/main.rs:8:14
  |
8 |     const S: &str = "bar";
  |              ^ expected lifetime parameter
@oli-obk
Copy link
Contributor

oli-obk commented Jun 5, 2018

This was explictly discussed tangentially in the rfc (rust-lang/rfcs#1623 (comment)) but in the end decided against. I'd assume this would need an RFC.

@estebank estebank added A-lifetimes Area: Lifetimes / regions A-associated-items Area: Associated items (types, constants & functions) labels Jan 8, 2019
@jonas-schievink jonas-schievink added C-feature-request Category: A feature request, i.e: not implemented / a PR. needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels Oct 4, 2020
@danielhenrymantilla
Copy link
Contributor

If the impl block does not introduce any lifetimes, then defaulting to 'static would be a sensible default. But if lifetime params are in scope, then I think omitting the lifetime should cause an error pointing to at least one non-'static lifetime parameter in scope and asking to disambiguate between 'static and that one.

That seems like a win-win situation w.r.t. the current situation:

  • in the basic cases, it does the Right Thing unambiguously,

  • in the others, it still fails but with a more informative error message.

@rodrimati1992
Copy link
Contributor

rodrimati1992 commented Oct 4, 2020

The impl block doesn't need any lifetime parameters for references to be non-static, all you need is a type parameter.
This code:

struct Foo<T>(T);

impl<T> Foo<T> {
    const FUNC: &'static fn()->T = &||loop{};
}

errors with:

error[E0310]: the parameter type `T` may not live long enough
 --> src/lib.rs:4:5
  |
3 | impl<T> Foo<T> {
  |      - help: consider adding an explicit lifetime bound...: `T: 'static`
4 |     const FUNC: &'static fn()->T = &||loop{};
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ...so that the reference type `&'static fn() -> T` does not outlive the data it points at

The fixed version:

struct Foo<T>(T);

impl<'a, T: 'a> Foo<T> {
    const FUNC: &'a fn() -> T = {
        let func: fn() -> T = || loop {};
        &{ func }
    };
}

I'm using function pointers here, but the same would apply to structs with function pointer fields and/or PhantomData<T>.

@danielhenrymantilla
Copy link
Contributor

For that case, having an error message saying that the default 'static lifetime cannot be applied and that the user either use a different lifetime, or provide a T : 'static bound ought to be enough. I don't see that as a problem (or as an orthogonal problem, we could say), especially when the generic type may not even appear within the constant:

struct Foo<T>(T);

impl<T> Foo<T> {
    const S: & str = ...;
//            ^
//            the only usable lifetime here is `'static`, so we might as well use it.
}
struct Foo<T>(T);

impl<'a, T : 'a> Foo<T> {
    const S: & str = ...;
//            ^
//            two applicable lifetimes in scope, here: `'a` and `'static`; do not favor any.
}

In other words: the only way to "extract" lifetime information out of a type parameter, AFAIK, is through a helper added generic lifetime parameter (and bounds tying them together). Thus, if no generic lifetime parameter is in scope, the only usable lifetime is 'static. If we had "associated lifetimes" then that would be a different story.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-associated-items Area: Associated items (types, constants & functions) A-lifetimes Area: Lifetimes / regions C-feature-request Category: A feature request, i.e: not implemented / a PR. needs-rfc This change is large or controversial enough that it should have an RFC accepted before doing it. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

6 participants