Improve/fix type bound lowering

This commit is contained in:
Florian Diebold 2019-08-22 17:43:09 +02:00
parent b1a40042e8
commit 4768f5e717
3 changed files with 64 additions and 30 deletions

View file

@ -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();

View file

@ -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
}
} }
} }
} }

View file

@ -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!(),
}
}
}