syn
syn copied to clipboard
Should `~const` be a variant of `syn::TraitBoundModifier` among with `None` and `Maybe(Token![?])`?
In combination,
#![feature(const_trait_impl)]
#![feature(const_fn_trait_bound)]
Nightly features (https://github.com/rust-lang/rust/issues/67792) allow constantly implement traits.
According to clarfonthey
The variance is mostly in terms of what implementations of traits are okay -- so,
const Trait
essentially would mean thatimpl const
is required, whereas~const Trait
means that a non-const impl will just make the function non-const, instead of preventing usage altogether.Yes, we don't have the ability to have
T: const Trait
bounds, but the idea is that the const should be covariant, which is why the~const
is there. This can be compared to a simpleT: Trait
bound, which will not affect the constness of the function, e.g.T: Copy
.Mostly, the matter is making sure that things are consistent with
const
being an opt-in thing, while also not confusing the syntax with the contravariant?Sized
.
Currently, ~const
is sort of supported at syn::TraitBound
level yet treated as a part of syn::Path
.
Excerpt from src/generics.rs
:
#[cfg_attr(doc_cfg, doc(cfg(feature = "parsing")))]
impl Parse for TraitBound {
fn parse(input: ParseStream) -> Result<Self> {
#[cfg(feature = "full")]
let tilde_const = if input.peek(Token![~]) && input.peek2(Token![const]) {
let tilde_token = input.parse::<Token![~]>()?;
let const_token = input.parse::<Token![const]>()?;
Some((tilde_token, const_token))
} else {
None
};
let modifier: TraitBoundModifier = input.parse()?;
let lifetimes: Option<BoundLifetimes> = input.parse()?;
let mut path: Path = input.parse()?;
if path.segments.last().unwrap().arguments.is_empty()
&& (input.peek(token::Paren) || input.peek(Token![::]) && input.peek3(token::Paren))
{
input.parse::<Option<Token![::]>>()?;
let args: ParenthesizedGenericArguments = input.parse()?;
let parenthesized = PathArguments::Parenthesized(args);
path.segments.last_mut().unwrap().arguments = parenthesized;
}
#[cfg(feature = "full")]
{
if let Some((tilde_token, const_token)) = tilde_const {
path.segments.insert(
0,
PathSegment {
ident: Ident::new("const", const_token.span),
arguments: PathArguments::None,
},
);
let (_const, punct) = path.segments.pairs_mut().next().unwrap().into_tuple();
*punct.unwrap() = Token;
}
}
Ok(TraitBound {
paren_token: None,
modifier,
lifetimes,
path,
})
}
}
I believe it makes more sense to parse ~const
as syn::TraitBoundModifier
.
I've implemented https://github.com/JohnScience/unconst_trait_impl based on some source code of syn
. It's a bit messy yet you can track the differences between the source code of syn
and mine. It's been made in a hurry yet it seems to work.
~const
is explicitly provisional syntax and is not backed by any RFC approved by the lang team. See https://github.com/rust-lang/rust/issues/67792: "This RFC has not yet been accepted. It is being implemented on a provisional basis to evaluate the potential fallout."
I don't believe it belongs in syn's syntax tree.