mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Improve/fix type bound lowering
This commit is contained in:
parent
b1a40042e8
commit
4768f5e717
3 changed files with 64 additions and 30 deletions
|
@ -3415,6 +3415,39 @@ fn test(x: Trait, y: &Trait) -> u64 {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn weird_bounds() {
|
||||||
|
assert_snapshot_matches!(
|
||||||
|
infer(r#"
|
||||||
|
trait Trait {}
|
||||||
|
fn test() {
|
||||||
|
let a: impl Trait + 'lifetime = foo;
|
||||||
|
let b: impl 'lifetime = foo;
|
||||||
|
let b: impl (Trait) = foo;
|
||||||
|
let b: impl ('lifetime) = foo;
|
||||||
|
let d: impl ?Sized = foo;
|
||||||
|
let e: impl Trait + ?Sized = foo;
|
||||||
|
}
|
||||||
|
"#),
|
||||||
|
@r###"
|
||||||
|
⋮
|
||||||
|
⋮[26; 237) '{ ...foo; }': ()
|
||||||
|
⋮[36; 37) 'a': impl Trait + {error}
|
||||||
|
⋮[64; 67) 'foo': impl Trait + {error}
|
||||||
|
⋮[77; 78) 'b': impl {error}
|
||||||
|
⋮[97; 100) 'foo': impl {error}
|
||||||
|
⋮[110; 111) 'b': impl Trait
|
||||||
|
⋮[128; 131) 'foo': impl Trait
|
||||||
|
⋮[141; 142) 'b': impl {error}
|
||||||
|
⋮[163; 166) 'foo': impl {error}
|
||||||
|
⋮[176; 177) 'd': impl {error}
|
||||||
|
⋮[193; 196) 'foo': impl {error}
|
||||||
|
⋮[206; 207) 'e': impl Trait + {error}
|
||||||
|
⋮[231; 234) 'foo': impl Trait + {error}
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
|
||||||
let file = db.parse(pos.file_id).ok().unwrap();
|
let file = db.parse(pos.file_id).ok().unwrap();
|
||||||
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
|
||||||
|
|
|
@ -136,7 +136,7 @@ pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>)
|
||||||
impl TypeBound {
|
impl TypeBound {
|
||||||
pub(crate) fn from_ast(node: ast::TypeBound) -> Self {
|
pub(crate) fn from_ast(node: ast::TypeBound) -> Self {
|
||||||
match node.kind() {
|
match node.kind() {
|
||||||
Some(ast::TypeBoundKind::PathType(path_type)) => {
|
ast::TypeBoundKind::PathType(path_type) => {
|
||||||
let path = match path_type.path() {
|
let path = match path_type.path() {
|
||||||
Some(p) => p,
|
Some(p) => p,
|
||||||
None => return TypeBound::Error,
|
None => return TypeBound::Error,
|
||||||
|
@ -147,9 +147,7 @@ impl TypeBound {
|
||||||
};
|
};
|
||||||
TypeBound::Path(path)
|
TypeBound::Path(path)
|
||||||
}
|
}
|
||||||
Some(ast::TypeBoundKind::ForType(_)) | Some(ast::TypeBoundKind::Lifetime(_)) | None => {
|
ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
|
||||||
TypeBound::Error
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -382,7 +382,36 @@ impl ast::WherePred {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
|
pub enum TypeBoundKind {
|
||||||
|
/// Trait
|
||||||
|
PathType(ast::PathType),
|
||||||
|
/// for<'a> ...
|
||||||
|
ForType(ast::ForType),
|
||||||
|
/// 'a
|
||||||
|
Lifetime(ast::SyntaxToken),
|
||||||
|
}
|
||||||
|
|
||||||
impl ast::TypeBound {
|
impl ast::TypeBound {
|
||||||
|
pub fn kind(&self) -> TypeBoundKind {
|
||||||
|
if let Some(path_type) = children(self).next() {
|
||||||
|
TypeBoundKind::PathType(path_type)
|
||||||
|
} else if let Some(for_type) = children(self).next() {
|
||||||
|
TypeBoundKind::ForType(for_type)
|
||||||
|
} else if let Some(lifetime) = self.lifetime() {
|
||||||
|
TypeBoundKind::Lifetime(lifetime)
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lifetime(&self) -> Option<SyntaxToken> {
|
||||||
|
self.syntax()
|
||||||
|
.children_with_tokens()
|
||||||
|
.filter_map(|it| it.into_token())
|
||||||
|
.find(|it| it.kind() == LIFETIME)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn question_mark_token(&self) -> Option<SyntaxToken> {
|
pub fn question_mark_token(&self) -> Option<SyntaxToken> {
|
||||||
self.syntax()
|
self.syntax()
|
||||||
.children_with_tokens()
|
.children_with_tokens()
|
||||||
|
@ -399,29 +428,3 @@ impl ast::TraitDef {
|
||||||
self.syntax().children_with_tokens().any(|t| t.kind() == T![auto])
|
self.syntax().children_with_tokens().any(|t| t.kind() == T![auto])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
|
||||||
pub enum TypeBoundKind {
|
|
||||||
/// Trait
|
|
||||||
PathType(ast::PathType),
|
|
||||||
/// for<'a> ...
|
|
||||||
ForType(ast::ForType),
|
|
||||||
/// 'a
|
|
||||||
Lifetime(ast::SyntaxToken),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ast::TypeBound {
|
|
||||||
pub fn kind(&self) -> Option<TypeBoundKind> {
|
|
||||||
let child = self.syntax.first_child_or_token()?;
|
|
||||||
match child.kind() {
|
|
||||||
PATH_TYPE => Some(TypeBoundKind::PathType(
|
|
||||||
ast::PathType::cast(child.into_node().unwrap()).unwrap(),
|
|
||||||
)),
|
|
||||||
FOR_TYPE => Some(TypeBoundKind::ForType(
|
|
||||||
ast::ForType::cast(child.into_node().unwrap()).unwrap(),
|
|
||||||
)),
|
|
||||||
LIFETIME => Some(TypeBoundKind::Lifetime(child.into_token().unwrap())),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue