Skip to content

Inflexible function signature for Interner trait #185

Description

@h3har

The function signature for Interner::display_merged_solvables is:

fn display_merged_solvables(&self, solvables: &[SolvableId]) -> impl std::fmt::Display + '_

However, the elided lifetimes prevent returning a Display-able struct that borrows from both arguments. This prevents you from writing a display implementation that avoids allocating or cloning unnecessarily, which might look like:

fn display_merged_solvables(&self, solvables: &[SolvableId]) -> impl std::fmt::Display + '_ {
    struct DisplayMergedSolvables<'a, 'b>(&'a ProviderType, &'b [SolvableId]);
    
    impl<'a, 'b> std::fmt::Display for DisplayMergedSolvables<'a, 'b> {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            todo!("insert implementation here")
        }
    }

    DisplayMergedSolvables(self, solvables)
}

This is because of how Rust's lifetime elision rules work. In particular, see the following from the Rustnomicon:

Elision rules are as follows:

  • Each elided lifetime in input position becomes a distinct lifetime parameter.
  • ...
  • If there are multiple input lifetime positions, but one of them is &self or &mut self, the lifetime of self is assigned to all elided output lifetimes.

In particular, the return value cannot borrow from solvables, since solvables has an independent lifetime of self, and - as per the above rules - the returned lifetime must equal the lifetime of self.

Adding lifetime parameters to the trait would be a breaking change, since they would conflict with the original trait definition. Perhaps if a new major release is added in the future that this problem is avoided with specific lifetime bounds. Otherwise, this is quite a minor issue.

Since the other methods of the Interner trait only borrow from self, this method is the only one that is affected.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions