aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-08-22 16:43:09 +0100
committerFlorian Diebold <[email protected]>2019-08-22 20:58:29 +0100
commit4768f5e7177159b894d65a50b1e4492cb4048ac3 (patch)
treede5d4388124443eb51847a390f259acd44ef1a65 /crates
parentb1a40042e8f595af0486cf1cc70b63be1ff302b3 (diff)
Improve/fix type bound lowering
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/ty/tests.rs33
-rw-r--r--crates/ra_hir/src/type_ref.rs6
-rw-r--r--crates/ra_syntax/src/ast/extensions.rs55
3 files changed, 64 insertions, 30 deletions
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 41cea9564..c5818b738 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3415,6 +3415,39 @@ fn test(x: Trait, y: &Trait) -> u64 {
3415 ); 3415 );
3416} 3416}
3417 3417
3418#[test]
3419fn weird_bounds() {
3420 assert_snapshot_matches!(
3421 infer(r#"
3422trait Trait {}
3423fn test() {
3424 let a: impl Trait + 'lifetime = foo;
3425 let b: impl 'lifetime = foo;
3426 let b: impl (Trait) = foo;
3427 let b: impl ('lifetime) = foo;
3428 let d: impl ?Sized = foo;
3429 let e: impl Trait + ?Sized = foo;
3430}
3431"#),
3432 @r###"
3433
3434 ⋮[26; 237) '{ ...foo; }': ()
3435 ⋮[36; 37) 'a': impl Trait + {error}
3436 ⋮[64; 67) 'foo': impl Trait + {error}
3437 ⋮[77; 78) 'b': impl {error}
3438 ⋮[97; 100) 'foo': impl {error}
3439 ⋮[110; 111) 'b': impl Trait
3440 ⋮[128; 131) 'foo': impl Trait
3441 ⋮[141; 142) 'b': impl {error}
3442 ⋮[163; 166) 'foo': impl {error}
3443 ⋮[176; 177) 'd': impl {error}
3444 ⋮[193; 196) 'foo': impl {error}
3445 ⋮[206; 207) 'e': impl Trait + {error}
3446 ⋮[231; 234) 'foo': impl Trait + {error}
3447 "###
3448 );
3449}
3450
3418fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 3451fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
3419 let file = db.parse(pos.file_id).ok().unwrap(); 3452 let file = db.parse(pos.file_id).ok().unwrap();
3420 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 3453 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
diff --git a/crates/ra_hir/src/type_ref.rs b/crates/ra_hir/src/type_ref.rs
index 949fa7a2c..fa91bfb22 100644
--- a/crates/ra_hir/src/type_ref.rs
+++ b/crates/ra_hir/src/type_ref.rs
@@ -136,7 +136,7 @@ pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>)
136impl TypeBound { 136impl TypeBound {
137 pub(crate) fn from_ast(node: ast::TypeBound) -> Self { 137 pub(crate) fn from_ast(node: ast::TypeBound) -> Self {
138 match node.kind() { 138 match node.kind() {
139 Some(ast::TypeBoundKind::PathType(path_type)) => { 139 ast::TypeBoundKind::PathType(path_type) => {
140 let path = match path_type.path() { 140 let path = match path_type.path() {
141 Some(p) => p, 141 Some(p) => p,
142 None => return TypeBound::Error, 142 None => return TypeBound::Error,
@@ -147,9 +147,7 @@ impl TypeBound {
147 }; 147 };
148 TypeBound::Path(path) 148 TypeBound::Path(path)
149 } 149 }
150 Some(ast::TypeBoundKind::ForType(_)) | Some(ast::TypeBoundKind::Lifetime(_)) | None => { 150 ast::TypeBoundKind::ForType(_) | ast::TypeBoundKind::Lifetime(_) => TypeBound::Error,
151 TypeBound::Error
152 }
153 } 151 }
154 } 152 }
155} 153}
diff --git a/crates/ra_syntax/src/ast/extensions.rs b/crates/ra_syntax/src/ast/extensions.rs
index 8de979ca2..e0ea3e5ab 100644
--- a/crates/ra_syntax/src/ast/extensions.rs
+++ b/crates/ra_syntax/src/ast/extensions.rs
@@ -382,7 +382,36 @@ impl ast::WherePred {
382 } 382 }
383} 383}
384 384
385#[derive(Clone, Debug, PartialEq, Eq, Hash)]
386pub enum TypeBoundKind {
387 /// Trait
388 PathType(ast::PathType),
389 /// for<'a> ...
390 ForType(ast::ForType),
391 /// 'a
392 Lifetime(ast::SyntaxToken),
393}
394
385impl ast::TypeBound { 395impl ast::TypeBound {
396 pub fn kind(&self) -> TypeBoundKind {
397 if let Some(path_type) = children(self).next() {
398 TypeBoundKind::PathType(path_type)
399 } else if let Some(for_type) = children(self).next() {
400 TypeBoundKind::ForType(for_type)
401 } else if let Some(lifetime) = self.lifetime() {
402 TypeBoundKind::Lifetime(lifetime)
403 } else {
404 unreachable!()
405 }
406 }
407
408 fn lifetime(&self) -> Option<SyntaxToken> {
409 self.syntax()
410 .children_with_tokens()
411 .filter_map(|it| it.into_token())
412 .find(|it| it.kind() == LIFETIME)
413 }
414
386 pub fn question_mark_token(&self) -> Option<SyntaxToken> { 415 pub fn question_mark_token(&self) -> Option<SyntaxToken> {
387 self.syntax() 416 self.syntax()
388 .children_with_tokens() 417 .children_with_tokens()
@@ -399,29 +428,3 @@ impl ast::TraitDef {
399 self.syntax().children_with_tokens().any(|t| t.kind() == T![auto]) 428 self.syntax().children_with_tokens().any(|t| t.kind() == T![auto])
400 } 429 }
401} 430}
402
403#[derive(Clone, Debug, PartialEq, Eq, Hash)]
404pub enum TypeBoundKind {
405 /// Trait
406 PathType(ast::PathType),
407 /// for<'a> ...
408 ForType(ast::ForType),
409 /// 'a
410 Lifetime(ast::SyntaxToken),
411}
412
413impl ast::TypeBound {
414 pub fn kind(&self) -> Option<TypeBoundKind> {
415 let child = self.syntax.first_child_or_token()?;
416 match child.kind() {
417 PATH_TYPE => Some(TypeBoundKind::PathType(
418 ast::PathType::cast(child.into_node().unwrap()).unwrap(),
419 )),
420 FOR_TYPE => Some(TypeBoundKind::ForType(
421 ast::ForType::cast(child.into_node().unwrap()).unwrap(),
422 )),
423 LIFETIME => Some(TypeBoundKind::Lifetime(child.into_token().unwrap())),
424 _ => unreachable!(),
425 }
426 }
427}