Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 42 additions & 32 deletions src/generics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -765,8 +765,6 @@ pub(crate) mod parsing {
return input.parse().map(TypeParamBound::Lifetime);
}

let begin = input.fork();

#[cfg(feature = "full")]
{
if input.peek(Token![use]) {
Expand All @@ -784,38 +782,20 @@ pub(crate) mod parsing {
}
}

let begin = input.fork();

let content;
let (paren_token, content) = if input.peek(token::Paren) {
(Some(parenthesized!(content in input)), &content)
} else {
(None, input)
};

let is_conditionally_const = cfg!(feature = "full") && content.peek(token::Bracket);
let is_unconditionally_const = cfg!(feature = "full") && content.peek(Token![const]);
if is_conditionally_const {
let conditionally_const;
let bracket_token = bracketed!(conditionally_const in content);
conditionally_const.parse::<Token![const]>()?;
if !allow_const {
let msg = "`[const]` is not allowed here";
return Err(Error::new(bracket_token.span.join(), msg));
}
} else if is_unconditionally_const {
let const_token: Token![const] = content.parse()?;
if !allow_const {
let msg = "`const` is not allowed here";
return Err(Error::new(const_token.span, msg));
}
}

let mut bound: TraitBound = content.parse()?;
bound.paren_token = paren_token;

if is_conditionally_const || is_unconditionally_const {
Ok(TypeParamBound::Verbatim(verbatim::between(&begin, input)))
} else {
if let Some(mut bound) = TraitBound::do_parse(content, allow_const)? {
bound.paren_token = paren_token;
Ok(TypeParamBound::Trait(bound))
} else {
Ok(TypeParamBound::Verbatim(verbatim::between(&begin, input)))
}
}

Expand Down Expand Up @@ -850,7 +830,33 @@ pub(crate) mod parsing {
#[cfg_attr(docsrs, doc(cfg(feature = "parsing")))]
impl Parse for TraitBound {
fn parse(input: ParseStream) -> Result<Self> {
let allow_const = false;
Self::do_parse(input, allow_const).map(Option::unwrap)
}
}

impl TraitBound {
fn do_parse(input: ParseStream, allow_const: bool) -> Result<Option<Self>> {
let mut lifetimes: Option<BoundLifetimes> = input.parse()?;

let is_conditionally_const = cfg!(feature = "full") && input.peek(token::Bracket);
let is_unconditionally_const = cfg!(feature = "full") && input.peek(Token![const]);
if is_conditionally_const {
let conditionally_const;
let bracket_token = bracketed!(conditionally_const in input);
conditionally_const.parse::<Token![const]>()?;
if !allow_const {
let msg = "`[const]` is not allowed here";
return Err(Error::new(bracket_token.span.join(), msg));
}
} else if is_unconditionally_const {
let const_token: Token![const] = input.parse()?;
if !allow_const {
let msg = "`const` is not allowed here";
return Err(Error::new(const_token.span, msg));
}
}

let modifier: TraitBoundModifier = input.parse()?;
if lifetimes.is_none() && matches!(modifier, TraitBoundModifier::Maybe(_)) {
lifetimes = input.parse()?;
Expand All @@ -876,12 +882,16 @@ pub(crate) mod parsing {
}
}

Ok(TraitBound {
paren_token: None,
modifier,
lifetimes,
path,
})
if is_conditionally_const || is_unconditionally_const {
Ok(None)
} else {
Ok(Some(TraitBound {
paren_token: None,
modifier,
lifetimes,
path,
}))
}
}
}

Expand Down
7 changes: 5 additions & 2 deletions tests/repo/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ static EXCLUDE_FILES: &[&str] = &[
"src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs",
"src/tools/rust-analyzer/crates/test-utils/src/minicore.rs",

// TODO: conditionally const trait bound with lifetime bindar: `T: for<'a> [const] async Trait<'a>`
// https://github.com/dtolnay/syn/issues/1888
// TODO: async trait bounds: `T: async Trait`
// https://github.com/dtolnay/syn/issues/1901
"src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/for_binder_bound.rs",

// TODO: bound lifetime with lifetime bound: `T: for<'a: 'b> Trait<'a>`
// https://github.com/dtolnay/syn/issues/1900
"tests/ui/traits/const-traits/conditionally-const-trait-bound-syntax.rs",

// TODO: non-lifetime binders: `where for<'a, T> &'a Struct<T>: Trait`
Expand Down
Loading