Constraining an associated type of a generic parameter
⚓ Rust 📅 2025-12-14 👤 surdeus 👁️ 6Today I've found myself suddenly having to interact with traits with associated types, and I'm not 100% sure how to achieve what I need to achieve. Sorry that this is a bit long, but I'm not sure exactly how much context is needed for what I'm doing to make sense. There's my best-effort TL;DR at the bottom.
Background
I'm parsing a file using the logos crate, and if I encounter a problem, I'd like to pass up a error struct which contains the following information:
struct ParseError
{
// The problematic token, or None if EOF
token: Option<String>,
// Where the token was encountered
location: Range<usize>,
// Programmer description, for context
description: String,
}
To achieve this, I'd like to be able to create an error like so:
ParseError::from_token(lexer, "Something went wrong here")
My proposed function signature looks like:
// 'l is the lifetime that the lexer object has.
// Ctx is the enum type representing the tokens that are acceptable.
// It implements the Logos trait using #[derive(Logos)].
pub fn from_token<'l, Ctx>(lexer: &logos::Lexer<'l, Ctx>, description: &str)
-> Self
where Ctx: logos::Logos<'l>,
And the body of the function would look like this:
{
return Self {
token: Some(lexer.slice().to_owned()),
location: lexer.span(),
description: description.to_owned(),
};
}
The issue I'm having is that lexer.slice().to_owned() needs quite precise constraints on the types/traits that my from_token() function uses.
First of all, using the naive signature above, the linter gives me an error regarding lexer.slice().to_owned():
the method to_owned exists for associated type <<Ctx as Logos<'_>>::Source
as Source>::Slice<'_>, but its trait bounds were not satisfied
the following trait bounds were not satisfied:
<<Ctx as Logos<'_>>::Source as Source>::Slice<'_>: Clone
which is required by <<Ctx as Logos<'_>>::Source as Source>::Slice<'_>: ToOwned
So there is a Slice type that needs constraining. Looking at the logos crate, the Source trait begins like this:
pub trait Source {
/// A type this `Source` can be sliced into.
type Slice<'a>: PartialEq + Eq + Debug
where
Self: 'a;
And Slice is later redefined like this:
impl Source for str {
type Slice<'a> = &'a str;
So I understand that Source::Slice will refer to a &str when the underlying data source is a str.
However, this is where my current understanding reaches its limit. I'm able to eliminate the linter error about the Clone trait by basically copying and pasting the stated type chain as a trait constraint:
where
Ctx: logos::Logos<'l>,
<<Ctx as Logos<'l>>::Source as logos::Source>::Slice<'l>: Clone,
But this doesn't fix the whole problem. I now get a different linter error from lexer.slice().to_owned() that I don't know how to resolve:
mismatched types
expected struct String
found associated type <<Ctx as Logos<'_>>::Source as Source>::Slice<'_>
consider constraining the associated type <<Ctx as Logos<'_>>::Source as
Source>::Slice<'_> to String
My educated guess is that, without a constraint on the associated Slice type, the compiler cannot guarantee that the type will have a to_owned() function that returns a String, and therefore that I need some way to constrain the Slice type to be a &str in this function. I can see how the logos crate does this for its Source trait and the various impls of it, but I don't know how to do it locally in my function.
TL;DR
For a trait MyTrait that has an associated type MyTrait::A, how do I constrain MyTrait::A to a concrete type when writing my_function<T>() where T: MyTrait?
1 post - 1 participant
🏷️ Rust_feed