diff options
Diffstat (limited to 'crates/ra_hir')
-rw-r--r-- | crates/ra_hir/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir/src/diagnostics.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 103 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/collector.rs | 67 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/raw.rs | 17 | ||||
-rw-r--r-- | crates/ra_hir/src/nameres/tests/mods.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir/src/source_binder.rs | 35 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 100 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/infer.rs | 47 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 83 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 14 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 121 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits.rs | 8 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 51 |
17 files changed, 607 insertions, 136 deletions
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml index 285b3c63a..1a2f1b47c 100644 --- a/crates/ra_hir/Cargo.toml +++ b/crates/ra_hir/Cargo.toml | |||
@@ -27,4 +27,4 @@ chalk-ir = { git = "https://github.com/rust-lang/chalk.git" } | |||
27 | lalrpop-intern = "0.15.1" | 27 | lalrpop-intern = "0.15.1" |
28 | 28 | ||
29 | [dev-dependencies] | 29 | [dev-dependencies] |
30 | insta = "0.9.0" | 30 | insta = "0.10.0" |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 779764590..89fc1d1a1 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -838,6 +838,10 @@ impl TypeAlias { | |||
838 | self.id.module(db) | 838 | self.id.module(db) |
839 | } | 839 | } |
840 | 840 | ||
841 | pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { | ||
842 | self.module(db).krate(db) | ||
843 | } | ||
844 | |||
841 | /// The containing impl block, if this is a method. | 845 | /// The containing impl block, if this is a method. |
842 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { | 846 | pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> { |
843 | let module_impls = db.impls_in_module(self.module(db)); | 847 | let module_impls = db.impls_in_module(self.module(db)); |
diff --git a/crates/ra_hir/src/diagnostics.rs b/crates/ra_hir/src/diagnostics.rs index 0290483b3..f6240830f 100644 --- a/crates/ra_hir/src/diagnostics.rs +++ b/crates/ra_hir/src/diagnostics.rs | |||
@@ -3,7 +3,7 @@ use std::{any::Any, fmt}; | |||
3 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; | 3 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, TextRange}; |
4 | use relative_path::RelativePathBuf; | 4 | use relative_path::RelativePathBuf; |
5 | 5 | ||
6 | use crate::{HirDatabase, HirFileId, Name}; | 6 | use crate::{HirDatabase, HirFileId, Name, Source}; |
7 | 7 | ||
8 | /// Diagnostic defines hir API for errors and warnings. | 8 | /// Diagnostic defines hir API for errors and warnings. |
9 | /// | 9 | /// |
@@ -19,10 +19,9 @@ use crate::{HirDatabase, HirFileId, Name}; | |||
19 | /// instance of `Diagnostic` on demand. | 19 | /// instance of `Diagnostic` on demand. |
20 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { | 20 | pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { |
21 | fn message(&self) -> String; | 21 | fn message(&self) -> String; |
22 | fn file(&self) -> HirFileId; | 22 | fn source(&self) -> Source<SyntaxNodePtr>; |
23 | fn syntax_node_ptr(&self) -> SyntaxNodePtr; | ||
24 | fn highlight_range(&self) -> TextRange { | 23 | fn highlight_range(&self) -> TextRange { |
25 | self.syntax_node_ptr().range() | 24 | self.source().ast.range() |
26 | } | 25 | } |
27 | fn as_any(&self) -> &(dyn Any + Send + 'static); | 26 | fn as_any(&self) -> &(dyn Any + Send + 'static); |
28 | } | 27 | } |
@@ -34,8 +33,8 @@ pub trait AstDiagnostic { | |||
34 | 33 | ||
35 | impl dyn Diagnostic { | 34 | impl dyn Diagnostic { |
36 | pub fn syntax_node(&self, db: &impl HirDatabase) -> SyntaxNode { | 35 | pub fn syntax_node(&self, db: &impl HirDatabase) -> SyntaxNode { |
37 | let node = db.parse_or_expand(self.file()).unwrap(); | 36 | let node = db.parse_or_expand(self.source().file_id).unwrap(); |
38 | self.syntax_node_ptr().to_node(&node) | 37 | self.source().ast.to_node(&node) |
39 | } | 38 | } |
40 | 39 | ||
41 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { | 40 | pub fn downcast_ref<D: Diagnostic>(&self) -> Option<&D> { |
@@ -87,12 +86,11 @@ impl Diagnostic for NoSuchField { | |||
87 | fn message(&self) -> String { | 86 | fn message(&self) -> String { |
88 | "no such field".to_string() | 87 | "no such field".to_string() |
89 | } | 88 | } |
90 | fn file(&self) -> HirFileId { | 89 | |
91 | self.file | 90 | fn source(&self) -> Source<SyntaxNodePtr> { |
92 | } | 91 | Source { file_id: self.file, ast: self.field.into() } |
93 | fn syntax_node_ptr(&self) -> SyntaxNodePtr { | ||
94 | self.field.into() | ||
95 | } | 92 | } |
93 | |||
96 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 94 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
97 | self | 95 | self |
98 | } | 96 | } |
@@ -109,11 +107,8 @@ impl Diagnostic for UnresolvedModule { | |||
109 | fn message(&self) -> String { | 107 | fn message(&self) -> String { |
110 | "unresolved module".to_string() | 108 | "unresolved module".to_string() |
111 | } | 109 | } |
112 | fn file(&self) -> HirFileId { | 110 | fn source(&self) -> Source<SyntaxNodePtr> { |
113 | self.file | 111 | Source { file_id: self.file, ast: self.decl.into() } |
114 | } | ||
115 | fn syntax_node_ptr(&self) -> SyntaxNodePtr { | ||
116 | self.decl.into() | ||
117 | } | 112 | } |
118 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 113 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
119 | self | 114 | self |
@@ -131,11 +126,8 @@ impl Diagnostic for MissingFields { | |||
131 | fn message(&self) -> String { | 126 | fn message(&self) -> String { |
132 | "fill structure fields".to_string() | 127 | "fill structure fields".to_string() |
133 | } | 128 | } |
134 | fn file(&self) -> HirFileId { | 129 | fn source(&self) -> Source<SyntaxNodePtr> { |
135 | self.file | 130 | Source { file_id: self.file, ast: self.field_list.into() } |
136 | } | ||
137 | fn syntax_node_ptr(&self) -> SyntaxNodePtr { | ||
138 | self.field_list.into() | ||
139 | } | 131 | } |
140 | fn as_any(&self) -> &(dyn Any + Send + 'static) { | 132 | fn as_any(&self) -> &(dyn Any + Send + 'static) { |
141 | self | 133 | self |
@@ -146,8 +138,8 @@ impl AstDiagnostic for MissingFields { | |||
146 | type AST = ast::NamedFieldList; | 138 | type AST = ast::NamedFieldList; |
147 | 139 | ||
148 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { | 140 | fn ast(&self, db: &impl HirDatabase) -> Self::AST { |
149 | let root = db.parse_or_expand(self.file()).unwrap(); | 141 | let root = db.parse_or_expand(self.source().file_id).unwrap(); |
150 | let node = self.syntax_node_ptr().to_node(&root); | 142 | let node = self.source().ast.to_node(&root); |
151 | ast::NamedFieldList::cast(node).unwrap() | 143 | ast::NamedFieldList::cast(node).unwrap() |
152 | } | 144 | } |
153 | } | 145 | } |
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 4dcea19a9..f33676655 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs | |||
@@ -11,17 +11,16 @@ use ra_syntax::{ | |||
11 | }, | 11 | }, |
12 | AstNode, AstPtr, SyntaxNodePtr, | 12 | AstNode, AstPtr, SyntaxNodePtr, |
13 | }; | 13 | }; |
14 | use test_utils::tested_by; | ||
14 | 15 | ||
15 | use crate::{ | 16 | use crate::{ |
16 | name::{AsName, SELF_PARAM}, | 17 | name::{AsName, SELF_PARAM}, |
18 | path::GenericArgs, | ||
19 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | ||
17 | type_ref::{Mutability, TypeRef}, | 20 | type_ref::{Mutability, TypeRef}, |
18 | DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name, | 21 | DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name, |
19 | Path, Resolver, | 22 | Path, Resolver, |
20 | }; | 23 | }; |
21 | use crate::{ | ||
22 | path::GenericArgs, | ||
23 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | ||
24 | }; | ||
25 | 24 | ||
26 | pub use self::scope::ExprScopes; | 25 | pub use self::scope::ExprScopes; |
27 | 26 | ||
@@ -558,37 +557,40 @@ where | |||
558 | let syntax_ptr = SyntaxNodePtr::new(expr.syntax()); | 557 | let syntax_ptr = SyntaxNodePtr::new(expr.syntax()); |
559 | match expr.kind() { | 558 | match expr.kind() { |
560 | ast::ExprKind::IfExpr(e) => { | 559 | ast::ExprKind::IfExpr(e) => { |
561 | if let Some(pat) = e.condition().and_then(|c| c.pat()) { | 560 | let then_branch = self.collect_block_opt(e.then_branch()); |
562 | // if let -- desugar to match | 561 | |
563 | let pat = self.collect_pat(pat); | 562 | let else_branch = e.else_branch().map(|b| match b { |
564 | let match_expr = | 563 | ast::ElseBranch::Block(it) => self.collect_block(it), |
565 | self.collect_expr_opt(e.condition().expect("checked above").expr()); | 564 | ast::ElseBranch::IfExpr(elif) => { |
566 | let then_branch = self.collect_block_opt(e.then_branch()); | 565 | let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap(); |
567 | let else_branch = e | 566 | self.collect_expr(expr) |
568 | .else_branch() | 567 | } |
569 | .map(|b| match b { | 568 | }); |
570 | ast::ElseBranch::Block(it) => self.collect_block(it), | 569 | |
571 | ast::ElseBranch::IfExpr(elif) => self.collect_expr(elif.into()), | 570 | let condition = match e.condition() { |
572 | }) | 571 | None => self.exprs.alloc(Expr::Missing), |
573 | .unwrap_or_else(|| self.empty_block()); | 572 | Some(condition) => match condition.pat() { |
574 | let placeholder_pat = self.pats.alloc(Pat::Missing); | 573 | None => self.collect_expr_opt(condition.expr()), |
575 | let arms = vec![ | 574 | // if let -- desugar to match |
576 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, | 575 | Some(pat) => { |
577 | MatchArm { pats: vec![placeholder_pat], expr: else_branch, guard: None }, | 576 | let pat = self.collect_pat(pat); |
578 | ]; | 577 | let match_expr = self.collect_expr_opt(condition.expr()); |
579 | self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr) | 578 | let placeholder_pat = self.pats.alloc(Pat::Missing); |
580 | } else { | 579 | let arms = vec![ |
581 | let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); | 580 | MatchArm { pats: vec![pat], expr: then_branch, guard: None }, |
582 | let then_branch = self.collect_block_opt(e.then_branch()); | 581 | MatchArm { |
583 | let else_branch = e.else_branch().map(|b| match b { | 582 | pats: vec![placeholder_pat], |
584 | ast::ElseBranch::Block(it) => self.collect_block(it), | 583 | expr: else_branch.unwrap_or_else(|| self.empty_block()), |
585 | ast::ElseBranch::IfExpr(elif) => { | 584 | guard: None, |
586 | let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap(); | 585 | }, |
587 | self.collect_expr(expr) | 586 | ]; |
587 | return self | ||
588 | .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr); | ||
588 | } | 589 | } |
589 | }); | 590 | }, |
590 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) | 591 | }; |
591 | } | 592 | |
593 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) | ||
592 | } | 594 | } |
593 | ast::ExprKind::TryBlockExpr(e) => { | 595 | ast::ExprKind::TryBlockExpr(e) => { |
594 | let body = self.collect_block_opt(e.try_body()); | 596 | let body = self.collect_block_opt(e.try_body()); |
@@ -600,17 +602,30 @@ where | |||
600 | self.alloc_expr(Expr::Loop { body }, syntax_ptr) | 602 | self.alloc_expr(Expr::Loop { body }, syntax_ptr) |
601 | } | 603 | } |
602 | ast::ExprKind::WhileExpr(e) => { | 604 | ast::ExprKind::WhileExpr(e) => { |
603 | let condition = if let Some(condition) = e.condition() { | ||
604 | if condition.pat().is_none() { | ||
605 | self.collect_expr_opt(condition.expr()) | ||
606 | } else { | ||
607 | // FIXME handle while let | ||
608 | return self.alloc_expr(Expr::Missing, syntax_ptr); | ||
609 | } | ||
610 | } else { | ||
611 | self.exprs.alloc(Expr::Missing) | ||
612 | }; | ||
613 | let body = self.collect_block_opt(e.loop_body()); | 605 | let body = self.collect_block_opt(e.loop_body()); |
606 | |||
607 | let condition = match e.condition() { | ||
608 | None => self.exprs.alloc(Expr::Missing), | ||
609 | Some(condition) => match condition.pat() { | ||
610 | None => self.collect_expr_opt(condition.expr()), | ||
611 | // if let -- desugar to match | ||
612 | Some(pat) => { | ||
613 | tested_by!(infer_while_let); | ||
614 | let pat = self.collect_pat(pat); | ||
615 | let match_expr = self.collect_expr_opt(condition.expr()); | ||
616 | let placeholder_pat = self.pats.alloc(Pat::Missing); | ||
617 | let break_ = self.exprs.alloc(Expr::Break { expr: None }); | ||
618 | let arms = vec![ | ||
619 | MatchArm { pats: vec![pat], expr: body, guard: None }, | ||
620 | MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, | ||
621 | ]; | ||
622 | let match_expr = | ||
623 | self.exprs.alloc(Expr::Match { expr: match_expr, arms }); | ||
624 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); | ||
625 | } | ||
626 | }, | ||
627 | }; | ||
628 | |||
614 | self.alloc_expr(Expr::While { condition, body }, syntax_ptr) | 629 | self.alloc_expr(Expr::While { condition, body }, syntax_ptr) |
615 | } | 630 | } |
616 | ast::ExprKind::ForExpr(e) => { | 631 | ast::ExprKind::ForExpr(e) => { |
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs index 2d831f0d8..5b15eee90 100644 --- a/crates/ra_hir/src/marks.rs +++ b/crates/ra_hir/src/marks.rs | |||
@@ -10,4 +10,5 @@ test_utils::marks!( | |||
10 | std_prelude | 10 | std_prelude |
11 | match_ergonomics_ref | 11 | match_ergonomics_ref |
12 | trait_resolution_on_fn_type | 12 | trait_resolution_on_fn_type |
13 | infer_while_let | ||
13 | ); | 14 | ); |
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs index 06b732215..7da2dcdff 100644 --- a/crates/ra_hir/src/nameres/collector.rs +++ b/crates/ra_hir/src/nameres/collector.rs | |||
@@ -483,7 +483,7 @@ struct ModCollector<'a, D> { | |||
483 | module_id: CrateModuleId, | 483 | module_id: CrateModuleId, |
484 | file_id: HirFileId, | 484 | file_id: HirFileId, |
485 | raw_items: &'a raw::RawItems, | 485 | raw_items: &'a raw::RawItems, |
486 | parent_module: Option<&'a Name>, | 486 | parent_module: Option<ParentModule<'a>>, |
487 | } | 487 | } |
488 | 488 | ||
489 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> | 489 | impl<DB> ModCollector<'_, &'_ mut DefCollector<&'_ DB>> |
@@ -508,15 +508,16 @@ where | |||
508 | fn collect_module(&mut self, module: &raw::ModuleData) { | 508 | fn collect_module(&mut self, module: &raw::ModuleData) { |
509 | match module { | 509 | match module { |
510 | // inline module, just recurse | 510 | // inline module, just recurse |
511 | raw::ModuleData::Definition { name, items, ast_id } => { | 511 | raw::ModuleData::Definition { name, items, ast_id, attr_path } => { |
512 | let module_id = | 512 | let module_id = |
513 | self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); | 513 | self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); |
514 | let parent_module = ParentModule { name, attr_path: attr_path.as_ref() }; | ||
514 | ModCollector { | 515 | ModCollector { |
515 | def_collector: &mut *self.def_collector, | 516 | def_collector: &mut *self.def_collector, |
516 | module_id, | 517 | module_id, |
517 | file_id: self.file_id, | 518 | file_id: self.file_id, |
518 | raw_items: self.raw_items, | 519 | raw_items: self.raw_items, |
519 | parent_module: Some(name), | 520 | parent_module: Some(parent_module), |
520 | } | 521 | } |
521 | .collect(&*items); | 522 | .collect(&*items); |
522 | } | 523 | } |
@@ -530,7 +531,7 @@ where | |||
530 | name, | 531 | name, |
531 | is_root, | 532 | is_root, |
532 | attr_path.as_ref(), | 533 | attr_path.as_ref(), |
533 | self.parent_module, | 534 | self.parent_module.as_ref(), |
534 | ) { | 535 | ) { |
535 | Ok(file_id) => { | 536 | Ok(file_id) => { |
536 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); | 537 | let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); |
@@ -647,7 +648,7 @@ fn resolve_submodule( | |||
647 | name: &Name, | 648 | name: &Name, |
648 | is_root: bool, | 649 | is_root: bool, |
649 | attr_path: Option<&SmolStr>, | 650 | attr_path: Option<&SmolStr>, |
650 | parent_module: Option<&Name>, | 651 | parent_module: Option<&ParentModule>, |
651 | ) -> Result<FileId, RelativePathBuf> { | 652 | ) -> Result<FileId, RelativePathBuf> { |
652 | let file_id = file_id.original_file(db); | 653 | let file_id = file_id.original_file(db); |
653 | let source_root_id = db.file_source_root(file_id); | 654 | let source_root_id = db.file_source_root(file_id); |
@@ -657,20 +658,49 @@ fn resolve_submodule( | |||
657 | let mod_name = path.file_stem().unwrap_or("unknown"); | 658 | let mod_name = path.file_stem().unwrap_or("unknown"); |
658 | 659 | ||
659 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { | 660 | let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) { |
660 | (Some(file_path), Some(parent_name)) => { | 661 | (Some(file_path), Some(parent_module)) => { |
661 | let file_path = normalize_attribute_path(file_path); | 662 | let file_path = normalize_attribute_path(file_path); |
662 | let path = dir_path.join(format!("{}/{}", parent_name, file_path)).normalize(); | 663 | match parent_module.attribute_path() { |
663 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(path)) | 664 | Some(parent_module_attr_path) => { |
665 | let path = dir_path | ||
666 | .join(format!( | ||
667 | "{}/{}", | ||
668 | normalize_attribute_path(parent_module_attr_path), | ||
669 | file_path | ||
670 | )) | ||
671 | .normalize(); | ||
672 | ResolutionMode::InlineModuleWithAttributePath( | ||
673 | InsideInlineModuleMode::WithAttributePath(path), | ||
674 | ) | ||
675 | } | ||
676 | None => { | ||
677 | let path = | ||
678 | dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize(); | ||
679 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath( | ||
680 | path, | ||
681 | )) | ||
682 | } | ||
683 | } | ||
664 | } | 684 | } |
685 | (None, Some(parent_module)) => match parent_module.attribute_path() { | ||
686 | Some(parent_module_attr_path) => { | ||
687 | let path = dir_path.join(format!( | ||
688 | "{}/{}.rs", | ||
689 | normalize_attribute_path(parent_module_attr_path), | ||
690 | name | ||
691 | )); | ||
692 | ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path)) | ||
693 | } | ||
694 | None => { | ||
695 | let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name)); | ||
696 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) | ||
697 | } | ||
698 | }, | ||
665 | (Some(file_path), None) => { | 699 | (Some(file_path), None) => { |
666 | let file_path = normalize_attribute_path(file_path); | 700 | let file_path = normalize_attribute_path(file_path); |
667 | let path = dir_path.join(file_path.as_ref()).normalize(); | 701 | let path = dir_path.join(file_path.as_ref()).normalize(); |
668 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) | 702 | ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path)) |
669 | } | 703 | } |
670 | (None, Some(parent_name)) => { | ||
671 | let path = dir_path.join(format!("{}/{}.rs", parent_name, name)); | ||
672 | ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) | ||
673 | } | ||
674 | _ => { | 704 | _ => { |
675 | let is_dir_owner = is_root || mod_name == "mod"; | 705 | let is_dir_owner = is_root || mod_name == "mod"; |
676 | if is_dir_owner { | 706 | if is_dir_owner { |
@@ -743,6 +773,7 @@ impl InsideInlineModuleMode { | |||
743 | enum ResolutionMode { | 773 | enum ResolutionMode { |
744 | OutOfLine(OutOfLineMode), | 774 | OutOfLine(OutOfLineMode), |
745 | InsideInlineModule(InsideInlineModuleMode), | 775 | InsideInlineModule(InsideInlineModuleMode), |
776 | InlineModuleWithAttributePath(InsideInlineModuleMode), | ||
746 | } | 777 | } |
747 | 778 | ||
748 | impl ResolutionMode { | 779 | impl ResolutionMode { |
@@ -752,6 +783,7 @@ impl ResolutionMode { | |||
752 | match self { | 783 | match self { |
753 | OutOfLine(mode) => mode.resolve(source_root), | 784 | OutOfLine(mode) => mode.resolve(source_root), |
754 | InsideInlineModule(mode) => mode.resolve(source_root), | 785 | InsideInlineModule(mode) => mode.resolve(source_root), |
786 | InlineModuleWithAttributePath(mode) => mode.resolve(source_root), | ||
755 | } | 787 | } |
756 | } | 788 | } |
757 | } | 789 | } |
@@ -773,6 +805,17 @@ fn resolve_find_result( | |||
773 | } | 805 | } |
774 | } | 806 | } |
775 | 807 | ||
808 | struct ParentModule<'a> { | ||
809 | name: &'a Name, | ||
810 | attr_path: Option<&'a SmolStr>, | ||
811 | } | ||
812 | |||
813 | impl<'a> ParentModule<'a> { | ||
814 | pub fn attribute_path(&self) -> Option<&SmolStr> { | ||
815 | self.attr_path.filter(|p| !p.is_empty()) | ||
816 | } | ||
817 | } | ||
818 | |||
776 | #[cfg(test)] | 819 | #[cfg(test)] |
777 | mod tests { | 820 | mod tests { |
778 | use ra_db::SourceDatabase; | 821 | use ra_db::SourceDatabase; |
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs index 8517f3c43..584e15e29 100644 --- a/crates/ra_hir/src/nameres/raw.rs +++ b/crates/ra_hir/src/nameres/raw.rs | |||
@@ -130,8 +130,17 @@ impl_arena_id!(Module); | |||
130 | 130 | ||
131 | #[derive(Debug, PartialEq, Eq)] | 131 | #[derive(Debug, PartialEq, Eq)] |
132 | pub(super) enum ModuleData { | 132 | pub(super) enum ModuleData { |
133 | Declaration { name: Name, ast_id: FileAstId<ast::Module>, attr_path: Option<SmolStr> }, | 133 | Declaration { |
134 | Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, | 134 | name: Name, |
135 | ast_id: FileAstId<ast::Module>, | ||
136 | attr_path: Option<SmolStr>, | ||
137 | }, | ||
138 | Definition { | ||
139 | name: Name, | ||
140 | ast_id: FileAstId<ast::Module>, | ||
141 | items: Vec<RawItem>, | ||
142 | attr_path: Option<SmolStr>, | ||
143 | }, | ||
135 | } | 144 | } |
136 | 145 | ||
137 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 146 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -256,9 +265,9 @@ impl RawItemsCollector { | |||
256 | None => return, | 265 | None => return, |
257 | }; | 266 | }; |
258 | 267 | ||
259 | let attr_path = extract_mod_path_attribute(&module); | ||
260 | let ast_id = self.source_ast_id_map.ast_id(&module); | 268 | let ast_id = self.source_ast_id_map.ast_id(&module); |
261 | if module.has_semi() { | 269 | if module.has_semi() { |
270 | let attr_path = extract_mod_path_attribute(&module); | ||
262 | let item = | 271 | let item = |
263 | self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id, attr_path }); | 272 | self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id, attr_path }); |
264 | self.push_item(current_module, RawItem::Module(item)); | 273 | self.push_item(current_module, RawItem::Module(item)); |
@@ -266,10 +275,12 @@ impl RawItemsCollector { | |||
266 | } | 275 | } |
267 | 276 | ||
268 | if let Some(item_list) = module.item_list() { | 277 | if let Some(item_list) = module.item_list() { |
278 | let attr_path = extract_mod_path_attribute(&module); | ||
269 | let item = self.raw_items.modules.alloc(ModuleData::Definition { | 279 | let item = self.raw_items.modules.alloc(ModuleData::Definition { |
270 | name, | 280 | name, |
271 | ast_id, | 281 | ast_id, |
272 | items: Vec::new(), | 282 | items: Vec::new(), |
283 | attr_path, | ||
273 | }); | 284 | }); |
274 | self.process_module(Some(item), item_list); | 285 | self.process_module(Some(item), item_list); |
275 | self.push_item(current_module, RawItem::Module(item)); | 286 | self.push_item(current_module, RawItem::Module(item)); |
diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mods.rs index 382728149..6dd18df1a 100644 --- a/crates/ra_hir/src/nameres/tests/mods.rs +++ b/crates/ra_hir/src/nameres/tests/mods.rs | |||
@@ -336,9 +336,7 @@ fn module_resolution_explicit_path_mod_rs_with_win_separator() { | |||
336 | "###); | 336 | "###); |
337 | } | 337 | } |
338 | 338 | ||
339 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
340 | #[test] | 339 | #[test] |
341 | #[ignore] | ||
342 | fn module_resolution_decl_inside_inline_module_with_path_attribute() { | 340 | fn module_resolution_decl_inside_inline_module_with_path_attribute() { |
343 | let map = def_map_with_crate_graph( | 341 | let map = def_map_with_crate_graph( |
344 | r###" | 342 | r###" |
@@ -397,9 +395,7 @@ fn module_resolution_decl_inside_inline_module() { | |||
397 | "###); | 395 | "###); |
398 | } | 396 | } |
399 | 397 | ||
400 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
401 | #[test] | 398 | #[test] |
402 | #[ignore] | ||
403 | fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { | 399 | fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { |
404 | let map = def_map_with_crate_graph( | 400 | let map = def_map_with_crate_graph( |
405 | r###" | 401 | r###" |
@@ -429,9 +425,7 @@ fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { | |||
429 | "###); | 425 | "###); |
430 | } | 426 | } |
431 | 427 | ||
432 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
433 | #[test] | 428 | #[test] |
434 | #[ignore] | ||
435 | fn module_resolution_decl_inside_inline_module_3() { | 429 | fn module_resolution_decl_inside_inline_module_3() { |
436 | let map = def_map_with_crate_graph( | 430 | let map = def_map_with_crate_graph( |
437 | r###" | 431 | r###" |
@@ -462,9 +456,7 @@ fn module_resolution_decl_inside_inline_module_3() { | |||
462 | "###); | 456 | "###); |
463 | } | 457 | } |
464 | 458 | ||
465 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
466 | #[test] | 459 | #[test] |
467 | #[ignore] | ||
468 | fn module_resolution_decl_inside_inline_module_empty_path() { | 460 | fn module_resolution_decl_inside_inline_module_empty_path() { |
469 | let map = def_map_with_crate_graph( | 461 | let map = def_map_with_crate_graph( |
470 | r###" | 462 | r###" |
@@ -475,7 +467,7 @@ fn module_resolution_decl_inside_inline_module_empty_path() { | |||
475 | mod bar; | 467 | mod bar; |
476 | } | 468 | } |
477 | 469 | ||
478 | //- /users.rs | 470 | //- /foo/users.rs |
479 | pub struct Baz; | 471 | pub struct Baz; |
480 | "###, | 472 | "###, |
481 | crate_graph! { | 473 | crate_graph! { |
@@ -520,9 +512,7 @@ fn module_resolution_decl_empty_path() { | |||
520 | "###); | 512 | "###); |
521 | } | 513 | } |
522 | 514 | ||
523 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
524 | #[test] | 515 | #[test] |
525 | #[ignore] | ||
526 | fn module_resolution_decl_inside_inline_module_relative_path() { | 516 | fn module_resolution_decl_inside_inline_module_relative_path() { |
527 | let map = def_map_with_crate_graph( | 517 | let map = def_map_with_crate_graph( |
528 | r###" | 518 | r###" |
@@ -660,9 +650,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() { | |||
660 | "###); | 650 | "###); |
661 | } | 651 | } |
662 | 652 | ||
663 | // FIXME: issue #1529. not support out-of-line modules inside inline. | ||
664 | #[test] | 653 | #[test] |
665 | #[ignore] | ||
666 | fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { | 654 | fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { |
667 | let map = def_map_with_crate_graph( | 655 | let map = def_map_with_crate_graph( |
668 | r###" | 656 | r###" |
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 882db7681..5ee71e421 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs | |||
@@ -25,6 +25,12 @@ pub struct PathSegment { | |||
25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 25 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
26 | pub struct GenericArgs { | 26 | pub struct GenericArgs { |
27 | pub args: Vec<GenericArg>, | 27 | pub args: Vec<GenericArg>, |
28 | /// This specifies whether the args contain a Self type as the first | ||
29 | /// element. This is the case for path segments like `<T as Trait>`, where | ||
30 | /// `T` is actually a type parameter for the path `Trait` specifying the | ||
31 | /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type | ||
32 | /// is left out. | ||
33 | pub has_self_type: bool, | ||
28 | // someday also bindings | 34 | // someday also bindings |
29 | } | 35 | } |
30 | 36 | ||
@@ -74,6 +80,28 @@ impl Path { | |||
74 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; | 80 | let segment = PathSegment { name: name.as_name(), args_and_bindings: args }; |
75 | segments.push(segment); | 81 | segments.push(segment); |
76 | } | 82 | } |
83 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | ||
84 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | ||
85 | |||
86 | // FIXME: handle <T> syntax (type segments without trait) | ||
87 | |||
88 | // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo | ||
89 | let path = Path::from_ast(trait_ref?.path()?)?; | ||
90 | kind = path.kind; | ||
91 | let mut prefix_segments = path.segments; | ||
92 | prefix_segments.reverse(); | ||
93 | segments.extend(prefix_segments); | ||
94 | // Insert the type reference (T in the above example) as Self parameter for the trait | ||
95 | let self_type = TypeRef::from_ast(type_ref?); | ||
96 | let mut last_segment = segments.last_mut()?; | ||
97 | if last_segment.args_and_bindings.is_none() { | ||
98 | last_segment.args_and_bindings = Some(Arc::new(GenericArgs::empty())); | ||
99 | }; | ||
100 | let args = last_segment.args_and_bindings.as_mut().unwrap(); | ||
101 | let mut args_inner = Arc::make_mut(args); | ||
102 | args_inner.has_self_type = true; | ||
103 | args_inner.args.insert(0, GenericArg::Type(self_type)); | ||
104 | } | ||
77 | ast::PathSegmentKind::CrateKw => { | 105 | ast::PathSegmentKind::CrateKw => { |
78 | kind = PathKind::Crate; | 106 | kind = PathKind::Crate; |
79 | break; | 107 | break; |
@@ -144,11 +172,15 @@ impl GenericArgs { | |||
144 | } | 172 | } |
145 | // lifetimes and assoc type args ignored for now | 173 | // lifetimes and assoc type args ignored for now |
146 | if !args.is_empty() { | 174 | if !args.is_empty() { |
147 | Some(GenericArgs { args }) | 175 | Some(GenericArgs { args, has_self_type: false }) |
148 | } else { | 176 | } else { |
149 | None | 177 | None |
150 | } | 178 | } |
151 | } | 179 | } |
180 | |||
181 | pub(crate) fn empty() -> GenericArgs { | ||
182 | GenericArgs { args: Vec::new(), has_self_type: false } | ||
183 | } | ||
152 | } | 184 | } |
153 | 185 | ||
154 | impl From<Name> for Path { | 186 | impl From<Name> for Path { |
@@ -236,6 +268,10 @@ fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | |||
236 | } | 268 | } |
237 | Path { kind: PathKind::Super, segments: Vec::new() } | 269 | Path { kind: PathKind::Super, segments: Vec::new() } |
238 | } | 270 | } |
271 | ast::PathSegmentKind::Type { .. } => { | ||
272 | // not allowed in imports | ||
273 | return None; | ||
274 | } | ||
239 | }; | 275 | }; |
240 | Some(res) | 276 | Some(res) |
241 | } | 277 | } |
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs index c2c6921cb..e86716d74 100644 --- a/crates/ra_hir/src/source_binder.rs +++ b/crates/ra_hir/src/source_binder.rs | |||
@@ -18,14 +18,18 @@ use ra_syntax::{ | |||
18 | use rustc_hash::{FxHashMap, FxHashSet}; | 18 | use rustc_hash::{FxHashMap, FxHashSet}; |
19 | 19 | ||
20 | use crate::{ | 20 | use crate::{ |
21 | expr, | ||
22 | expr::{ | 21 | expr::{ |
22 | self, | ||
23 | scope::{ExprScopes, ScopeId}, | 23 | scope::{ExprScopes, ScopeId}, |
24 | BodySourceMap, | 24 | BodySourceMap, |
25 | }, | 25 | }, |
26 | ids::LocationCtx, | 26 | ids::LocationCtx, |
27 | name, | ||
28 | path::{PathKind, PathSegment}, | ||
29 | ty::method_resolution::implements_trait, | ||
27 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, | 30 | AsName, AstId, Const, Crate, DefWithBody, Either, Enum, Function, HirDatabase, HirFileId, |
28 | MacroDef, Module, Name, Path, PerNs, Resolver, Static, Struct, Trait, Ty, | 31 | MacroDef, Module, ModuleDef, Name, Path, PerNs, Resolution, Resolver, Static, Struct, Trait, |
32 | Ty, | ||
29 | }; | 33 | }; |
30 | 34 | ||
31 | /// Locates the module by `FileId`. Picks topmost module in the file. | 35 | /// Locates the module by `FileId`. Picks topmost module in the file. |
@@ -409,6 +413,33 @@ impl SourceAnalyzer { | |||
409 | crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) | 413 | crate::ty::autoderef(db, &self.resolver, canonical).map(|canonical| canonical.value) |
410 | } | 414 | } |
411 | 415 | ||
416 | /// Checks that particular type `ty` implements `std::future::Future`. | ||
417 | /// This function is used in `.await` syntax completion. | ||
418 | pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { | ||
419 | let std_future_path = Path { | ||
420 | kind: PathKind::Abs, | ||
421 | segments: vec![ | ||
422 | PathSegment { name: name::STD, args_and_bindings: None }, | ||
423 | PathSegment { name: name::FUTURE_MOD, args_and_bindings: None }, | ||
424 | PathSegment { name: name::FUTURE_TYPE, args_and_bindings: None }, | ||
425 | ], | ||
426 | }; | ||
427 | |||
428 | let std_future_trait = | ||
429 | match self.resolver.resolve_path_segments(db, &std_future_path).into_fully_resolved() { | ||
430 | PerNs { types: Some(Resolution::Def(ModuleDef::Trait(trait_))), .. } => trait_, | ||
431 | _ => return false, | ||
432 | }; | ||
433 | |||
434 | let krate = match self.resolver.krate() { | ||
435 | Some(krate) => krate, | ||
436 | _ => return false, | ||
437 | }; | ||
438 | |||
439 | let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; | ||
440 | implements_trait(&canonical_ty, db, &self.resolver, krate, std_future_trait) | ||
441 | } | ||
442 | |||
412 | #[cfg(test)] | 443 | #[cfg(test)] |
413 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { | 444 | pub(crate) fn body_source_map(&self) -> Arc<BodySourceMap> { |
414 | self.body_source_map.clone().unwrap() | 445 | self.body_source_map.clone().unwrap() |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 82589e504..642dd02cb 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -94,6 +94,12 @@ pub enum TypeCtor { | |||
94 | 94 | ||
95 | /// A tuple type. For example, `(i32, bool)`. | 95 | /// A tuple type. For example, `(i32, bool)`. |
96 | Tuple { cardinality: u16 }, | 96 | Tuple { cardinality: u16 }, |
97 | |||
98 | /// Represents an associated item like `Iterator::Item`. This is used | ||
99 | /// when we have tried to normalize a projection like `T::Item` but | ||
100 | /// couldn't find a better representation. In that case, we generate | ||
101 | /// an **application type** like `(Iterator::Item)<T>`. | ||
102 | AssociatedType(TypeAlias), | ||
97 | } | 103 | } |
98 | 104 | ||
99 | /// A nominal type with (maybe 0) type parameters. This might be a primitive | 105 | /// A nominal type with (maybe 0) type parameters. This might be a primitive |
@@ -114,6 +120,12 @@ pub struct ProjectionTy { | |||
114 | pub parameters: Substs, | 120 | pub parameters: Substs, |
115 | } | 121 | } |
116 | 122 | ||
123 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | ||
124 | pub struct UnselectedProjectionTy { | ||
125 | pub type_name: Name, | ||
126 | pub parameters: Substs, | ||
127 | } | ||
128 | |||
117 | /// A type. | 129 | /// A type. |
118 | /// | 130 | /// |
119 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents | 131 | /// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents |
@@ -127,6 +139,18 @@ pub enum Ty { | |||
127 | /// several other things. | 139 | /// several other things. |
128 | Apply(ApplicationTy), | 140 | Apply(ApplicationTy), |
129 | 141 | ||
142 | /// A "projection" type corresponds to an (unnormalized) | ||
143 | /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the | ||
144 | /// trait and all its parameters are fully known. | ||
145 | Projection(ProjectionTy), | ||
146 | |||
147 | /// This is a variant of a projection in which the trait is | ||
148 | /// **not** known. It corresponds to a case where people write | ||
149 | /// `T::Item` without specifying the trait. We would then try to | ||
150 | /// figure out the trait by looking at all the traits that are in | ||
151 | /// scope. | ||
152 | UnselectedProjection(UnselectedProjectionTy), | ||
153 | |||
130 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} | 154 | /// A type parameter; for example, `T` in `fn f<T>(x: T) {} |
131 | Param { | 155 | Param { |
132 | /// The index of the parameter (starting with parameters from the | 156 | /// The index of the parameter (starting with parameters from the |
@@ -352,6 +376,16 @@ impl Ty { | |||
352 | t.walk(f); | 376 | t.walk(f); |
353 | } | 377 | } |
354 | } | 378 | } |
379 | Ty::Projection(p_ty) => { | ||
380 | for t in p_ty.parameters.iter() { | ||
381 | t.walk(f); | ||
382 | } | ||
383 | } | ||
384 | Ty::UnselectedProjection(p_ty) => { | ||
385 | for t in p_ty.parameters.iter() { | ||
386 | t.walk(f); | ||
387 | } | ||
388 | } | ||
355 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 389 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
356 | } | 390 | } |
357 | f(self); | 391 | f(self); |
@@ -362,6 +396,12 @@ impl Ty { | |||
362 | Ty::Apply(a_ty) => { | 396 | Ty::Apply(a_ty) => { |
363 | a_ty.parameters.walk_mut(f); | 397 | a_ty.parameters.walk_mut(f); |
364 | } | 398 | } |
399 | Ty::Projection(p_ty) => { | ||
400 | p_ty.parameters.walk_mut(f); | ||
401 | } | ||
402 | Ty::UnselectedProjection(p_ty) => { | ||
403 | p_ty.parameters.walk_mut(f); | ||
404 | } | ||
365 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} | 405 | Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} |
366 | } | 406 | } |
367 | f(self); | 407 | f(self); |
@@ -572,15 +612,61 @@ impl HirDisplay for ApplicationTy { | |||
572 | write!(f, ">")?; | 612 | write!(f, ">")?; |
573 | } | 613 | } |
574 | } | 614 | } |
615 | TypeCtor::AssociatedType(type_alias) => { | ||
616 | let trait_name = type_alias | ||
617 | .parent_trait(f.db) | ||
618 | .and_then(|t| t.name(f.db)) | ||
619 | .unwrap_or_else(Name::missing); | ||
620 | let name = type_alias.name(f.db); | ||
621 | write!(f, "{}::{}", trait_name, name)?; | ||
622 | if self.parameters.len() > 0 { | ||
623 | write!(f, "<")?; | ||
624 | f.write_joined(&*self.parameters.0, ", ")?; | ||
625 | write!(f, ">")?; | ||
626 | } | ||
627 | } | ||
575 | } | 628 | } |
576 | Ok(()) | 629 | Ok(()) |
577 | } | 630 | } |
578 | } | 631 | } |
579 | 632 | ||
633 | impl HirDisplay for ProjectionTy { | ||
634 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
635 | let trait_name = self | ||
636 | .associated_ty | ||
637 | .parent_trait(f.db) | ||
638 | .and_then(|t| t.name(f.db)) | ||
639 | .unwrap_or_else(Name::missing); | ||
640 | write!(f, "<{} as {}", self.parameters[0].display(f.db), trait_name,)?; | ||
641 | if self.parameters.len() > 1 { | ||
642 | write!(f, "<")?; | ||
643 | f.write_joined(&self.parameters[1..], ", ")?; | ||
644 | write!(f, ">")?; | ||
645 | } | ||
646 | write!(f, ">::{}", self.associated_ty.name(f.db))?; | ||
647 | Ok(()) | ||
648 | } | ||
649 | } | ||
650 | |||
651 | impl HirDisplay for UnselectedProjectionTy { | ||
652 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
653 | write!(f, "{}", self.parameters[0].display(f.db))?; | ||
654 | if self.parameters.len() > 1 { | ||
655 | write!(f, "<")?; | ||
656 | f.write_joined(&self.parameters[1..], ", ")?; | ||
657 | write!(f, ">")?; | ||
658 | } | ||
659 | write!(f, "::{}", self.type_name)?; | ||
660 | Ok(()) | ||
661 | } | ||
662 | } | ||
663 | |||
580 | impl HirDisplay for Ty { | 664 | impl HirDisplay for Ty { |
581 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | 665 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { |
582 | match self { | 666 | match self { |
583 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, | 667 | Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, |
668 | Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, | ||
669 | Ty::UnselectedProjection(p_ty) => p_ty.hir_fmt(f)?, | ||
584 | Ty::Param { name, .. } => write!(f, "{}", name)?, | 670 | Ty::Param { name, .. } => write!(f, "{}", name)?, |
585 | Ty::Bound(idx) => write!(f, "?{}", idx)?, | 671 | Ty::Bound(idx) => write!(f, "?{}", idx)?, |
586 | Ty::Unknown => write!(f, "{{unknown}}")?, | 672 | Ty::Unknown => write!(f, "{{unknown}}")?, |
@@ -606,3 +692,17 @@ impl HirDisplay for TraitRef { | |||
606 | Ok(()) | 692 | Ok(()) |
607 | } | 693 | } |
608 | } | 694 | } |
695 | |||
696 | impl HirDisplay for Obligation { | ||
697 | fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { | ||
698 | match self { | ||
699 | Obligation::Trait(tr) => write!(f, "Implements({})", tr.display(f.db)), | ||
700 | Obligation::Projection(proj) => write!( | ||
701 | f, | ||
702 | "Normalize({} => {})", | ||
703 | proj.projection_ty.display(f.db), | ||
704 | proj.ty.display(f.db) | ||
705 | ), | ||
706 | } | ||
707 | } | ||
708 | } | ||
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 594c5bc79..675df4a22 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs | |||
@@ -245,7 +245,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
245 | &self.resolver, | 245 | &self.resolver, |
246 | type_ref, | 246 | type_ref, |
247 | ); | 247 | ); |
248 | self.insert_type_vars(ty) | 248 | let ty = self.insert_type_vars(ty); |
249 | self.normalize_associated_types_in(ty) | ||
249 | } | 250 | } |
250 | 251 | ||
251 | fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { | 252 | fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { |
@@ -411,6 +412,32 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
411 | ty | 412 | ty |
412 | } | 413 | } |
413 | 414 | ||
415 | /// Recurses through the given type, normalizing associated types mentioned | ||
416 | /// in it by replacing them by type variables and registering obligations to | ||
417 | /// resolve later. This should be done once for every type we get from some | ||
418 | /// type annotation (e.g. from a let type annotation, field type or function | ||
419 | /// call). `make_ty` handles this already, but e.g. for field types we need | ||
420 | /// to do it as well. | ||
421 | fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { | ||
422 | let ty = self.resolve_ty_as_possible(&mut vec![], ty); | ||
423 | ty.fold(&mut |ty| match ty { | ||
424 | Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty), | ||
425 | Ty::UnselectedProjection(proj_ty) => { | ||
426 | // FIXME use Chalk's unselected projection support | ||
427 | Ty::UnselectedProjection(proj_ty) | ||
428 | } | ||
429 | _ => ty, | ||
430 | }) | ||
431 | } | ||
432 | |||
433 | fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { | ||
434 | let var = self.new_type_var(); | ||
435 | let predicate = ProjectionPredicate { projection_ty: proj_ty.clone(), ty: var.clone() }; | ||
436 | let obligation = Obligation::Projection(predicate); | ||
437 | self.obligations.push(obligation); | ||
438 | var | ||
439 | } | ||
440 | |||
414 | /// Resolves the type completely; type variables without known type are | 441 | /// Resolves the type completely; type variables without known type are |
415 | /// replaced by Ty::Unknown. | 442 | /// replaced by Ty::Unknown. |
416 | fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { | 443 | fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { |
@@ -549,6 +576,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
549 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); | 576 | let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); |
550 | let ty = ty.subst(&substs); | 577 | let ty = ty.subst(&substs); |
551 | let ty = self.insert_type_vars(ty); | 578 | let ty = self.insert_type_vars(ty); |
579 | let ty = self.normalize_associated_types_in(ty); | ||
552 | Some(ty) | 580 | Some(ty) |
553 | } | 581 | } |
554 | Resolution::LocalBinding(pat) => { | 582 | Resolution::LocalBinding(pat) => { |
@@ -670,6 +698,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
670 | .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) | 698 | .and_then(|d| d.field(self.db, &Name::tuple_field_name(i))) |
671 | .map_or(Ty::Unknown, |field| field.ty(self.db)) | 699 | .map_or(Ty::Unknown, |field| field.ty(self.db)) |
672 | .subst(&substs); | 700 | .subst(&substs); |
701 | let expected_ty = self.normalize_associated_types_in(expected_ty); | ||
673 | self.infer_pat(subpat, &expected_ty, default_bm); | 702 | self.infer_pat(subpat, &expected_ty, default_bm); |
674 | } | 703 | } |
675 | 704 | ||
@@ -697,6 +726,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
697 | let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); | 726 | let matching_field = def.and_then(|it| it.field(self.db, &subpat.name)); |
698 | let expected_ty = | 727 | let expected_ty = |
699 | matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); | 728 | matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs); |
729 | let expected_ty = self.normalize_associated_types_in(expected_ty); | ||
700 | self.infer_pat(subpat.pat, &expected_ty, default_bm); | 730 | self.infer_pat(subpat.pat, &expected_ty, default_bm); |
701 | } | 731 | } |
702 | 732 | ||
@@ -927,9 +957,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
927 | self.unify(&expected_receiver_ty, &actual_receiver_ty); | 957 | self.unify(&expected_receiver_ty, &actual_receiver_ty); |
928 | 958 | ||
929 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 959 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); |
930 | for (arg, param) in args.iter().zip(param_iter) { | 960 | for (arg, param_ty) in args.iter().zip(param_iter) { |
931 | self.infer_expr(*arg, &Expectation::has_type(param)); | 961 | let param_ty = self.normalize_associated_types_in(param_ty); |
962 | self.infer_expr(*arg, &Expectation::has_type(param_ty)); | ||
932 | } | 963 | } |
964 | let ret_ty = self.normalize_associated_types_in(ret_ty); | ||
933 | ret_ty | 965 | ret_ty |
934 | } | 966 | } |
935 | 967 | ||
@@ -1020,9 +1052,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1020 | }; | 1052 | }; |
1021 | self.register_obligations_for_call(&callee_ty); | 1053 | self.register_obligations_for_call(&callee_ty); |
1022 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); | 1054 | let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); |
1023 | for (arg, param) in args.iter().zip(param_iter) { | 1055 | for (arg, param_ty) in args.iter().zip(param_iter) { |
1024 | self.infer_expr(*arg, &Expectation::has_type(param)); | 1056 | let param_ty = self.normalize_associated_types_in(param_ty); |
1057 | self.infer_expr(*arg, &Expectation::has_type(param_ty)); | ||
1025 | } | 1058 | } |
1059 | let ret_ty = self.normalize_associated_types_in(ret_ty); | ||
1026 | ret_ty | 1060 | ret_ty |
1027 | } | 1061 | } |
1028 | Expr::MethodCall { receiver, args, method_name, generic_args } => self | 1062 | Expr::MethodCall { receiver, args, method_name, generic_args } => self |
@@ -1120,7 +1154,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
1120 | _ => None, | 1154 | _ => None, |
1121 | }) | 1155 | }) |
1122 | .unwrap_or(Ty::Unknown); | 1156 | .unwrap_or(Ty::Unknown); |
1123 | self.insert_type_vars(ty) | 1157 | let ty = self.insert_type_vars(ty); |
1158 | self.normalize_associated_types_in(ty) | ||
1124 | } | 1159 | } |
1125 | Expr::Await { expr } => { | 1160 | Expr::Await { expr } => { |
1126 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); | 1161 | let inner_ty = self.infer_expr(*expr, &Expectation::none()); |
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 894ba0695..debedcbb8 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -8,7 +8,7 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use super::{FnSig, GenericPredicate, Substs, TraitRef, Ty, TypeCtor}; | 11 | use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; |
12 | use crate::{ | 12 | use crate::{ |
13 | adt::VariantDef, | 13 | adt::VariantDef, |
14 | generics::HasGenericParams, | 14 | generics::HasGenericParams, |
@@ -64,7 +64,8 @@ impl Ty { | |||
64 | 64 | ||
65 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { | 65 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Self { |
66 | // Resolve the path (in type namespace) | 66 | // Resolve the path (in type namespace) |
67 | let resolution = resolver.resolve_path_without_assoc_items(db, path).take_types(); | 67 | let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner(); |
68 | let resolution = resolution.take_types(); | ||
68 | 69 | ||
69 | let def = match resolution { | 70 | let def = match resolution { |
70 | Some(Resolution::Def(def)) => def, | 71 | Some(Resolution::Def(def)) => def, |
@@ -73,6 +74,10 @@ impl Ty { | |||
73 | panic!("path resolved to local binding in type ns"); | 74 | panic!("path resolved to local binding in type ns"); |
74 | } | 75 | } |
75 | Some(Resolution::GenericParam(idx)) => { | 76 | Some(Resolution::GenericParam(idx)) => { |
77 | if remaining_index.is_some() { | ||
78 | // e.g. T::Item | ||
79 | return Ty::Unknown; | ||
80 | } | ||
76 | return Ty::Param { | 81 | return Ty::Param { |
77 | idx, | 82 | idx, |
78 | // FIXME: maybe return name in resolution? | 83 | // FIXME: maybe return name in resolution? |
@@ -83,18 +88,54 @@ impl Ty { | |||
83 | }; | 88 | }; |
84 | } | 89 | } |
85 | Some(Resolution::SelfType(impl_block)) => { | 90 | Some(Resolution::SelfType(impl_block)) => { |
91 | if remaining_index.is_some() { | ||
92 | // e.g. Self::Item | ||
93 | return Ty::Unknown; | ||
94 | } | ||
86 | return impl_block.target_ty(db); | 95 | return impl_block.target_ty(db); |
87 | } | 96 | } |
88 | None => return Ty::Unknown, | 97 | None => { |
98 | // path did not resolve | ||
99 | return Ty::Unknown; | ||
100 | } | ||
89 | }; | 101 | }; |
90 | 102 | ||
91 | let typable: TypableDef = match def.into() { | 103 | if let ModuleDef::Trait(trait_) = def { |
92 | None => return Ty::Unknown, | 104 | let segment = match remaining_index { |
93 | Some(it) => it, | 105 | None => path.segments.last().expect("resolved path has at least one element"), |
94 | }; | 106 | Some(i) => &path.segments[i - 1], |
95 | let ty = db.type_for_def(typable, Namespace::Types); | 107 | }; |
96 | let substs = Ty::substs_from_path(db, resolver, path, typable); | 108 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); |
97 | ty.subst(&substs) | 109 | if let Some(remaining_index) = remaining_index { |
110 | if remaining_index == path.segments.len() - 1 { | ||
111 | let segment = &path.segments[remaining_index]; | ||
112 | let associated_ty = | ||
113 | match trait_ref.trait_.associated_type_by_name(db, segment.name.clone()) { | ||
114 | Some(t) => t, | ||
115 | None => { | ||
116 | // associated type not found | ||
117 | return Ty::Unknown; | ||
118 | } | ||
119 | }; | ||
120 | // FIXME handle type parameters on the segment | ||
121 | Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) | ||
122 | } else { | ||
123 | // FIXME more than one segment remaining, is this possible? | ||
124 | Ty::Unknown | ||
125 | } | ||
126 | } else { | ||
127 | // FIXME dyn Trait without the dyn | ||
128 | Ty::Unknown | ||
129 | } | ||
130 | } else { | ||
131 | let typable: TypableDef = match def.into() { | ||
132 | None => return Ty::Unknown, | ||
133 | Some(it) => it, | ||
134 | }; | ||
135 | let ty = db.type_for_def(typable, Namespace::Types); | ||
136 | let substs = Ty::substs_from_path(db, resolver, path, typable); | ||
137 | ty.subst(&substs) | ||
138 | } | ||
98 | } | 139 | } |
99 | 140 | ||
100 | pub(super) fn substs_from_path_segment( | 141 | pub(super) fn substs_from_path_segment( |
@@ -219,14 +260,25 @@ impl TraitRef { | |||
219 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | 260 | Resolution::Def(ModuleDef::Trait(tr)) => tr, |
220 | _ => return None, | 261 | _ => return None, |
221 | }; | 262 | }; |
222 | let mut substs = Self::substs_from_path(db, resolver, path, resolved); | 263 | let segment = path.segments.last().expect("path should have at least one segment"); |
264 | Some(TraitRef::from_resolved_path(db, resolver, resolved, segment, explicit_self_ty)) | ||
265 | } | ||
266 | |||
267 | fn from_resolved_path( | ||
268 | db: &impl HirDatabase, | ||
269 | resolver: &Resolver, | ||
270 | resolved: Trait, | ||
271 | segment: &PathSegment, | ||
272 | explicit_self_ty: Option<Ty>, | ||
273 | ) -> Self { | ||
274 | let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); | ||
223 | if let Some(self_ty) = explicit_self_ty { | 275 | if let Some(self_ty) = explicit_self_ty { |
224 | // FIXME this could be nicer | 276 | // FIXME this could be nicer |
225 | let mut substs_vec = substs.0.to_vec(); | 277 | let mut substs_vec = substs.0.to_vec(); |
226 | substs_vec[0] = self_ty; | 278 | substs_vec[0] = self_ty; |
227 | substs.0 = substs_vec.into(); | 279 | substs.0 = substs_vec.into(); |
228 | } | 280 | } |
229 | Some(TraitRef { trait_: resolved, substs }) | 281 | TraitRef { trait_: resolved, substs } |
230 | } | 282 | } |
231 | 283 | ||
232 | pub(crate) fn from_hir( | 284 | pub(crate) fn from_hir( |
@@ -245,11 +297,12 @@ impl TraitRef { | |||
245 | fn substs_from_path( | 297 | fn substs_from_path( |
246 | db: &impl HirDatabase, | 298 | db: &impl HirDatabase, |
247 | resolver: &Resolver, | 299 | resolver: &Resolver, |
248 | path: &Path, | 300 | segment: &PathSegment, |
249 | resolved: Trait, | 301 | resolved: Trait, |
250 | ) -> Substs { | 302 | ) -> Substs { |
251 | let segment = path.segments.last().expect("path should have at least one segment"); | 303 | let has_self_param = |
252 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), true) | 304 | segment.args_and_bindings.as_ref().map(|a| a.has_self_type).unwrap_or(false); |
305 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), !has_self_param) | ||
253 | } | 306 | } |
254 | 307 | ||
255 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { | 308 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { |
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs index d421bf9ef..88d012a74 100644 --- a/crates/ra_hir/src/ty/method_resolution.rs +++ b/crates/ra_hir/src/ty/method_resolution.rs | |||
@@ -255,6 +255,20 @@ fn iterate_inherent_methods<T>( | |||
255 | None | 255 | None |
256 | } | 256 | } |
257 | 257 | ||
258 | pub(crate) fn implements_trait( | ||
259 | ty: &Canonical<Ty>, | ||
260 | db: &impl HirDatabase, | ||
261 | resolver: &Resolver, | ||
262 | krate: Crate, | ||
263 | trait_: Trait, | ||
264 | ) -> bool { | ||
265 | let env = lower::trait_env(db, resolver); | ||
266 | let goal = generic_implements_goal(db, env.clone(), trait_, ty.clone()); | ||
267 | let solution = db.trait_solve(krate, goal); | ||
268 | |||
269 | solution.is_some() | ||
270 | } | ||
271 | |||
258 | impl Ty { | 272 | impl Ty { |
259 | // This would be nicer if it just returned an iterator, but that runs into | 273 | // This would be nicer if it just returned an iterator, but that runs into |
260 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. | 274 | // lifetime problems, because we need to borrow temp `CrateImplBlocks`. |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index 36dea17a3..28727bb18 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -145,6 +145,26 @@ mod collections { | |||
145 | } | 145 | } |
146 | 146 | ||
147 | #[test] | 147 | #[test] |
148 | fn infer_while_let() { | ||
149 | covers!(infer_while_let); | ||
150 | let (db, pos) = MockDatabase::with_position( | ||
151 | r#" | ||
152 | //- /main.rs | ||
153 | enum Option<T> { Some(T), None } | ||
154 | |||
155 | fn test() { | ||
156 | let foo: Option<f32> = None; | ||
157 | while let Option::Some(x) = foo { | ||
158 | <|>x | ||
159 | } | ||
160 | } | ||
161 | |||
162 | "#, | ||
163 | ); | ||
164 | assert_eq!("f32", type_at_pos(&db, pos)); | ||
165 | } | ||
166 | |||
167 | #[test] | ||
148 | fn infer_basics() { | 168 | fn infer_basics() { |
149 | assert_snapshot_matches!( | 169 | assert_snapshot_matches!( |
150 | infer(r#" | 170 | infer(r#" |
@@ -2488,15 +2508,55 @@ struct S; | |||
2488 | impl Iterable for S { type Item = u32; } | 2508 | impl Iterable for S { type Item = u32; } |
2489 | fn test<T: Iterable>() { | 2509 | fn test<T: Iterable>() { |
2490 | let x: <S as Iterable>::Item = 1; | 2510 | let x: <S as Iterable>::Item = 1; |
2491 | let y: T::Item = no_matter; | 2511 | let y: <T as Iterable>::Item = no_matter; |
2512 | let z: T::Item = no_matter; | ||
2513 | } | ||
2514 | "#), | ||
2515 | @r###" | ||
2516 | ⋮ | ||
2517 | ⋮[108; 227) '{ ...ter; }': () | ||
2518 | ⋮[118; 119) 'x': u32 | ||
2519 | ⋮[145; 146) '1': u32 | ||
2520 | ⋮[156; 157) 'y': {unknown} | ||
2521 | ⋮[183; 192) 'no_matter': {unknown} | ||
2522 | ⋮[202; 203) 'z': {unknown} | ||
2523 | ⋮[215; 224) 'no_matter': {unknown} | ||
2524 | "### | ||
2525 | ); | ||
2526 | } | ||
2527 | |||
2528 | #[test] | ||
2529 | fn infer_return_associated_type() { | ||
2530 | assert_snapshot_matches!( | ||
2531 | infer(r#" | ||
2532 | trait Iterable { | ||
2533 | type Item; | ||
2534 | } | ||
2535 | struct S; | ||
2536 | impl Iterable for S { type Item = u32; } | ||
2537 | fn foo1<T: Iterable>(t: T) -> T::Item {} | ||
2538 | fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} | ||
2539 | fn test() { | ||
2540 | let x = foo1(S); | ||
2541 | let y = foo2(S); | ||
2492 | } | 2542 | } |
2493 | "#), | 2543 | "#), |
2494 | @r###" | 2544 | @r###" |
2495 | [108; 181) '{ ...ter; }': () | 2545 | ⋮ |
2496 | [118; 119) 'x': i32 | 2546 | ⋮[106; 107) 't': T |
2497 | [145; 146) '1': i32 | 2547 | ⋮[123; 125) '{}': () |
2498 | [156; 157) 'y': {unknown} | 2548 | ⋮[147; 148) 't': T |
2499 | [169; 178) 'no_matter': {unknown}"### | 2549 | ⋮[178; 180) '{}': () |
2550 | ⋮[191; 236) '{ ...(S); }': () | ||
2551 | ⋮[201; 202) 'x': {unknown} | ||
2552 | ⋮[205; 209) 'foo1': fn foo1<S>(T) -> {unknown} | ||
2553 | ⋮[205; 212) 'foo1(S)': {unknown} | ||
2554 | ⋮[210; 211) 'S': S | ||
2555 | ⋮[222; 223) 'y': u32 | ||
2556 | ⋮[226; 230) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item | ||
2557 | ⋮[226; 233) 'foo2(S)': u32 | ||
2558 | ⋮[231; 232) 'S': S | ||
2559 | "### | ||
2500 | ); | 2560 | ); |
2501 | } | 2561 | } |
2502 | 2562 | ||
@@ -3121,6 +3181,55 @@ fn test<T: Trait>(t: T) { (*t)<|>; } | |||
3121 | assert_eq!(t, "i128"); | 3181 | assert_eq!(t, "i128"); |
3122 | } | 3182 | } |
3123 | 3183 | ||
3184 | #[test] | ||
3185 | fn associated_type_placeholder() { | ||
3186 | let t = type_at( | ||
3187 | r#" | ||
3188 | //- /main.rs | ||
3189 | pub trait ApplyL { | ||
3190 | type Out; | ||
3191 | } | ||
3192 | |||
3193 | pub struct RefMutL<T>; | ||
3194 | |||
3195 | impl<T> ApplyL for RefMutL<T> { | ||
3196 | type Out = <T as ApplyL>::Out; | ||
3197 | } | ||
3198 | |||
3199 | fn test<T: ApplyL>() { | ||
3200 | let y: <RefMutL<T> as ApplyL>::Out = no_matter; | ||
3201 | y<|>; | ||
3202 | } | ||
3203 | "#, | ||
3204 | ); | ||
3205 | // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types]. | ||
3206 | // FIXME: fix type parameter names going missing when going through Chalk | ||
3207 | assert_eq!(t, "ApplyL::Out<[missing name]>"); | ||
3208 | } | ||
3209 | |||
3210 | #[test] | ||
3211 | fn associated_type_placeholder_2() { | ||
3212 | let t = type_at( | ||
3213 | r#" | ||
3214 | //- /main.rs | ||
3215 | pub trait ApplyL { | ||
3216 | type Out; | ||
3217 | } | ||
3218 | fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out; | ||
3219 | |||
3220 | fn test<T: ApplyL>(t: T) { | ||
3221 | let y = foo(t); | ||
3222 | y<|>; | ||
3223 | } | ||
3224 | "#, | ||
3225 | ); | ||
3226 | // FIXME here Chalk doesn't normalize the type to a placeholder. I think we | ||
3227 | // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>) | ||
3228 | // to the trait env ourselves here; probably Chalk can't do this by itself. | ||
3229 | // assert_eq!(t, "ApplyL::Out<[missing name]>"); | ||
3230 | assert_eq!(t, "{unknown}"); | ||
3231 | } | ||
3232 | |||
3124 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 3233 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
3125 | let file = db.parse(pos.file_id).ok().unwrap(); | 3234 | let file = db.parse(pos.file_id).ok().unwrap(); |
3126 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); | 3235 | let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); |
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs index 0769e6e17..fde5d8a47 100644 --- a/crates/ra_hir/src/ty/traits.rs +++ b/crates/ra_hir/src/ty/traits.rs | |||
@@ -7,7 +7,7 @@ use parking_lot::Mutex; | |||
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
9 | 9 | ||
10 | use super::{Canonical, GenericPredicate, ProjectionTy, TraitRef, Ty}; | 10 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty}; |
11 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; | 11 | use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; |
12 | 12 | ||
13 | use self::chalk::{from_chalk, ToChalk}; | 13 | use self::chalk::{from_chalk, ToChalk}; |
@@ -61,7 +61,6 @@ fn solve( | |||
61 | ) -> Option<chalk_solve::Solution> { | 61 | ) -> Option<chalk_solve::Solution> { |
62 | let context = ChalkContext { db, krate }; | 62 | let context = ChalkContext { db, krate }; |
63 | let solver = db.trait_solver(krate); | 63 | let solver = db.trait_solver(krate); |
64 | debug!("solve goal: {:?}", goal); | ||
65 | let solution = solver.lock().solve(&context, goal); | 64 | let solution = solver.lock().solve(&context, goal); |
66 | debug!("solve({:?}) => {:?}", goal, solution); | 65 | debug!("solve({:?}) => {:?}", goal, solution); |
67 | solution | 66 | solution |
@@ -120,10 +119,11 @@ pub struct ProjectionPredicate { | |||
120 | pub(crate) fn trait_solve_query( | 119 | pub(crate) fn trait_solve_query( |
121 | db: &impl HirDatabase, | 120 | db: &impl HirDatabase, |
122 | krate: Crate, | 121 | krate: Crate, |
123 | trait_ref: Canonical<InEnvironment<Obligation>>, | 122 | goal: Canonical<InEnvironment<Obligation>>, |
124 | ) -> Option<Solution> { | 123 | ) -> Option<Solution> { |
125 | let _p = profile("trait_solve_query"); | 124 | let _p = profile("trait_solve_query"); |
126 | let canonical = trait_ref.to_chalk(db).cast(); | 125 | debug!("trait_solve_query({})", goal.value.value.display(db)); |
126 | let canonical = goal.to_chalk(db).cast(); | ||
127 | // We currently don't deal with universes (I think / hope they're not yet | 127 | // We currently don't deal with universes (I think / hope they're not yet |
128 | // relevant for our use cases?) | 128 | // relevant for our use cases?) |
129 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; | 129 | let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 9e7ae0724..6df7094c5 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -45,11 +45,33 @@ impl ToChalk for Ty { | |||
45 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { | 45 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty { |
46 | match self { | 46 | match self { |
47 | Ty::Apply(apply_ty) => { | 47 | Ty::Apply(apply_ty) => { |
48 | let struct_id = apply_ty.ctor.to_chalk(db); | 48 | let name = match apply_ty.ctor { |
49 | let name = TypeName::TypeKindId(struct_id.into()); | 49 | TypeCtor::AssociatedType(type_alias) => { |
50 | let type_id = type_alias.to_chalk(db); | ||
51 | TypeName::AssociatedType(type_id) | ||
52 | } | ||
53 | _ => { | ||
54 | // other TypeCtors get interned and turned into a chalk StructId | ||
55 | let struct_id = apply_ty.ctor.to_chalk(db); | ||
56 | TypeName::TypeKindId(struct_id.into()) | ||
57 | } | ||
58 | }; | ||
50 | let parameters = apply_ty.parameters.to_chalk(db); | 59 | let parameters = apply_ty.parameters.to_chalk(db); |
51 | chalk_ir::ApplicationTy { name, parameters }.cast() | 60 | chalk_ir::ApplicationTy { name, parameters }.cast() |
52 | } | 61 | } |
62 | Ty::Projection(proj_ty) => { | ||
63 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | ||
64 | let parameters = proj_ty.parameters.to_chalk(db); | ||
65 | chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast() | ||
66 | } | ||
67 | Ty::UnselectedProjection(proj_ty) => { | ||
68 | let type_name = lalrpop_intern::intern(&proj_ty.type_name.to_string()); | ||
69 | let parameters = proj_ty.parameters.to_chalk(db); | ||
70 | chalk_ir::Ty::UnselectedProjection(chalk_ir::UnselectedProjectionTy { | ||
71 | type_name, | ||
72 | parameters, | ||
73 | }) | ||
74 | } | ||
53 | Ty::Param { idx, .. } => { | 75 | Ty::Param { idx, .. } => { |
54 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty() | 76 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty() |
55 | } | 77 | } |
@@ -66,15 +88,21 @@ impl ToChalk for Ty { | |||
66 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { | 88 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { |
67 | match chalk { | 89 | match chalk { |
68 | chalk_ir::Ty::Apply(apply_ty) => { | 90 | chalk_ir::Ty::Apply(apply_ty) => { |
91 | // FIXME this is kind of hacky due to the fact that | ||
92 | // TypeName::Placeholder is a Ty::Param on our side | ||
69 | match apply_ty.name { | 93 | match apply_ty.name { |
70 | TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { | 94 | TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { |
71 | let ctor = from_chalk(db, struct_id); | 95 | let ctor = from_chalk(db, struct_id); |
72 | let parameters = from_chalk(db, apply_ty.parameters); | 96 | let parameters = from_chalk(db, apply_ty.parameters); |
73 | Ty::Apply(ApplicationTy { ctor, parameters }) | 97 | Ty::Apply(ApplicationTy { ctor, parameters }) |
74 | } | 98 | } |
99 | TypeName::AssociatedType(type_id) => { | ||
100 | let ctor = TypeCtor::AssociatedType(from_chalk(db, type_id)); | ||
101 | let parameters = from_chalk(db, apply_ty.parameters); | ||
102 | Ty::Apply(ApplicationTy { ctor, parameters }) | ||
103 | } | ||
75 | // FIXME handle TypeKindId::Trait/Type here | 104 | // FIXME handle TypeKindId::Trait/Type here |
76 | TypeName::TypeKindId(_) => unimplemented!(), | 105 | TypeName::TypeKindId(_) => unimplemented!(), |
77 | TypeName::AssociatedType(_) => unimplemented!(), | ||
78 | TypeName::Placeholder(idx) => { | 106 | TypeName::Placeholder(idx) => { |
79 | assert_eq!(idx.ui, UniverseIndex::ROOT); | 107 | assert_eq!(idx.ui, UniverseIndex::ROOT); |
80 | Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } | 108 | Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() } |
@@ -389,11 +417,12 @@ where | |||
389 | &self, | 417 | &self, |
390 | projection: &'p chalk_ir::ProjectionTy, | 418 | projection: &'p chalk_ir::ProjectionTy, |
391 | ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { | 419 | ) -> (Arc<AssociatedTyDatum>, &'p [Parameter], &'p [Parameter]) { |
392 | debug!("split_projection {:?}", projection); | 420 | let proj_ty: ProjectionTy = from_chalk(self.db, projection.clone()); |
393 | unimplemented!() | 421 | debug!("split_projection {:?} = {}", projection, proj_ty.display(self.db)); |
422 | // we don't support GATs, so I think this should always be correct currently | ||
423 | (self.db.associated_ty_data(projection.associated_ty_id), &projection.parameters, &[]) | ||
394 | } | 424 | } |
395 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> { | 425 | fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause> { |
396 | debug!("custom_clauses"); | ||
397 | vec![] | 426 | vec![] |
398 | } | 427 | } |
399 | fn all_structs(&self) -> Vec<chalk_ir::StructId> { | 428 | fn all_structs(&self) -> Vec<chalk_ir::StructId> { |
@@ -529,6 +558,16 @@ pub(crate) fn struct_datum_query( | |||
529 | adt.krate(db) != Some(krate), | 558 | adt.krate(db) != Some(krate), |
530 | ) | 559 | ) |
531 | } | 560 | } |
561 | TypeCtor::AssociatedType(type_alias) => { | ||
562 | let generic_params = type_alias.generic_params(db); | ||
563 | let bound_vars = Substs::bound_vars(&generic_params); | ||
564 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | ||
565 | ( | ||
566 | generic_params.count_params_including_parent(), | ||
567 | where_clauses, | ||
568 | type_alias.krate(db) != Some(krate), | ||
569 | ) | ||
570 | } | ||
532 | }; | 571 | }; |
533 | let flags = chalk_rust_ir::StructFlags { | 572 | let flags = chalk_rust_ir::StructFlags { |
534 | upstream, | 573 | upstream, |