mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 04:23:25 +00:00
Merge #1038
1038: Add WherePred to allow predicate access in WhereClause r=matklad a=vipentti Lifetime bounds in where predicates are now also parsed into `TYPE_BOUND_LIST` to allow unified access to bounds. Co-authored-by: Ville Penttinen <villem.penttinen@gmail.com>
This commit is contained in:
commit
dec9bde108
5 changed files with 132 additions and 8 deletions
|
@ -165,7 +165,7 @@ fn where_predicate(p: &mut Parser) {
|
|||
LIFETIME => {
|
||||
p.bump();
|
||||
if p.at(COLON) {
|
||||
lifetime_bounds(p);
|
||||
bounds(p);
|
||||
} else {
|
||||
p.error("expected colon");
|
||||
}
|
||||
|
|
|
@ -799,3 +799,70 @@ fn test_doc_comment_preserves_indents() {
|
|||
let module = file.syntax().descendants().find_map(Module::cast).unwrap();
|
||||
assert_eq!("doc1\n```\nfn foo() {\n // ...\n}\n```", module.doc_comment_text().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_where_predicates() {
|
||||
fn assert_bound(text: &str, bound: Option<&TypeBound>) {
|
||||
assert_eq!(text, bound.unwrap().syntax().text().to_string());
|
||||
}
|
||||
|
||||
let file = SourceFile::parse(
|
||||
r#"
|
||||
fn foo()
|
||||
where
|
||||
T: Clone + Copy + Debug + 'static,
|
||||
'a: 'b + 'c,
|
||||
Iterator::Item: 'a + Debug,
|
||||
Iterator::Item: Debug + 'a,
|
||||
<T as Iterator>::Item: Debug + 'a,
|
||||
for<'a> F: Fn(&'a str)
|
||||
{}
|
||||
"#,
|
||||
);
|
||||
let where_clause = file.syntax().descendants().find_map(WhereClause::cast).unwrap();
|
||||
|
||||
let mut predicates = where_clause.predicates();
|
||||
|
||||
let pred = predicates.next().unwrap();
|
||||
let mut bounds = pred.type_bound_list().unwrap().bounds();
|
||||
|
||||
assert_eq!("T", pred.type_ref().unwrap().syntax().text().to_string());
|
||||
assert_bound("Clone", bounds.next());
|
||||
assert_bound("Copy", bounds.next());
|
||||
assert_bound("Debug", bounds.next());
|
||||
assert_bound("'static", bounds.next());
|
||||
|
||||
let pred = predicates.next().unwrap();
|
||||
let mut bounds = pred.type_bound_list().unwrap().bounds();
|
||||
|
||||
assert_eq!("'a", pred.lifetime().unwrap().syntax().text().to_string());
|
||||
|
||||
assert_bound("'b", bounds.next());
|
||||
assert_bound("'c", bounds.next());
|
||||
|
||||
let pred = predicates.next().unwrap();
|
||||
let mut bounds = pred.type_bound_list().unwrap().bounds();
|
||||
|
||||
assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string());
|
||||
assert_bound("'a", bounds.next());
|
||||
|
||||
let pred = predicates.next().unwrap();
|
||||
let mut bounds = pred.type_bound_list().unwrap().bounds();
|
||||
|
||||
assert_eq!("Iterator::Item", pred.type_ref().unwrap().syntax().text().to_string());
|
||||
assert_bound("Debug", bounds.next());
|
||||
assert_bound("'a", bounds.next());
|
||||
|
||||
let pred = predicates.next().unwrap();
|
||||
let mut bounds = pred.type_bound_list().unwrap().bounds();
|
||||
|
||||
assert_eq!("<T as Iterator>::Item", pred.type_ref().unwrap().syntax().text().to_string());
|
||||
assert_bound("Debug", bounds.next());
|
||||
assert_bound("'a", bounds.next());
|
||||
|
||||
let pred = predicates.next().unwrap();
|
||||
let mut bounds = pred.type_bound_list().unwrap().bounds();
|
||||
|
||||
assert_eq!("for<'a> F", pred.type_ref().unwrap().syntax().text().to_string());
|
||||
assert_bound("Fn(&'a str)", bounds.next());
|
||||
}
|
||||
|
|
|
@ -4810,7 +4810,48 @@ impl ToOwned for WhereClause {
|
|||
}
|
||||
|
||||
|
||||
impl WhereClause {}
|
||||
impl WhereClause {
|
||||
pub fn predicates(&self) -> impl Iterator<Item = &WherePred> {
|
||||
super::children(self)
|
||||
}
|
||||
}
|
||||
|
||||
// WherePred
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
#[repr(transparent)]
|
||||
pub struct WherePred {
|
||||
pub(crate) syntax: SyntaxNode,
|
||||
}
|
||||
unsafe impl TransparentNewType for WherePred {
|
||||
type Repr = rowan::SyntaxNode<RaTypes>;
|
||||
}
|
||||
|
||||
impl AstNode for WherePred {
|
||||
fn cast(syntax: &SyntaxNode) -> Option<&Self> {
|
||||
match syntax.kind() {
|
||||
WHERE_PRED => Some(WherePred::from_repr(syntax.into_repr())),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
fn syntax(&self) -> &SyntaxNode { &self.syntax }
|
||||
}
|
||||
|
||||
impl ToOwned for WherePred {
|
||||
type Owned = TreeArc<WherePred>;
|
||||
fn to_owned(&self) -> TreeArc<WherePred> { TreeArc::cast(self.syntax.to_owned()) }
|
||||
}
|
||||
|
||||
|
||||
impl ast::TypeBoundsOwner for WherePred {}
|
||||
impl WherePred {
|
||||
pub fn type_ref(&self) -> Option<&TypeRef> {
|
||||
super::child_opt(self)
|
||||
}
|
||||
|
||||
pub fn lifetime(&self) -> Option<&Lifetime> {
|
||||
super::child_opt(self)
|
||||
}
|
||||
}
|
||||
|
||||
// WhileExpr
|
||||
#[derive(Debug, PartialEq, Eq, Hash)]
|
||||
|
|
|
@ -595,7 +595,20 @@ Grammar(
|
|||
["bounds", "TypeBound"],
|
||||
]
|
||||
),
|
||||
"WhereClause": (),
|
||||
"WherePred": (
|
||||
options: [
|
||||
"TypeRef",
|
||||
"Lifetime",
|
||||
],
|
||||
traits: [
|
||||
"TypeBoundsOwner",
|
||||
],
|
||||
),
|
||||
"WhereClause": (
|
||||
collections: [
|
||||
["predicates", "WherePred"],
|
||||
],
|
||||
),
|
||||
"ExprStmt": (
|
||||
options: [ ["expr", "Expr"] ]
|
||||
),
|
||||
|
|
|
@ -15,11 +15,14 @@ SOURCE_FILE@[0; 116)
|
|||
LIFETIME@[18; 20) "'a"
|
||||
COLON@[20; 21)
|
||||
WHITESPACE@[21; 22)
|
||||
LIFETIME@[22; 24) "'b"
|
||||
WHITESPACE@[24; 25)
|
||||
PLUS@[25; 26)
|
||||
WHITESPACE@[26; 27)
|
||||
LIFETIME@[27; 29) "'c"
|
||||
TYPE_BOUND_LIST@[22; 29)
|
||||
TYPE_BOUND@[22; 24)
|
||||
LIFETIME@[22; 24) "'b"
|
||||
WHITESPACE@[24; 25)
|
||||
PLUS@[25; 26)
|
||||
WHITESPACE@[26; 27)
|
||||
TYPE_BOUND@[27; 29)
|
||||
LIFETIME@[27; 29) "'c"
|
||||
COMMA@[29; 30)
|
||||
WHITESPACE@[30; 34)
|
||||
WHERE_PRED@[34; 59)
|
||||
|
|
Loading…
Reference in a new issue