Skip to content

Better diagnostics for inappropriate lifetime from (large) match statement #85123

@djc

Description

@djc

With this reduced example, I get a nice, specific error message:

use std::borrow::Cow;

enum Foo<'a> {
    Bar(Cow<'a, [u8]>),
    Baz(Cow<'a, [u8]>),
}

impl<'a> Foo<'a> {
    fn to_owned(&self) -> Foo<'static> {
        match self {
            Foo::Bar(x) => Foo::Bar(x.to_owned()),
            Foo::Baz(x) => Foo::Baz(x.to_owned()),
        }
    }
}

Error:

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
  --> src/lib.rs:10:15
   |
10 |         match self {
   |               ^^^^
   |
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 8:6...
  --> src/lib.rs:8:6
   |
8  | impl<'a> Foo<'a> {
   |      ^^
note: ...so that the types are compatible
  --> src/lib.rs:10:15
   |
10 |         match self {
   |               ^^^^
   = note: expected `&Foo<'_>`
              found `&Foo<'a>`
   = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
  --> src/lib.rs:11:28
   |
11 |             Foo::Bar(x) => Foo::Bar(x.to_owned()),
   |                            ^^^^^^^^^^^^^^^^^^^^^^
   = note: expected `Foo<'static>`
              found `Foo<'_>`

However, in this real world case (from rustls/rustls#685), the error message isn't as good:

    pub fn to_owned(&self) -> ClientExtension<'static> {
        use ClientExtension::*;
        match self {
            ECPointFormats(x) => ECPointFormats(x.clone()),
            NamedGroups(x) => NamedGroups(x.clone()),
            SignatureAlgorithms(x) => SignatureAlgorithms(x.clone()),
            ServerName(x) => ServerName(x.iter().map(|y| y.to_owned()).collect()),
            SessionTicketRequest => SessionTicketRequest,
            SessionTicketOffer(x) => SessionTicketOffer(x.to_owned()),
            Protocols(x) => Protocols(x.iter().map(|y| y.to_owned()).collect()),
            SupportedVersions(x) => SupportedVersions(x.clone()),
            KeyShare(x) => KeyShare(x.iter().map(|y| y.to_owned()).collect()),
            PresharedKeyModes(x) => PresharedKeyModes(x.clone()),
            PresharedKey(x) => PresharedKey(x.to_owned()),
            Cookie(x) => Cookie(x.to_owned()),
            ExtendedMasterSecretRequest => ExtendedMasterSecretRequest,
            CertificateStatusRequest(x) => CertificateStatusRequest(x.to_owned()),
            SignedCertificateTimestampRequest => SignedCertificateTimestampRequest,
            TransportParameters(x) => TransportParameters(x.to_owned()),
            TransportParametersDraft(x) => TransportParametersDraft(x.to_owned()),
            EarlyData => EarlyData,
            Unknown(r) => Unknown(r.to_owned()),
        }
    }
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> rustls/src/msgs/handshake.rs:698:15
    |
698 |         match self {
    |               ^^^^
    |
note: first, the lifetime cannot outlive the lifetime `'a` as defined on the impl at 670:6...
   --> rustls/src/msgs/handshake.rs:670:6
    |
670 | impl<'a> ClientExtension<'a> {
    |      ^^
note: ...so that the types are compatible
   --> rustls/src/msgs/handshake.rs:698:15
    |
698 |         match self {
    |               ^^^^
    = note: expected `&ClientExtension<'_>`
               found `&ClientExtension<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the expression is assignable
   --> rustls/src/msgs/handshake.rs:698:9
    |
698 | /         match self {
699 | |             ECPointFormats(x) => ECPointFormats(x.clone()),
700 | |             NamedGroups(x) => NamedGroups(x.clone()),
701 | |             SignatureAlgorithms(x) => SignatureAlgorithms(x.clone()),
...   |
717 | |             Unknown(r) => Unknown(r.to_owned()),
718 | |         }
    | |_________^
    = note: expected `ClientExtension<'static>`
               found `ClientExtension<'_>`

Note that this error does not point to any specific arm, and leaves me to figure out which of the match arms had incorrect lifetimes. In this case, I happened to know which arms were at fault, but in an earlier instance I ended up bisecting the match arms by copy/pasting until I figured out which ones were incorrect.

This happened for me with rustc 1.52.0, but I see the same behavior with a nightly from 2021-04-24.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-diagnosticsArea: Messages for errors, warnings, and lintsT-compilerRelevant to the compiler team, which will review and decide on the PR/issue.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions