aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/hir/src/lib.rs21
-rw-r--r--crates/hir_def/src/attr.rs11
-rw-r--r--crates/hir_def/src/item_tree.rs35
-rw-r--r--crates/hir_def/src/item_tree/lower.rs56
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs525
-rw-r--r--crates/hir_def/src/item_tree/tests.rs244
-rw-r--r--crates/hir_def/src/nameres/collector.rs314
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs17
-rw-r--r--crates/hir_def/src/nameres/tests/macros.rs74
-rw-r--r--crates/hir_def/src/path.rs9
-rw-r--r--crates/hir_expand/src/name.rs2
-rw-r--r--crates/hir_ty/src/builder.rs16
-rw-r--r--crates/hir_ty/src/chalk_db.rs15
-rw-r--r--crates/hir_ty/src/chalk_ext.rs5
-rw-r--r--crates/hir_ty/src/db.rs10
-rw-r--r--crates/hir_ty/src/infer.rs192
-rw-r--r--crates/hir_ty/src/infer/coerce.rs480
-rw-r--r--crates/hir_ty/src/infer/expr.rs142
-rw-r--r--crates/hir_ty/src/infer/pat.rs19
-rw-r--r--crates/hir_ty/src/infer/path.rs6
-rw-r--r--crates/hir_ty/src/infer/unify.rs861
-rw-r--r--crates/hir_ty/src/interner.rs49
-rw-r--r--crates/hir_ty/src/lib.rs71
-rw-r--r--crates/hir_ty/src/lower.rs4
-rw-r--r--crates/hir_ty/src/method_resolution.rs47
-rw-r--r--crates/hir_ty/src/tests/coercion.rs56
-rw-r--r--crates/hir_ty/src/tests/patterns.rs2
-rw-r--r--crates/hir_ty/src/tests/regression.rs69
-rw-r--r--crates/hir_ty/src/tests/simple.rs36
-rw-r--r--crates/hir_ty/src/tests/traits.rs2
-rw-r--r--crates/hir_ty/src/tls.rs138
-rw-r--r--crates/hir_ty/src/traits.rs40
-rw-r--r--crates/ide/src/lib.rs5
-rw-r--r--crates/ide/src/view_item_tree.rs16
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs17
-rw-r--r--crates/ide_assists/src/handlers/merge_imports.rs14
-rw-r--r--crates/ide_assists/src/tests.rs8
-rw-r--r--crates/ide_completion/src/render.rs2
-rw-r--r--crates/ide_completion/src/test_utils.rs8
-rw-r--r--crates/ide_db/src/helpers/insert_use.rs105
-rw-r--r--crates/ide_db/src/helpers/insert_use/tests.rs141
-rw-r--r--crates/ide_db/src/helpers/merge_imports.rs21
-rw-r--r--crates/rust-analyzer/src/config.rs46
-rw-r--r--crates/rust-analyzer/src/handlers.rs10
-rw-r--r--crates/rust-analyzer/src/integrated_benchmarks.rs11
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs14
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs14
-rw-r--r--crates/stdx/src/lib.rs28
-rw-r--r--crates/syntax/src/ast/node_ext.rs23
-rw-r--r--docs/dev/lsp-extensions.md20
-rw-r--r--docs/user/generated_config.adoc9
-rw-r--r--docs/user/manual.adoc2
-rw-r--r--editors/code/package.json26
-rw-r--r--editors/code/src/commands.ts50
-rw-r--r--editors/code/src/lsp_ext.ts6
-rw-r--r--editors/code/src/main.ts1
57 files changed, 2875 insertions, 1291 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d443b124c..52d72c3c5 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1712,15 +1712,17 @@ impl Type {
1712 resolver: &Resolver, 1712 resolver: &Resolver,
1713 ty: Ty, 1713 ty: Ty,
1714 ) -> Type { 1714 ) -> Type {
1715 let environment = 1715 let environment = resolver
1716 resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d)); 1716 .generic_def()
1717 .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
1717 Type { krate, env: environment, ty } 1718 Type { krate, env: environment, ty }
1718 } 1719 }
1719 1720
1720 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type { 1721 fn new(db: &dyn HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
1721 let resolver = lexical_env.resolver(db.upcast()); 1722 let resolver = lexical_env.resolver(db.upcast());
1722 let environment = 1723 let environment = resolver
1723 resolver.generic_def().map_or_else(Default::default, |d| db.trait_environment(d)); 1724 .generic_def()
1725 .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
1724 Type { krate, env: environment, ty } 1726 Type { krate, env: environment, ty }
1725 } 1727 }
1726 1728
@@ -2051,11 +2053,7 @@ impl Type {
2051 name: Option<&Name>, 2053 name: Option<&Name>,
2052 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>, 2054 mut callback: impl FnMut(&Ty, AssocItem) -> Option<T>,
2053 ) -> Option<T> { 2055 ) -> Option<T> {
2054 // There should be no inference vars in types passed here 2056 let canonical = hir_ty::replace_errors_with_variables(self.ty.clone());
2055 // FIXME check that?
2056 // FIXME replace Unknown by bound vars here
2057 let canonical =
2058 Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(&Interner) };
2059 2057
2060 let env = self.env.clone(); 2058 let env = self.env.clone();
2061 let krate = krate.id; 2059 let krate = krate.id;
@@ -2223,8 +2221,9 @@ impl Type {
2223 walk_type(db, self, &mut cb); 2221 walk_type(db, self, &mut cb);
2224 } 2222 }
2225 2223
2226 pub fn could_unify_with(&self, other: &Type) -> bool { 2224 pub fn could_unify_with(&self, db: &dyn HirDatabase, other: &Type) -> bool {
2227 could_unify(&self.ty, &other.ty) 2225 let tys = hir_ty::replace_errors_with_variables((self.ty.clone(), other.ty.clone()));
2226 could_unify(db, self.env.clone(), &tys)
2228 } 2227 }
2229} 2228}
2230 2229
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index aadd4e44a..89a1ea770 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -2,7 +2,7 @@
2 2
3use std::{ 3use std::{
4 convert::{TryFrom, TryInto}, 4 convert::{TryFrom, TryInto},
5 ops, 5 fmt, ops,
6 sync::Arc, 6 sync::Arc,
7}; 7};
8 8
@@ -648,6 +648,15 @@ pub enum AttrInput {
648 TokenTree(Subtree), 648 TokenTree(Subtree),
649} 649}
650 650
651impl fmt::Display for AttrInput {
652 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
653 match self {
654 AttrInput::Literal(lit) => write!(f, " = \"{}\"", lit.escape_debug()),
655 AttrInput::TokenTree(subtree) => subtree.fmt(f),
656 }
657 }
658}
659
651impl Attr { 660impl Attr {
652 fn from_src( 661 fn from_src(
653 db: &dyn DefDatabase, 662 db: &dyn DefDatabase,
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index cad8a7479..528270d49 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -1,6 +1,9 @@
1//! A simplified AST that only contains items. 1//! A simplified AST that only contains items.
2 2
3mod lower; 3mod lower;
4mod pretty;
5#[cfg(test)]
6mod tests;
4 7
5use std::{ 8use std::{
6 any::type_name, 9 any::type_name,
@@ -132,6 +135,7 @@ impl ItemTree {
132 let ItemTreeData { 135 let ItemTreeData {
133 imports, 136 imports,
134 extern_crates, 137 extern_crates,
138 extern_blocks,
135 functions, 139 functions,
136 params, 140 params,
137 structs, 141 structs,
@@ -154,6 +158,7 @@ impl ItemTree {
154 158
155 imports.shrink_to_fit(); 159 imports.shrink_to_fit();
156 extern_crates.shrink_to_fit(); 160 extern_crates.shrink_to_fit();
161 extern_blocks.shrink_to_fit();
157 functions.shrink_to_fit(); 162 functions.shrink_to_fit();
158 params.shrink_to_fit(); 163 params.shrink_to_fit();
159 structs.shrink_to_fit(); 164 structs.shrink_to_fit();
@@ -203,6 +208,10 @@ impl ItemTree {
203 } 208 }
204 } 209 }
205 210
211 pub fn pretty_print(&self) -> String {
212 pretty::print_item_tree(self)
213 }
214
206 fn data(&self) -> &ItemTreeData { 215 fn data(&self) -> &ItemTreeData {
207 self.data.as_ref().expect("attempted to access data of empty ItemTree") 216 self.data.as_ref().expect("attempted to access data of empty ItemTree")
208 } 217 }
@@ -239,6 +248,7 @@ static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(P
239struct ItemTreeData { 248struct ItemTreeData {
240 imports: Arena<Import>, 249 imports: Arena<Import>,
241 extern_crates: Arena<ExternCrate>, 250 extern_crates: Arena<ExternCrate>,
251 extern_blocks: Arena<ExternBlock>,
242 functions: Arena<Function>, 252 functions: Arena<Function>,
243 params: Arena<Param>, 253 params: Arena<Param>,
244 structs: Arena<Struct>, 254 structs: Arena<Struct>,
@@ -432,6 +442,7 @@ macro_rules! mod_items {
432mod_items! { 442mod_items! {
433 Import in imports -> ast::Use, 443 Import in imports -> ast::Use,
434 ExternCrate in extern_crates -> ast::ExternCrate, 444 ExternCrate in extern_crates -> ast::ExternCrate,
445 ExternBlock in extern_blocks -> ast::ExternBlock,
435 Function in functions -> ast::Fn, 446 Function in functions -> ast::Fn,
436 Struct in structs -> ast::Struct, 447 Struct in structs -> ast::Struct,
437 Union in unions -> ast::Union, 448 Union in unions -> ast::Union,
@@ -508,6 +519,13 @@ pub struct ExternCrate {
508} 519}
509 520
510#[derive(Debug, Clone, Eq, PartialEq)] 521#[derive(Debug, Clone, Eq, PartialEq)]
522pub struct ExternBlock {
523 pub abi: Option<Interned<str>>,
524 pub ast_id: FileAstId<ast::ExternBlock>,
525 pub children: Box<[ModItem]>,
526}
527
528#[derive(Debug, Clone, Eq, PartialEq)]
511pub struct Function { 529pub struct Function {
512 pub name: Name, 530 pub name: Name,
513 pub visibility: RawVisibilityId, 531 pub visibility: RawVisibilityId,
@@ -549,17 +567,6 @@ pub struct Struct {
549 pub generic_params: Interned<GenericParams>, 567 pub generic_params: Interned<GenericParams>,
550 pub fields: Fields, 568 pub fields: Fields,
551 pub ast_id: FileAstId<ast::Struct>, 569 pub ast_id: FileAstId<ast::Struct>,
552 pub kind: StructDefKind,
553}
554
555#[derive(Debug, Clone, Eq, PartialEq)]
556pub enum StructDefKind {
557 /// `struct S { ... }` - type namespace only.
558 Record,
559 /// `struct S(...);`
560 Tuple,
561 /// `struct S;`
562 Unit,
563} 570}
564 571
565#[derive(Debug, Clone, Eq, PartialEq)] 572#[derive(Debug, Clone, Eq, PartialEq)]
@@ -691,6 +698,7 @@ impl ModItem {
691 match self { 698 match self {
692 ModItem::Import(_) 699 ModItem::Import(_)
693 | ModItem::ExternCrate(_) 700 | ModItem::ExternCrate(_)
701 | ModItem::ExternBlock(_)
694 | ModItem::Struct(_) 702 | ModItem::Struct(_)
695 | ModItem::Union(_) 703 | ModItem::Union(_)
696 | ModItem::Enum(_) 704 | ModItem::Enum(_)
@@ -715,6 +723,7 @@ impl ModItem {
715 match self { 723 match self {
716 ModItem::Import(it) => tree[it.index].ast_id().upcast(), 724 ModItem::Import(it) => tree[it.index].ast_id().upcast(),
717 ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(), 725 ModItem::ExternCrate(it) => tree[it.index].ast_id().upcast(),
726 ModItem::ExternBlock(it) => tree[it.index].ast_id().upcast(),
718 ModItem::Function(it) => tree[it.index].ast_id().upcast(), 727 ModItem::Function(it) => tree[it.index].ast_id().upcast(),
719 ModItem::Struct(it) => tree[it.index].ast_id().upcast(), 728 ModItem::Struct(it) => tree[it.index].ast_id().upcast(),
720 ModItem::Union(it) => tree[it.index].ast_id().upcast(), 729 ModItem::Union(it) => tree[it.index].ast_id().upcast(),
@@ -774,6 +783,10 @@ impl<T> IdRange<T> {
774 fn new(range: Range<Idx<T>>) -> Self { 783 fn new(range: Range<Idx<T>>) -> Self {
775 Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData } 784 Self { range: range.start.into_raw().into()..range.end.into_raw().into(), _p: PhantomData }
776 } 785 }
786
787 fn is_empty(&self) -> bool {
788 self.range.is_empty()
789 }
777} 790}
778 791
779impl<T> Iterator for IdRange<T> { 792impl<T> Iterator for IdRange<T> {
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index fe348091d..91cf75371 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -147,9 +147,7 @@ impl<'a> Ctx<'a> {
147 ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into), 147 ast::Item::MacroCall(ast) => self.lower_macro_call(ast).map(Into::into),
148 ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into), 148 ast::Item::MacroRules(ast) => self.lower_macro_rules(ast).map(Into::into),
149 ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into), 149 ast::Item::MacroDef(ast) => self.lower_macro_def(ast).map(Into::into),
150 ast::Item::ExternBlock(ast) => { 150 ast::Item::ExternBlock(ast) => Some(self.lower_extern_block(ast).into()),
151 Some(ModItems(self.lower_extern_block(ast).into_iter().collect::<SmallVec<_>>()))
152 }
153 }; 151 };
154 152
155 if !attrs.is_empty() { 153 if !attrs.is_empty() {
@@ -230,12 +228,7 @@ impl<'a> Ctx<'a> {
230 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt); 228 let generic_params = self.lower_generic_params(GenericsOwner::Struct, strukt);
231 let fields = self.lower_fields(&strukt.kind()); 229 let fields = self.lower_fields(&strukt.kind());
232 let ast_id = self.source_ast_id_map.ast_id(strukt); 230 let ast_id = self.source_ast_id_map.ast_id(strukt);
233 let kind = match strukt.kind() { 231 let res = Struct { name, visibility, generic_params, fields, ast_id };
234 ast::StructKind::Record(_) => StructDefKind::Record,
235 ast::StructKind::Tuple(_) => StructDefKind::Tuple,
236 ast::StructKind::Unit => StructDefKind::Unit,
237 };
238 let res = Struct { name, visibility, generic_params, fields, ast_id, kind };
239 Some(id(self.data().structs.alloc(res))) 232 Some(id(self.data().structs.alloc(res)))
240 } 233 }
241 234
@@ -397,19 +390,7 @@ impl<'a> Ctx<'a> {
397 ret_type 390 ret_type
398 }; 391 };
399 392
400 let abi = func.abi().map(|abi| { 393 let abi = func.abi().map(lower_abi);
401 // FIXME: Abi::abi() -> Option<SyntaxToken>?
402 match abi.syntax().last_token() {
403 Some(tok) if tok.kind() == SyntaxKind::STRING => {
404 // FIXME: Better way to unescape?
405 Interned::new_str(tok.text().trim_matches('"'))
406 }
407 _ => {
408 // `extern` default to be `extern "C"`.
409 Interned::new_str("C")
410 }
411 }
412 });
413 394
414 let ast_id = self.source_ast_id_map.ast_id(func); 395 let ast_id = self.source_ast_id_map.ast_id(func);
415 396
@@ -647,8 +628,10 @@ impl<'a> Ctx<'a> {
647 Some(id(self.data().macro_defs.alloc(res))) 628 Some(id(self.data().macro_defs.alloc(res)))
648 } 629 }
649 630
650 fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> Vec<ModItem> { 631 fn lower_extern_block(&mut self, block: &ast::ExternBlock) -> FileItemTreeId<ExternBlock> {
651 block.extern_item_list().map_or(Vec::new(), |list| { 632 let ast_id = self.source_ast_id_map.ast_id(block);
633 let abi = block.abi().map(lower_abi);
634 let children: Box<[_]> = block.extern_item_list().map_or(Box::new([]), |list| {
652 list.extern_items() 635 list.extern_items()
653 .filter_map(|item| { 636 .filter_map(|item| {
654 self.collect_inner_items(item.syntax()); 637 self.collect_inner_items(item.syntax());
@@ -673,13 +656,20 @@ impl<'a> Ctx<'a> {
673 self.data().type_aliases[foreign_ty.index].is_extern = true; 656 self.data().type_aliases[foreign_ty.index].is_extern = true;
674 foreign_ty.into() 657 foreign_ty.into()
675 } 658 }
676 ast::ExternItem::MacroCall(_) => return None, 659 ast::ExternItem::MacroCall(call) => {
660 // FIXME: we need some way of tracking that the macro call is in an
661 // extern block
662 self.lower_macro_call(&call)?.into()
663 }
677 }; 664 };
678 self.add_attrs(id.into(), attrs); 665 self.add_attrs(id.into(), attrs);
679 Some(id) 666 Some(id)
680 }) 667 })
681 .collect() 668 .collect()
682 }) 669 });
670
671 let res = ExternBlock { abi, ast_id, children };
672 id(self.data().extern_blocks.alloc(res))
683 } 673 }
684 674
685 /// Lowers generics defined on `node` and collects inner items defined within. 675 /// Lowers generics defined on `node` and collects inner items defined within.
@@ -879,3 +869,17 @@ fn is_intrinsic_fn_unsafe(name: &Name) -> bool {
879 ] 869 ]
880 .contains(&name) 870 .contains(&name)
881} 871}
872
873fn lower_abi(abi: ast::Abi) -> Interned<str> {
874 // FIXME: Abi::abi() -> Option<SyntaxToken>?
875 match abi.syntax().last_token() {
876 Some(tok) if tok.kind() == SyntaxKind::STRING => {
877 // FIXME: Better way to unescape?
878 Interned::new_str(tok.text().trim_matches('"'))
879 }
880 _ => {
881 // `extern` default to be `extern "C"`.
882 Interned::new_str("C")
883 }
884 }
885}
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
new file mode 100644
index 000000000..5ec02d1be
--- /dev/null
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -0,0 +1,525 @@
1//! `ItemTree` debug printer.
2
3use std::fmt::{self, Write};
4
5use crate::{attr::RawAttrs, visibility::RawVisibility};
6
7use super::*;
8
9pub(super) fn print_item_tree(tree: &ItemTree) -> String {
10 let mut p = Printer { tree, buf: String::new(), indent_level: 0, needs_indent: true };
11
12 if let Some(attrs) = tree.attrs.get(&AttrOwner::TopLevel) {
13 p.print_attrs(attrs, true);
14 }
15 p.blank();
16
17 for item in tree.top_level_items() {
18 p.print_mod_item(*item);
19 }
20
21 let mut s = p.buf.trim_end_matches('\n').to_string();
22 s.push('\n');
23 s
24}
25
26macro_rules! w {
27 ($dst:expr, $($arg:tt)*) => {
28 drop(write!($dst, $($arg)*))
29 };
30}
31
32macro_rules! wln {
33 ($dst:expr) => {
34 drop(writeln!($dst))
35 };
36 ($dst:expr, $($arg:tt)*) => {
37 drop(writeln!($dst, $($arg)*))
38 };
39}
40
41struct Printer<'a> {
42 tree: &'a ItemTree,
43 buf: String,
44 indent_level: usize,
45 needs_indent: bool,
46}
47
48impl<'a> Printer<'a> {
49 fn indented(&mut self, f: impl FnOnce(&mut Self)) {
50 self.indent_level += 1;
51 wln!(self);
52 f(self);
53 self.indent_level -= 1;
54 self.buf = self.buf.trim_end_matches('\n').to_string();
55 }
56
57 /// Ensures that a blank line is output before the next text.
58 fn blank(&mut self) {
59 let mut iter = self.buf.chars().rev().fuse();
60 match (iter.next(), iter.next()) {
61 (Some('\n'), Some('\n')) | (Some('\n'), None) | (None, None) => {}
62 (Some('\n'), Some(_)) => {
63 self.buf.push('\n');
64 }
65 (Some(_), _) => {
66 self.buf.push('\n');
67 self.buf.push('\n');
68 }
69 (None, Some(_)) => unreachable!(),
70 }
71 }
72
73 fn print_attrs(&mut self, attrs: &RawAttrs, inner: bool) {
74 let inner = if inner { "!" } else { "" };
75 for attr in &**attrs {
76 wln!(
77 self,
78 "#{}[{}{}] // {:?}",
79 inner,
80 attr.path,
81 attr.input.as_ref().map(|it| it.to_string()).unwrap_or_default(),
82 attr.id,
83 );
84 }
85 }
86
87 fn print_attrs_of(&mut self, of: impl Into<AttrOwner>) {
88 if let Some(attrs) = self.tree.attrs.get(&of.into()) {
89 self.print_attrs(attrs, false);
90 }
91 }
92
93 fn print_visibility(&mut self, vis: RawVisibilityId) {
94 match &self.tree[vis] {
95 RawVisibility::Module(path) => w!(self, "pub({}) ", path),
96 RawVisibility::Public => w!(self, "pub "),
97 };
98 }
99
100 fn print_fields(&mut self, fields: &Fields) {
101 match fields {
102 Fields::Record(fields) => {
103 w!(self, " {{");
104 self.indented(|this| {
105 for field in fields.clone() {
106 let Field { visibility, name, type_ref } = &this.tree[field];
107 this.print_attrs_of(field);
108 this.print_visibility(*visibility);
109 w!(this, "{}: ", name);
110 this.print_type_ref(type_ref);
111 wln!(this, ",");
112 }
113 });
114 w!(self, "}}");
115 }
116 Fields::Tuple(fields) => {
117 w!(self, "(");
118 self.indented(|this| {
119 for field in fields.clone() {
120 let Field { visibility, name, type_ref } = &this.tree[field];
121 this.print_attrs_of(field);
122 this.print_visibility(*visibility);
123 w!(this, "{}: ", name);
124 this.print_type_ref(type_ref);
125 wln!(this, ",");
126 }
127 });
128 w!(self, ")");
129 }
130 Fields::Unit => {}
131 }
132 }
133
134 fn print_mod_item(&mut self, item: ModItem) {
135 self.print_attrs_of(item);
136
137 match item {
138 ModItem::Import(it) => {
139 let Import { visibility, path, is_glob, alias, ast_id: _, index } = &self.tree[it];
140 self.print_visibility(*visibility);
141 w!(self, "use {}", path);
142 if *is_glob {
143 w!(self, "::*");
144 }
145 if let Some(alias) = alias {
146 w!(self, " as {}", alias);
147 }
148 wln!(self, "; // {}", index);
149 }
150 ModItem::ExternCrate(it) => {
151 let ExternCrate { name, alias, visibility, ast_id: _ } = &self.tree[it];
152 self.print_visibility(*visibility);
153 w!(self, "extern crate {}", name);
154 if let Some(alias) = alias {
155 w!(self, " as {}", alias);
156 }
157 wln!(self, ";");
158 }
159 ModItem::ExternBlock(it) => {
160 let ExternBlock { abi, ast_id: _, children } = &self.tree[it];
161 w!(self, "extern ");
162 if let Some(abi) = abi {
163 w!(self, "\"{}\" ", abi);
164 }
165 w!(self, "{{");
166 self.indented(|this| {
167 for child in &**children {
168 this.print_mod_item(*child);
169 }
170 });
171 wln!(self, "}}");
172 }
173 ModItem::Function(it) => {
174 let Function {
175 name,
176 visibility,
177 generic_params: _, // FIXME print these somehow
178 abi,
179 params,
180 ret_type,
181 ast_id: _,
182 flags,
183 } = &self.tree[it];
184 if flags.bits != 0 {
185 wln!(self, "// flags = 0x{:X}", flags.bits);
186 }
187 self.print_visibility(*visibility);
188 if let Some(abi) = abi {
189 w!(self, "extern \"{}\" ", abi);
190 }
191 w!(self, "fn {}(", name);
192 if !params.is_empty() {
193 self.indented(|this| {
194 for param in params.clone() {
195 this.print_attrs_of(param);
196 match &this.tree[param] {
197 Param::Normal(ty) => {
198 w!(this, "_: ");
199 this.print_type_ref(ty);
200 wln!(this, ",");
201 }
202 Param::Varargs => {
203 wln!(this, "...");
204 }
205 };
206 }
207 });
208 }
209 w!(self, ") -> ");
210 self.print_type_ref(ret_type);
211 wln!(self, ";");
212 }
213 ModItem::Struct(it) => {
214 let Struct { visibility, name, fields, generic_params: _, ast_id: _ } =
215 &self.tree[it];
216 self.print_visibility(*visibility);
217 w!(self, "struct {}", name);
218 self.print_fields(fields);
219 if matches!(fields, Fields::Record(_)) {
220 wln!(self);
221 } else {
222 wln!(self, ";");
223 }
224 }
225 ModItem::Union(it) => {
226 let Union { name, visibility, fields, generic_params: _, ast_id: _ } =
227 &self.tree[it];
228 self.print_visibility(*visibility);
229 w!(self, "union {}", name);
230 self.print_fields(fields);
231 if matches!(fields, Fields::Record(_)) {
232 wln!(self);
233 } else {
234 wln!(self, ";");
235 }
236 }
237 ModItem::Enum(it) => {
238 let Enum { name, visibility, variants, generic_params: _, ast_id: _ } =
239 &self.tree[it];
240 self.print_visibility(*visibility);
241 w!(self, "enum {} {{", name);
242 self.indented(|this| {
243 for variant in variants.clone() {
244 let Variant { name, fields } = &this.tree[variant];
245 this.print_attrs_of(variant);
246 w!(this, "{}", name);
247 this.print_fields(fields);
248 wln!(this, ",");
249 }
250 });
251 wln!(self, "}}");
252 }
253 ModItem::Const(it) => {
254 let Const { name, visibility, type_ref, ast_id: _ } = &self.tree[it];
255 self.print_visibility(*visibility);
256 w!(self, "const ");
257 match name {
258 Some(name) => w!(self, "{}", name),
259 None => w!(self, "_"),
260 }
261 w!(self, ": ");
262 self.print_type_ref(type_ref);
263 wln!(self, " = _;");
264 }
265 ModItem::Static(it) => {
266 let Static { name, visibility, mutable, is_extern, type_ref, ast_id: _ } =
267 &self.tree[it];
268 self.print_visibility(*visibility);
269 w!(self, "static ");
270 if *mutable {
271 w!(self, "mut ");
272 }
273 w!(self, "{}: ", name);
274 self.print_type_ref(type_ref);
275 w!(self, " = _;");
276 if *is_extern {
277 w!(self, " // extern");
278 }
279 wln!(self);
280 }
281 ModItem::Trait(it) => {
282 let Trait {
283 name,
284 visibility,
285 is_auto,
286 is_unsafe,
287 bounds,
288 items,
289 generic_params: _,
290 ast_id: _,
291 } = &self.tree[it];
292 self.print_visibility(*visibility);
293 if *is_unsafe {
294 w!(self, "unsafe ");
295 }
296 if *is_auto {
297 w!(self, "auto ");
298 }
299 w!(self, "trait {}", name);
300 if !bounds.is_empty() {
301 w!(self, ": ");
302 self.print_type_bounds(bounds);
303 }
304 w!(self, " {{");
305 self.indented(|this| {
306 for item in &**items {
307 this.print_mod_item((*item).into());
308 }
309 });
310 wln!(self, "}}");
311 }
312 ModItem::Impl(it) => {
313 let Impl {
314 target_trait,
315 self_ty,
316 is_negative,
317 items,
318 generic_params: _,
319 ast_id: _,
320 } = &self.tree[it];
321 w!(self, "impl ");
322 if *is_negative {
323 w!(self, "!");
324 }
325 if let Some(tr) = target_trait {
326 self.print_path(&tr.path);
327 w!(self, " for ");
328 }
329 self.print_type_ref(self_ty);
330 w!(self, " {{");
331 self.indented(|this| {
332 for item in &**items {
333 this.print_mod_item((*item).into());
334 }
335 });
336 wln!(self, "}}");
337 }
338 ModItem::TypeAlias(it) => {
339 let TypeAlias {
340 name,
341 visibility,
342 bounds,
343 type_ref,
344 is_extern,
345 generic_params: _,
346 ast_id: _,
347 } = &self.tree[it];
348 self.print_visibility(*visibility);
349 w!(self, "type {}", name);
350 if !bounds.is_empty() {
351 w!(self, ": ");
352 self.print_type_bounds(bounds);
353 }
354 if let Some(ty) = type_ref {
355 w!(self, " = ");
356 self.print_type_ref(ty);
357 }
358 w!(self, ";");
359 if *is_extern {
360 w!(self, " // extern");
361 }
362 wln!(self);
363 }
364 ModItem::Mod(it) => {
365 let Mod { name, visibility, kind, ast_id: _ } = &self.tree[it];
366 self.print_visibility(*visibility);
367 w!(self, "mod {}", name);
368 match kind {
369 ModKind::Inline { items } => {
370 w!(self, " {{");
371 self.indented(|this| {
372 for item in &**items {
373 this.print_mod_item((*item).into());
374 }
375 });
376 wln!(self, "}}");
377 }
378 ModKind::Outline {} => {
379 wln!(self, ";");
380 }
381 }
382 }
383 ModItem::MacroCall(it) => {
384 let MacroCall { path, ast_id: _, fragment: _ } = &self.tree[it];
385 wln!(self, "{}!(...);", path);
386 }
387 ModItem::MacroRules(it) => {
388 let MacroRules { name, ast_id: _ } = &self.tree[it];
389 wln!(self, "macro_rules! {} {{ ... }}", name);
390 }
391 ModItem::MacroDef(it) => {
392 let MacroDef { name, visibility, ast_id: _ } = &self.tree[it];
393 self.print_visibility(*visibility);
394 wln!(self, "macro {} {{ ... }}", name);
395 }
396 }
397
398 self.blank();
399 }
400
401 fn print_type_ref(&mut self, type_ref: &TypeRef) {
402 // FIXME: deduplicate with `HirDisplay` impl
403 match type_ref {
404 TypeRef::Never => w!(self, "!"),
405 TypeRef::Placeholder => w!(self, "_"),
406 TypeRef::Tuple(fields) => {
407 w!(self, "(");
408 for (i, field) in fields.iter().enumerate() {
409 if i != 0 {
410 w!(self, ", ");
411 }
412 self.print_type_ref(field);
413 }
414 w!(self, ")");
415 }
416 TypeRef::Path(path) => self.print_path(path),
417 TypeRef::RawPtr(pointee, mtbl) => {
418 let mtbl = match mtbl {
419 Mutability::Shared => "*const",
420 Mutability::Mut => "*mut",
421 };
422 w!(self, "{} ", mtbl);
423 self.print_type_ref(pointee);
424 }
425 TypeRef::Reference(pointee, lt, mtbl) => {
426 let mtbl = match mtbl {
427 Mutability::Shared => "",
428 Mutability::Mut => "mut ",
429 };
430 w!(self, "&");
431 if let Some(lt) = lt {
432 w!(self, "{} ", lt.name);
433 }
434 w!(self, "{}", mtbl);
435 self.print_type_ref(pointee);
436 }
437 TypeRef::Array(elem, len) => {
438 w!(self, "[");
439 self.print_type_ref(elem);
440 w!(self, "; {}]", len);
441 }
442 TypeRef::Slice(elem) => {
443 w!(self, "[");
444 self.print_type_ref(elem);
445 w!(self, "]");
446 }
447 TypeRef::Fn(args_and_ret, varargs) => {
448 let (ret, args) =
449 args_and_ret.split_last().expect("TypeRef::Fn is missing return type");
450 w!(self, "fn(");
451 for (i, arg) in args.iter().enumerate() {
452 if i != 0 {
453 w!(self, ", ");
454 }
455 self.print_type_ref(arg);
456 }
457 if *varargs {
458 if !args.is_empty() {
459 w!(self, ", ");
460 }
461 w!(self, "...");
462 }
463 w!(self, ") -> ");
464 self.print_type_ref(ret);
465 }
466 TypeRef::Macro(_ast_id) => {
467 w!(self, "<macro>");
468 }
469 TypeRef::Error => drop(write!(self, "{{unknown}}")),
470 TypeRef::ImplTrait(bounds) => {
471 w!(self, "impl ");
472 self.print_type_bounds(bounds);
473 }
474 TypeRef::DynTrait(bounds) => {
475 w!(self, "dyn ");
476 self.print_type_bounds(bounds);
477 }
478 }
479 }
480
481 fn print_type_bounds(&mut self, bounds: &[TypeBound]) {
482 for (i, bound) in bounds.iter().enumerate() {
483 if i != 0 {
484 w!(self, " + ");
485 }
486
487 match bound {
488 TypeBound::Path(path) => self.print_path(path),
489 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
490 TypeBound::Error => w!(self, "{{unknown}}"),
491 }
492 }
493 }
494
495 fn print_path(&mut self, path: &Path) {
496 if path.type_anchor().is_none()
497 && path.segments().iter().all(|seg| seg.args_and_bindings.is_none())
498 {
499 w!(self, "{}", path.mod_path());
500 } else {
501 // too complicated, just use `Debug`
502 w!(self, "{:?}", path);
503 }
504 }
505}
506
507impl<'a> Write for Printer<'a> {
508 fn write_str(&mut self, s: &str) -> fmt::Result {
509 for line in s.split_inclusive('\n') {
510 if self.needs_indent {
511 match self.buf.chars().last() {
512 Some('\n') | None => {}
513 _ => self.buf.push('\n'),
514 }
515 self.buf.push_str(&" ".repeat(self.indent_level));
516 self.needs_indent = false;
517 }
518
519 self.buf.push_str(line);
520 self.needs_indent = line.ends_with('\n');
521 }
522
523 Ok(())
524 }
525}
diff --git a/crates/hir_def/src/item_tree/tests.rs b/crates/hir_def/src/item_tree/tests.rs
new file mode 100644
index 000000000..100ae9b97
--- /dev/null
+++ b/crates/hir_def/src/item_tree/tests.rs
@@ -0,0 +1,244 @@
1use base_db::fixture::WithFixture;
2use expect_test::{expect, Expect};
3
4use crate::{db::DefDatabase, test_db::TestDB};
5
6fn check(ra_fixture: &str, expect: Expect) {
7 let (db, file_id) = TestDB::with_single_file(ra_fixture);
8 let item_tree = db.file_item_tree(file_id.into());
9 let pretty = item_tree.pretty_print();
10 expect.assert_eq(&pretty);
11}
12
13#[test]
14fn imports() {
15 check(
16 r#"
17//! file comment
18#![no_std]
19//! another file comment
20
21extern crate self as renamed;
22pub(super) extern crate bli;
23
24pub use crate::path::{nested, items as renamed, Trait as _};
25use globs::*;
26
27/// docs on import
28use crate::{A, B};
29 "#,
30 expect![[r##"
31 #![doc = " file comment"] // AttrId { is_doc_comment: true, ast_index: 0 }
32 #![no_std] // AttrId { is_doc_comment: false, ast_index: 0 }
33 #![doc = " another file comment"] // AttrId { is_doc_comment: true, ast_index: 1 }
34
35 pub(self) extern crate self as renamed;
36
37 pub(super) extern crate bli;
38
39 pub use crate::path::nested; // 0
40
41 pub use crate::path::items as renamed; // 1
42
43 pub use crate::path::Trait as _; // 2
44
45 pub(self) use globs::*; // 0
46
47 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 }
48 pub(self) use crate::A; // 0
49
50 #[doc = " docs on import"] // AttrId { is_doc_comment: true, ast_index: 0 }
51 pub(self) use crate::B; // 1
52 "##]],
53 );
54}
55
56#[test]
57fn extern_blocks() {
58 check(
59 r#"
60#[on_extern_block]
61extern "C" {
62 #[on_extern_type]
63 type ExType;
64
65 #[on_extern_static]
66 static EX_STATIC: u8;
67
68 #[on_extern_fn]
69 fn ex_fn();
70}
71 "#,
72 expect![[r##"
73 #[on_extern_block] // AttrId { is_doc_comment: false, ast_index: 0 }
74 extern "C" {
75 #[on_extern_type] // AttrId { is_doc_comment: false, ast_index: 0 }
76 pub(self) type ExType; // extern
77
78 #[on_extern_static] // AttrId { is_doc_comment: false, ast_index: 0 }
79 pub(self) static EX_STATIC: u8 = _; // extern
80
81 #[on_extern_fn] // AttrId { is_doc_comment: false, ast_index: 0 }
82 // flags = 0x60
83 pub(self) fn ex_fn() -> ();
84 }
85 "##]],
86 );
87}
88
89#[test]
90fn adts() {
91 check(
92 r#"
93struct Unit;
94
95#[derive(Debug)]
96struct Struct {
97 /// fld docs
98 fld: (),
99}
100
101struct Tuple(#[attr] u8);
102
103union Ize {
104 a: (),
105 b: (),
106}
107
108enum E {
109 /// comment on Unit
110 Unit,
111 /// comment on Tuple
112 Tuple(u8),
113 Struct {
114 /// comment on a: u8
115 a: u8,
116 }
117}
118 "#,
119 expect![[r##"
120 pub(self) struct Unit;
121
122 #[derive(Debug)] // AttrId { is_doc_comment: false, ast_index: 0 }
123 pub(self) struct Struct {
124 #[doc = " fld docs"] // AttrId { is_doc_comment: true, ast_index: 0 }
125 pub(self) fld: (),
126 }
127
128 pub(self) struct Tuple(
129 #[attr] // AttrId { is_doc_comment: false, ast_index: 0 }
130 pub(self) 0: u8,
131 );
132
133 pub(self) union Ize {
134 pub(self) a: (),
135 pub(self) b: (),
136 }
137
138 pub(self) enum E {
139 #[doc = " comment on Unit"] // AttrId { is_doc_comment: true, ast_index: 0 }
140 Unit,
141 #[doc = " comment on Tuple"] // AttrId { is_doc_comment: true, ast_index: 0 }
142 Tuple(
143 pub(self) 0: u8,
144 ),
145 Struct {
146 #[doc = " comment on a: u8"] // AttrId { is_doc_comment: true, ast_index: 0 }
147 pub(self) a: u8,
148 },
149 }
150 "##]],
151 );
152}
153
154#[test]
155fn misc() {
156 check(
157 r#"
158pub static mut ST: () = ();
159
160const _: Anon = ();
161
162#[attr]
163fn f(#[attr] arg: u8, _: ()) {
164 #![inner_attr_in_fn]
165}
166
167trait Tr: SuperTrait + 'lifetime {
168 type Assoc: AssocBound = Default;
169 fn method(&self);
170}
171 "#,
172 expect![[r##"
173 pub static mut ST: () = _;
174
175 pub(self) const _: Anon = _;
176
177 #[attr] // AttrId { is_doc_comment: false, ast_index: 0 }
178 #[inner_attr_in_fn] // AttrId { is_doc_comment: false, ast_index: 1 }
179 // flags = 0x2
180 pub(self) fn f(
181 #[attr] // AttrId { is_doc_comment: false, ast_index: 0 }
182 _: u8,
183 _: (),
184 ) -> ();
185
186 pub(self) trait Tr: SuperTrait + 'lifetime {
187 pub(self) type Assoc: AssocBound = Default;
188
189 // flags = 0x1
190 pub(self) fn method(
191 _: &Self,
192 ) -> ();
193 }
194 "##]],
195 );
196}
197
198#[test]
199fn modules() {
200 check(
201 r#"
202/// outer
203mod inline {
204 //! inner
205
206 use super::*;
207
208 fn fn_in_module() {}
209}
210 "#,
211 expect![[r##"
212 #[doc = " outer"] // AttrId { is_doc_comment: true, ast_index: 0 }
213 #[doc = " inner"] // AttrId { is_doc_comment: true, ast_index: 1 }
214 pub(self) mod inline {
215 pub(self) use super::*; // 0
216
217 // flags = 0x2
218 pub(self) fn fn_in_module() -> ();
219 }
220 "##]],
221 );
222}
223
224#[test]
225fn macros() {
226 check(
227 r#"
228macro_rules! m {
229 () => {};
230}
231
232pub macro m2() {}
233
234m!();
235 "#,
236 expect![[r#"
237 macro_rules! m { ... }
238
239 pub macro m2 { ... }
240
241 m!(...);
242 "#]],
243 );
244}
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 3896be25d..014ea4de4 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -16,19 +16,20 @@ use hir_expand::{
16 FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 16 FragmentKind, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use itertools::Itertools;
19use rustc_hash::{FxHashMap, FxHashSet}; 20use rustc_hash::{FxHashMap, FxHashSet};
20use syntax::ast; 21use syntax::ast;
21 22
22use crate::{ 23use crate::{
23 attr::{AttrId, Attrs}, 24 attr::{Attr, AttrId, AttrInput, Attrs},
24 builtin_attr, 25 builtin_attr,
25 db::DefDatabase, 26 db::DefDatabase,
26 derive_macro_as_call_id, 27 derive_macro_as_call_id,
27 intern::Interned, 28 intern::Interned,
28 item_scope::{ImportType, PerNsGlobImports}, 29 item_scope::{ImportType, PerNsGlobImports},
29 item_tree::{ 30 item_tree::{
30 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem, 31 self, Fields, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod,
31 ModKind, StructDefKind, 32 ModItem, ModKind,
32 }, 33 },
33 macro_call_as_call_id, 34 macro_call_as_call_id,
34 nameres::{ 35 nameres::{
@@ -94,14 +95,16 @@ pub(super) fn collect_defs(
94 unresolved_imports: Vec::new(), 95 unresolved_imports: Vec::new(),
95 resolved_imports: Vec::new(), 96 resolved_imports: Vec::new(),
96 97
97 unexpanded_macros: Vec::new(), 98 unresolved_macros: Vec::new(),
98 mod_dirs: FxHashMap::default(), 99 mod_dirs: FxHashMap::default(),
99 cfg_options, 100 cfg_options,
100 proc_macros, 101 proc_macros,
101 exports_proc_macros: false, 102 exports_proc_macros: false,
102 from_glob_import: Default::default(), 103 from_glob_import: Default::default(),
103 ignore_attrs_on: FxHashSet::default(), 104 skip_attrs: Default::default(),
104 derive_helpers_in_scope: FxHashMap::default(), 105 derive_helpers_in_scope: Default::default(),
106 registered_attrs: Default::default(),
107 registered_tools: Default::default(),
105 }; 108 };
106 match block { 109 match block {
107 Some(block) => { 110 Some(block) => {
@@ -237,7 +240,7 @@ struct DefCollector<'a> {
237 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>, 240 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility)>>,
238 unresolved_imports: Vec<ImportDirective>, 241 unresolved_imports: Vec<ImportDirective>,
239 resolved_imports: Vec<ImportDirective>, 242 resolved_imports: Vec<ImportDirective>,
240 unexpanded_macros: Vec<MacroDirective>, 243 unresolved_macros: Vec<MacroDirective>,
241 mod_dirs: FxHashMap<LocalModuleId, ModDir>, 244 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
242 cfg_options: &'a CfgOptions, 245 cfg_options: &'a CfgOptions,
243 /// List of procedural macros defined by this crate. This is read from the dynamic library 246 /// List of procedural macros defined by this crate. This is read from the dynamic library
@@ -247,10 +250,20 @@ struct DefCollector<'a> {
247 proc_macros: Vec<(Name, ProcMacroExpander)>, 250 proc_macros: Vec<(Name, ProcMacroExpander)>,
248 exports_proc_macros: bool, 251 exports_proc_macros: bool,
249 from_glob_import: PerNsGlobImports, 252 from_glob_import: PerNsGlobImports,
250 ignore_attrs_on: FxHashSet<InFile<ModItem>>, 253 /// If we fail to resolve an attribute on a `ModItem`, we fall back to ignoring the attribute.
254 /// This map is used to skip all attributes up to and including the one that failed to resolve,
255 /// in order to not expand them twice.
256 ///
257 /// This also stores the attributes to skip when we resolve derive helpers and non-macro
258 /// non-builtin attributes in general.
259 skip_attrs: FxHashMap<InFile<ModItem>, AttrId>,
251 /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper 260 /// Tracks which custom derives are in scope for an item, to allow resolution of derive helper
252 /// attributes. 261 /// attributes.
253 derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>, 262 derive_helpers_in_scope: FxHashMap<AstId<ast::Item>, Vec<Name>>,
263 /// Custom attributes registered with `#![register_attr]`.
264 registered_attrs: Vec<String>,
265 /// Custom tool modules registered with `#![register_tool]`.
266 registered_tools: Vec<String>,
254} 267}
255 268
256impl DefCollector<'_> { 269impl DefCollector<'_> {
@@ -259,11 +272,39 @@ impl DefCollector<'_> {
259 let item_tree = self.db.file_item_tree(file_id.into()); 272 let item_tree = self.db.file_item_tree(file_id.into());
260 let module_id = self.def_map.root; 273 let module_id = self.def_map.root;
261 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id }; 274 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
262 if item_tree 275
263 .top_level_attrs(self.db, self.def_map.krate) 276 let attrs = item_tree.top_level_attrs(self.db, self.def_map.krate);
264 .cfg() 277 if attrs.cfg().map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) {
265 .map_or(true, |cfg| self.cfg_options.check(&cfg) != Some(false)) 278 // Process other crate-level attributes.
266 { 279 for attr in &*attrs {
280 let attr_name = match attr.path.as_ident() {
281 Some(name) => name,
282 None => continue,
283 };
284
285 let registered_name = if *attr_name == hir_expand::name![register_attr]
286 || *attr_name == hir_expand::name![register_tool]
287 {
288 match &attr.input {
289 Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees {
290 [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(),
291 _ => continue,
292 },
293 _ => continue,
294 }
295 } else {
296 continue;
297 };
298
299 if *attr_name == hir_expand::name![register_attr] {
300 self.registered_attrs.push(registered_name.to_string());
301 cov_mark::hit!(register_attr);
302 } else {
303 self.registered_tools.push(registered_name.to_string());
304 cov_mark::hit!(register_tool);
305 }
306 }
307
267 ModCollector { 308 ModCollector {
268 def_collector: &mut *self, 309 def_collector: &mut *self,
269 macro_depth: 0, 310 macro_depth: 0,
@@ -319,7 +360,7 @@ impl DefCollector<'_> {
319 } 360 }
320 } 361 }
321 362
322 if self.reseed_with_unresolved_attributes() == ReachedFixedPoint::Yes { 363 if self.reseed_with_unresolved_attribute() == ReachedFixedPoint::Yes {
323 break; 364 break;
324 } 365 }
325 } 366 }
@@ -362,27 +403,23 @@ impl DefCollector<'_> {
362 } 403 }
363 404
364 /// When the fixed-point loop reaches a stable state, we might still have some unresolved 405 /// When the fixed-point loop reaches a stable state, we might still have some unresolved
365 /// attributes (or unexpanded attribute proc macros) left over. This takes them, and feeds the 406 /// attributes (or unexpanded attribute proc macros) left over. This takes one of them, and
366 /// item they're applied to back into name resolution. 407 /// feeds the item it's applied to back into name resolution.
367 /// 408 ///
368 /// This effectively ignores the fact that the macro is there and just treats the items as 409 /// This effectively ignores the fact that the macro is there and just treats the items as
369 /// normal code. 410 /// normal code.
370 /// 411 ///
371 /// This improves UX when proc macros are turned off or don't work, and replicates the behavior 412 /// This improves UX when proc macros are turned off or don't work, and replicates the behavior
372 /// before we supported proc. attribute macros. 413 /// before we supported proc. attribute macros.
373 fn reseed_with_unresolved_attributes(&mut self) -> ReachedFixedPoint { 414 fn reseed_with_unresolved_attribute(&mut self) -> ReachedFixedPoint {
374 cov_mark::hit!(unresolved_attribute_fallback); 415 cov_mark::hit!(unresolved_attribute_fallback);
375 416
376 let mut added_items = false; 417 let mut unresolved_macros = std::mem::replace(&mut self.unresolved_macros, Vec::new());
377 let unexpanded_macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 418 let pos = unresolved_macros.iter().position(|directive| {
378 for directive in &unexpanded_macros { 419 if let MacroDirectiveKind::Attr { ast_id, mod_item, attr } = &directive.kind {
379 if let MacroDirectiveKind::Attr { ast_id, mod_item, .. } = &directive.kind { 420 self.skip_attrs.insert(ast_id.ast_id.with_value(*mod_item), *attr);
380 // Make sure to only add such items once.
381 if !self.ignore_attrs_on.insert(ast_id.ast_id.with_value(*mod_item)) {
382 continue;
383 }
384 421
385 let file_id = self.def_map[directive.module_id].definition_source(self.db).file_id; 422 let file_id = ast_id.ast_id.file_id;
386 let item_tree = self.db.file_item_tree(file_id); 423 let item_tree = self.db.file_item_tree(file_id);
387 let mod_dir = self.mod_dirs[&directive.module_id].clone(); 424 let mod_dir = self.mod_dirs[&directive.module_id].clone();
388 ModCollector { 425 ModCollector {
@@ -394,14 +431,20 @@ impl DefCollector<'_> {
394 mod_dir, 431 mod_dir,
395 } 432 }
396 .collect(&[*mod_item]); 433 .collect(&[*mod_item]);
397 added_items = true; 434 true
435 } else {
436 false
398 } 437 }
438 });
439
440 if let Some(pos) = pos {
441 unresolved_macros.remove(pos);
399 } 442 }
400 443
401 // The collection above might add new unresolved macros (eg. derives), so merge the lists. 444 // The collection above might add new unresolved macros (eg. derives), so merge the lists.
402 self.unexpanded_macros.extend(unexpanded_macros); 445 self.unresolved_macros.extend(unresolved_macros);
403 446
404 if added_items { 447 if pos.is_some() {
405 // Continue name resolution with the new data. 448 // Continue name resolution with the new data.
406 ReachedFixedPoint::No 449 ReachedFixedPoint::No
407 } else { 450 } else {
@@ -873,7 +916,7 @@ impl DefCollector<'_> {
873 } 916 }
874 917
875 fn resolve_macros(&mut self) -> ReachedFixedPoint { 918 fn resolve_macros(&mut self) -> ReachedFixedPoint {
876 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 919 let mut macros = std::mem::replace(&mut self.unresolved_macros, Vec::new());
877 let mut resolved = Vec::new(); 920 let mut resolved = Vec::new();
878 let mut res = ReachedFixedPoint::Yes; 921 let mut res = ReachedFixedPoint::Yes;
879 macros.retain(|directive| { 922 macros.retain(|directive| {
@@ -922,14 +965,43 @@ impl DefCollector<'_> {
922 Err(UnresolvedMacro { .. }) => (), 965 Err(UnresolvedMacro { .. }) => (),
923 } 966 }
924 } 967 }
925 MacroDirectiveKind::Attr { .. } => { 968 MacroDirectiveKind::Attr { ast_id, mod_item, attr } => {
926 // not yet :) 969 if let Some(ident) = ast_id.path.as_ident() {
970 if let Some(helpers) = self.derive_helpers_in_scope.get(&ast_id.ast_id) {
971 if helpers.contains(ident) {
972 cov_mark::hit!(resolved_derive_helper);
973
974 // Resolved to derive helper. Collect the item's attributes again,
975 // starting after the derive helper.
976 let file_id = ast_id.ast_id.file_id;
977 let item_tree = self.db.file_item_tree(file_id);
978 let mod_dir = self.mod_dirs[&directive.module_id].clone();
979 self.skip_attrs.insert(InFile::new(file_id, *mod_item), *attr);
980 ModCollector {
981 def_collector: &mut *self,
982 macro_depth: directive.depth,
983 module_id: directive.module_id,
984 file_id,
985 item_tree: &item_tree,
986 mod_dir,
987 }
988 .collect(&[*mod_item]);
989
990 // Remove the original directive since we resolved it.
991 return false;
992 }
993 }
994 }
995
996 // Not resolved to a derive helper, so try to resolve as a macro.
997 // FIXME: not yet :)
927 } 998 }
928 } 999 }
929 1000
930 true 1001 true
931 }); 1002 });
932 self.unexpanded_macros = macros; 1003 // Attribute resolution can add unresolved macro invocations, so concatenate the lists.
1004 self.unresolved_macros.extend(macros);
933 1005
934 for (module_id, macro_call_id, depth) in resolved { 1006 for (module_id, macro_call_id, depth) in resolved {
935 self.collect_macro_expansion(module_id, macro_call_id, depth); 1007 self.collect_macro_expansion(module_id, macro_call_id, depth);
@@ -1000,7 +1072,7 @@ impl DefCollector<'_> {
1000 fn finish(mut self) -> DefMap { 1072 fn finish(mut self) -> DefMap {
1001 // Emit diagnostics for all remaining unexpanded macros. 1073 // Emit diagnostics for all remaining unexpanded macros.
1002 1074
1003 for directive in &self.unexpanded_macros { 1075 for directive in &self.unresolved_macros {
1004 match &directive.kind { 1076 match &directive.kind {
1005 MacroDirectiveKind::FnLike { ast_id, fragment } => match macro_call_as_call_id( 1077 MacroDirectiveKind::FnLike { ast_id, fragment } => match macro_call_as_call_id(
1006 ast_id, 1078 ast_id,
@@ -1102,7 +1174,7 @@ impl ModCollector<'_, '_> {
1102 1174
1103 // Prelude module is always considered to be `#[macro_use]`. 1175 // Prelude module is always considered to be `#[macro_use]`.
1104 if let Some(prelude_module) = self.def_collector.def_map.prelude { 1176 if let Some(prelude_module) = self.def_collector.def_map.prelude {
1105 if prelude_module.krate != self.def_collector.def_map.krate { 1177 if prelude_module.krate != krate {
1106 cov_mark::hit!(prelude_is_macro_use); 1178 cov_mark::hit!(prelude_is_macro_use);
1107 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate); 1179 self.def_collector.import_all_macros_exported(self.module_id, prelude_module.krate);
1108 } 1180 }
@@ -1172,6 +1244,7 @@ impl ModCollector<'_, '_> {
1172 status: PartialResolvedImport::Unresolved, 1244 status: PartialResolvedImport::Unresolved,
1173 }) 1245 })
1174 } 1246 }
1247 ModItem::ExternBlock(block) => self.collect(&self.item_tree[block].children),
1175 ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]), 1248 ModItem::MacroCall(mac) => self.collect_macro_call(&self.item_tree[mac]),
1176 ModItem::MacroRules(id) => self.collect_macro_rules(id), 1249 ModItem::MacroRules(id) => self.collect_macro_rules(id),
1177 ModItem::MacroDef(id) => self.collect_macro_def(id), 1250 ModItem::MacroDef(id) => self.collect_macro_def(id),
@@ -1203,28 +1276,18 @@ impl ModCollector<'_, '_> {
1203 ModItem::Struct(id) => { 1276 ModItem::Struct(id) => {
1204 let it = &self.item_tree[id]; 1277 let it = &self.item_tree[id];
1205 1278
1206 // FIXME: check attrs to see if this is an attribute macro invocation;
1207 // in which case we don't add the invocation, just a single attribute
1208 // macro invocation
1209 self.collect_derives(&attrs, it.ast_id.upcast());
1210
1211 def = Some(DefData { 1279 def = Some(DefData {
1212 id: StructLoc { container: module, id: ItemTreeId::new(self.file_id, id) } 1280 id: StructLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
1213 .intern(self.def_collector.db) 1281 .intern(self.def_collector.db)
1214 .into(), 1282 .into(),
1215 name: &it.name, 1283 name: &it.name,
1216 visibility: &self.item_tree[it.visibility], 1284 visibility: &self.item_tree[it.visibility],
1217 has_constructor: it.kind != StructDefKind::Record, 1285 has_constructor: !matches!(it.fields, Fields::Record(_)),
1218 }); 1286 });
1219 } 1287 }
1220 ModItem::Union(id) => { 1288 ModItem::Union(id) => {
1221 let it = &self.item_tree[id]; 1289 let it = &self.item_tree[id];
1222 1290
1223 // FIXME: check attrs to see if this is an attribute macro invocation;
1224 // in which case we don't add the invocation, just a single attribute
1225 // macro invocation
1226 self.collect_derives(&attrs, it.ast_id.upcast());
1227
1228 def = Some(DefData { 1291 def = Some(DefData {
1229 id: UnionLoc { container: module, id: ItemTreeId::new(self.file_id, id) } 1292 id: UnionLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
1230 .intern(self.def_collector.db) 1293 .intern(self.def_collector.db)
@@ -1237,11 +1300,6 @@ impl ModCollector<'_, '_> {
1237 ModItem::Enum(id) => { 1300 ModItem::Enum(id) => {
1238 let it = &self.item_tree[id]; 1301 let it = &self.item_tree[id];
1239 1302
1240 // FIXME: check attrs to see if this is an attribute macro invocation;
1241 // in which case we don't add the invocation, just a single attribute
1242 // macro invocation
1243 self.collect_derives(&attrs, it.ast_id.upcast());
1244
1245 def = Some(DefData { 1303 def = Some(DefData {
1246 id: EnumLoc { container: module, id: ItemTreeId::new(self.file_id, id) } 1304 id: EnumLoc { container: module, id: ItemTreeId::new(self.file_id, id) }
1247 .intern(self.def_collector.db) 1305 .intern(self.def_collector.db)
@@ -1453,76 +1511,116 @@ impl ModCollector<'_, '_> {
1453 /// 1511 ///
1454 /// Returns `Err` when some attributes could not be resolved to builtins and have been 1512 /// Returns `Err` when some attributes could not be resolved to builtins and have been
1455 /// registered as unresolved. 1513 /// registered as unresolved.
1514 ///
1515 /// If `ignore_up_to` is `Some`, attributes precending and including that attribute will be
1516 /// assumed to be resolved already.
1456 fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> { 1517 fn resolve_attributes(&mut self, attrs: &Attrs, mod_item: ModItem) -> Result<(), ()> {
1457 fn is_builtin_attr(path: &ModPath) -> bool { 1518 let mut ignore_up_to =
1458 if path.kind == PathKind::Plain { 1519 self.def_collector.skip_attrs.get(&InFile::new(self.file_id, mod_item)).copied();
1459 if let Some(tool_module) = path.segments().first() { 1520 let iter = attrs
1460 let tool_module = tool_module.to_string(); 1521 .iter()
1461 if builtin_attr::TOOL_MODULES.iter().any(|m| tool_module == *m) { 1522 .dedup_by(|a, b| {
1462 return true; 1523 // FIXME: this should not be required, all attributes on an item should have a
1463 } 1524 // unique ID!
1464 } 1525 // Still, this occurs because `#[cfg_attr]` can "expand" to multiple attributes:
1465 1526 // #[cfg_attr(not(off), unresolved, unresolved)]
1466 if let Some(name) = path.as_ident() { 1527 // struct S;
1467 let name = name.to_string(); 1528 // We should come up with a different way to ID attributes.
1468 if builtin_attr::INERT_ATTRIBUTES 1529 a.id == b.id
1469 .iter() 1530 })
1470 .chain(builtin_attr::EXTRA_ATTRIBUTES) 1531 .skip_while(|attr| match ignore_up_to {
1471 .any(|attr| name == *attr) 1532 Some(id) if attr.id == id => {
1472 { 1533 ignore_up_to = None;
1473 return true; 1534 true
1474 }
1475 } 1535 }
1476 } 1536 Some(_) => true,
1477 1537 None => false,
1478 false 1538 });
1479 } 1539
1480 1540 for attr in iter {
1481 // We failed to resolve an attribute on this item earlier, and are falling back to treating 1541 if attr.path.as_ident() == Some(&hir_expand::name![derive]) {
1482 // the item as-is. 1542 self.collect_derive(attr, mod_item);
1483 if self.def_collector.ignore_attrs_on.contains(&InFile::new(self.file_id, mod_item)) { 1543 } else if self.is_builtin_or_registered_attr(&attr.path) {
1484 return Ok(()); 1544 continue;
1485 } 1545 } else {
1486 1546 log::debug!("non-builtin attribute {}", attr.path);
1487 match attrs.iter().find(|attr| !is_builtin_attr(&attr.path)) {
1488 Some(non_builtin_attr) => {
1489 log::debug!("non-builtin attribute {}", non_builtin_attr.path);
1490 1547
1491 let ast_id = AstIdWithPath::new( 1548 let ast_id = AstIdWithPath::new(
1492 self.file_id, 1549 self.file_id,
1493 mod_item.ast_id(self.item_tree), 1550 mod_item.ast_id(self.item_tree),
1494 non_builtin_attr.path.as_ref().clone(), 1551 attr.path.as_ref().clone(),
1495 ); 1552 );
1496 self.def_collector.unexpanded_macros.push(MacroDirective { 1553 self.def_collector.unresolved_macros.push(MacroDirective {
1497 module_id: self.module_id, 1554 module_id: self.module_id,
1498 depth: self.macro_depth + 1, 1555 depth: self.macro_depth + 1,
1499 kind: MacroDirectiveKind::Attr { ast_id, attr: non_builtin_attr.id, mod_item }, 1556 kind: MacroDirectiveKind::Attr { ast_id, attr: attr.id, mod_item },
1500 }); 1557 });
1501 1558
1502 Err(()) 1559 return Err(());
1503 } 1560 }
1504 None => Ok(()),
1505 } 1561 }
1562
1563 Ok(())
1506 } 1564 }
1507 1565
1508 fn collect_derives(&mut self, attrs: &Attrs, ast_id: FileAstId<ast::Item>) { 1566 fn is_builtin_or_registered_attr(&self, path: &ModPath) -> bool {
1509 for derive in attrs.by_key("derive").attrs() { 1567 if path.kind == PathKind::Plain {
1510 match derive.parse_derive() { 1568 if let Some(tool_module) = path.segments().first() {
1511 Some(derive_macros) => { 1569 let tool_module = tool_module.to_string();
1512 for path in derive_macros { 1570 if builtin_attr::TOOL_MODULES
1513 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path); 1571 .iter()
1514 self.def_collector.unexpanded_macros.push(MacroDirective { 1572 .copied()
1515 module_id: self.module_id, 1573 .chain(self.def_collector.registered_tools.iter().map(|s| &**s))
1516 depth: self.macro_depth + 1, 1574 .any(|m| tool_module == *m)
1517 kind: MacroDirectiveKind::Derive { ast_id, derive_attr: derive.id }, 1575 {
1518 }); 1576 return true;
1519 }
1520 } 1577 }
1521 None => { 1578 }
1522 // FIXME: diagnose 1579
1523 log::debug!("malformed derive: {:?}", derive); 1580 if let Some(name) = path.as_ident() {
1581 let name = name.to_string();
1582 if builtin_attr::INERT_ATTRIBUTES
1583 .iter()
1584 .chain(builtin_attr::EXTRA_ATTRIBUTES)
1585 .copied()
1586 .chain(self.def_collector.registered_attrs.iter().map(|s| &**s))
1587 .any(|attr| name == *attr)
1588 {
1589 return true;
1590 }
1591 }
1592 }
1593
1594 false
1595 }
1596
1597 fn collect_derive(&mut self, attr: &Attr, mod_item: ModItem) {
1598 let ast_id: FileAstId<ast::Item> = match mod_item {
1599 ModItem::Struct(it) => self.item_tree[it].ast_id.upcast(),
1600 ModItem::Union(it) => self.item_tree[it].ast_id.upcast(),
1601 ModItem::Enum(it) => self.item_tree[it].ast_id.upcast(),
1602 _ => {
1603 // Cannot use derive on this item.
1604 // FIXME: diagnose
1605 return;
1606 }
1607 };
1608
1609 match attr.parse_derive() {
1610 Some(derive_macros) => {
1611 for path in derive_macros {
1612 let ast_id = AstIdWithPath::new(self.file_id, ast_id, path);
1613 self.def_collector.unresolved_macros.push(MacroDirective {
1614 module_id: self.module_id,
1615 depth: self.macro_depth + 1,
1616 kind: MacroDirectiveKind::Derive { ast_id, derive_attr: attr.id },
1617 });
1524 } 1618 }
1525 } 1619 }
1620 None => {
1621 // FIXME: diagnose
1622 log::debug!("malformed derive: {:?}", attr);
1623 }
1526 } 1624 }
1527 } 1625 }
1528 1626
@@ -1686,7 +1784,7 @@ impl ModCollector<'_, '_> {
1686 ast_id.path.kind = PathKind::Super(0); 1784 ast_id.path.kind = PathKind::Super(0);
1687 } 1785 }
1688 1786
1689 self.def_collector.unexpanded_macros.push(MacroDirective { 1787 self.def_collector.unresolved_macros.push(MacroDirective {
1690 module_id: self.module_id, 1788 module_id: self.module_id,
1691 depth: self.macro_depth + 1, 1789 depth: self.macro_depth + 1,
1692 kind: MacroDirectiveKind::FnLike { ast_id, fragment: mac.fragment }, 1790 kind: MacroDirectiveKind::FnLike { ast_id, fragment: mac.fragment },
@@ -1731,14 +1829,16 @@ mod tests {
1731 glob_imports: FxHashMap::default(), 1829 glob_imports: FxHashMap::default(),
1732 unresolved_imports: Vec::new(), 1830 unresolved_imports: Vec::new(),
1733 resolved_imports: Vec::new(), 1831 resolved_imports: Vec::new(),
1734 unexpanded_macros: Vec::new(), 1832 unresolved_macros: Vec::new(),
1735 mod_dirs: FxHashMap::default(), 1833 mod_dirs: FxHashMap::default(),
1736 cfg_options: &CfgOptions::default(), 1834 cfg_options: &CfgOptions::default(),
1737 proc_macros: Default::default(), 1835 proc_macros: Default::default(),
1738 exports_proc_macros: false, 1836 exports_proc_macros: false,
1739 from_glob_import: Default::default(), 1837 from_glob_import: Default::default(),
1740 ignore_attrs_on: FxHashSet::default(), 1838 skip_attrs: Default::default(),
1741 derive_helpers_in_scope: FxHashMap::default(), 1839 derive_helpers_in_scope: Default::default(),
1840 registered_attrs: Default::default(),
1841 registered_tools: Default::default(),
1742 }; 1842 };
1743 collector.seed_with_top_level(); 1843 collector.seed_with_top_level();
1744 collector.collect(); 1844 collector.collect();
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index 543975e07..75147d973 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -237,3 +237,20 @@ fn good_out_dir_diagnostic() {
237 "#, 237 "#,
238 ); 238 );
239} 239}
240
241#[test]
242fn register_attr_and_tool() {
243 cov_mark::check!(register_attr);
244 cov_mark::check!(register_tool);
245 check_no_diagnostics(
246 r#"
247#![register_tool(tool)]
248#![register_attr(attr)]
249
250#[tool::path]
251#[attr]
252struct S;
253 "#,
254 );
255 // NB: we don't currently emit diagnostics here
256}
diff --git a/crates/hir_def/src/nameres/tests/macros.rs b/crates/hir_def/src/nameres/tests/macros.rs
index 6eb5f97be..3065efd65 100644
--- a/crates/hir_def/src/nameres/tests/macros.rs
+++ b/crates/hir_def/src/nameres/tests/macros.rs
@@ -736,6 +736,80 @@ fn unresolved_attributes_fall_back_track_per_file_moditems() {
736} 736}
737 737
738#[test] 738#[test]
739fn unresolved_attrs_extern_block_hang() {
740 // Regression test for https://github.com/rust-analyzer/rust-analyzer/issues/8905
741 check(
742 r#"
743#[unresolved]
744extern "C" {
745 #[unresolved]
746 fn f();
747}
748 "#,
749 expect![[r#"
750 crate
751 f: v
752 "#]],
753 );
754}
755
756#[test]
757fn macros_in_extern_block() {
758 check(
759 r#"
760macro_rules! m {
761 () => { static S: u8; };
762}
763
764extern {
765 m!();
766}
767 "#,
768 expect![[r#"
769 crate
770 S: v
771 "#]],
772 );
773}
774
775#[test]
776fn resolves_derive_helper() {
777 cov_mark::check!(resolved_derive_helper);
778 check(
779 r#"
780//- /main.rs crate:main deps:proc
781#[derive(proc::Derive)]
782#[helper]
783#[unresolved]
784struct S;
785
786//- /proc.rs crate:proc
787#[proc_macro_derive(Derive, attributes(helper))]
788fn derive() {}
789 "#,
790 expect![[r#"
791 crate
792 S: t v
793 "#]],
794 );
795}
796
797#[test]
798fn unresolved_attr_with_cfg_attr_hang() {
799 // Another regression test for https://github.com/rust-analyzer/rust-analyzer/issues/8905
800 check(
801 r#"
802#[cfg_attr(not(off), unresolved, unresolved)]
803struct S;
804 "#,
805 expect![[r#"
806 crate
807 S: t v
808 "#]],
809 );
810}
811
812#[test]
739fn macro_expansion_overflow() { 813fn macro_expansion_overflow() {
740 cov_mark::check!(macro_expansion_overflow); 814 cov_mark::check!(macro_expansion_overflow);
741 check( 815 check(
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index a43441b1c..9b8873fd2 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -46,6 +46,15 @@ pub enum ImportAlias {
46 Alias(Name), 46 Alias(Name),
47} 47}
48 48
49impl Display for ImportAlias {
50 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51 match self {
52 ImportAlias::Underscore => f.write_str("_"),
53 ImportAlias::Alias(name) => f.write_str(&name.to_string()),
54 }
55 }
56}
57
49impl ModPath { 58impl ModPath {
50 pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { 59 pub fn from_src(db: &dyn DefDatabase, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
51 let ctx = LowerCtx::with_hygiene(db, hygiene); 60 let ctx = LowerCtx::with_hygiene(db, hygiene);
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index 5a5dc9afd..ef67ea2e9 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -164,6 +164,8 @@ pub mod known {
164 doc, 164 doc,
165 cfg, 165 cfg,
166 cfg_attr, 166 cfg_attr,
167 register_attr,
168 register_tool,
167 // Components of known path (value or mod name) 169 // Components of known path (value or mod name)
168 std, 170 std,
169 core, 171 core,
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index e25ef866d..893e727c2 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -6,15 +6,15 @@ use chalk_ir::{
6 cast::{Cast, CastTo, Caster}, 6 cast::{Cast, CastTo, Caster},
7 fold::Fold, 7 fold::Fold,
8 interner::HasInterner, 8 interner::HasInterner,
9 AdtId, BoundVar, DebruijnIndex, Safety, Scalar, 9 AdtId, BoundVar, DebruijnIndex, Scalar,
10}; 10};
11use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId}; 11use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId};
12use smallvec::SmallVec; 12use smallvec::SmallVec;
13 13
14use crate::{ 14use crate::{
15 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, 15 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
16 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution, 16 CallableSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt,
17 TraitRef, Ty, TyDefId, TyExt, TyKind, ValueTyDefId, 17 TyKind, ValueTyDefId,
18}; 18};
19 19
20/// This is a builder for `Ty` or anything that needs a `Substitution`. 20/// This is a builder for `Ty` or anything that needs a `Substitution`.
@@ -77,15 +77,7 @@ impl TyBuilder<()> {
77 } 77 }
78 78
79 pub fn fn_ptr(sig: CallableSig) -> Ty { 79 pub fn fn_ptr(sig: CallableSig) -> Ty {
80 TyKind::Function(FnPointer { 80 TyKind::Function(sig.to_fn_ptr()).intern(&Interner)
81 num_binders: 0,
82 sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs },
83 substitution: FnSubst(Substitution::from_iter(
84 &Interner,
85 sig.params_and_return.iter().cloned(),
86 )),
87 })
88 .intern(&Interner)
89 } 81 }
90 82
91 pub fn builtin(builtin: BuiltinType) -> Ty { 83 pub fn builtin(builtin: BuiltinType) -> Ty {
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 8f054d06b..b108fd559 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -344,20 +344,20 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
344 } 344 }
345 345
346 fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> { 346 fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
347 self 347 &self.db
348 } 348 }
349} 349}
350 350
351impl<'a> chalk_ir::UnificationDatabase<Interner> for ChalkContext<'a> { 351impl<'a> chalk_ir::UnificationDatabase<Interner> for &'a dyn HirDatabase {
352 fn fn_def_variance( 352 fn fn_def_variance(
353 &self, 353 &self,
354 fn_def_id: chalk_ir::FnDefId<Interner>, 354 fn_def_id: chalk_ir::FnDefId<Interner>,
355 ) -> chalk_ir::Variances<Interner> { 355 ) -> chalk_ir::Variances<Interner> {
356 self.db.fn_def_variance(self.krate, fn_def_id) 356 HirDatabase::fn_def_variance(*self, fn_def_id)
357 } 357 }
358 358
359 fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> { 359 fn adt_variance(&self, adt_id: chalk_ir::AdtId<Interner>) -> chalk_ir::Variances<Interner> {
360 self.db.adt_variance(self.krate, adt_id) 360 HirDatabase::adt_variance(*self, adt_id)
361 } 361 }
362} 362}
363 363
@@ -651,11 +651,7 @@ pub(crate) fn fn_def_datum_query(
651 Arc::new(datum) 651 Arc::new(datum)
652} 652}
653 653
654pub(crate) fn fn_def_variance_query( 654pub(crate) fn fn_def_variance_query(db: &dyn HirDatabase, fn_def_id: FnDefId) -> Variances {
655 db: &dyn HirDatabase,
656 _krate: CrateId,
657 fn_def_id: FnDefId,
658) -> Variances {
659 let callable_def: CallableDefId = from_chalk(db, fn_def_id); 655 let callable_def: CallableDefId = from_chalk(db, fn_def_id);
660 let generic_params = generics(db.upcast(), callable_def.into()); 656 let generic_params = generics(db.upcast(), callable_def.into());
661 Variances::from_iter( 657 Variances::from_iter(
@@ -666,7 +662,6 @@ pub(crate) fn fn_def_variance_query(
666 662
667pub(crate) fn adt_variance_query( 663pub(crate) fn adt_variance_query(
668 db: &dyn HirDatabase, 664 db: &dyn HirDatabase,
669 _krate: CrateId,
670 chalk_ir::AdtId(adt_id): AdtId, 665 chalk_ir::AdtId(adt_id): AdtId,
671) -> Variances { 666) -> Variances {
672 let generic_params = generics(db.upcast(), adt_id.into()); 667 let generic_params = generics(db.upcast(), adt_id.into());
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 5232a7d80..df340a6ca 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -18,6 +18,7 @@ pub trait TyExt {
18 fn is_unit(&self) -> bool; 18 fn is_unit(&self) -> bool;
19 fn is_never(&self) -> bool; 19 fn is_never(&self) -> bool;
20 fn is_unknown(&self) -> bool; 20 fn is_unknown(&self) -> bool;
21 fn is_ty_var(&self) -> bool;
21 22
22 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>; 23 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
23 fn as_builtin(&self) -> Option<BuiltinType>; 24 fn as_builtin(&self) -> Option<BuiltinType>;
@@ -55,6 +56,10 @@ impl TyExt for Ty {
55 matches!(self.kind(&Interner), TyKind::Error) 56 matches!(self.kind(&Interner), TyKind::Error)
56 } 57 }
57 58
59 fn is_ty_var(&self) -> bool {
60 matches!(self.kind(&Interner), TyKind::InferenceVar(_, _))
61 }
62
58 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> { 63 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
59 match self.kind(&Interner) { 64 match self.kind(&Interner) {
60 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)), 65 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 9da0a02e3..be5b9110e 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -117,10 +117,10 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
117 fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc<chalk_db::FnDefDatum>; 117 fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc<chalk_db::FnDefDatum>;
118 118
119 #[salsa::invoke(chalk_db::fn_def_variance_query)] 119 #[salsa::invoke(chalk_db::fn_def_variance_query)]
120 fn fn_def_variance(&self, krate: CrateId, fn_def_id: FnDefId) -> chalk_db::Variances; 120 fn fn_def_variance(&self, fn_def_id: FnDefId) -> chalk_db::Variances;
121 121
122 #[salsa::invoke(chalk_db::adt_variance_query)] 122 #[salsa::invoke(chalk_db::adt_variance_query)]
123 fn adt_variance(&self, krate: CrateId, adt_id: chalk_db::AdtId) -> chalk_db::Variances; 123 fn adt_variance(&self, adt_id: chalk_db::AdtId) -> chalk_db::Variances;
124 124
125 #[salsa::invoke(chalk_db::associated_ty_value_query)] 125 #[salsa::invoke(chalk_db::associated_ty_value_query)]
126 fn associated_ty_value( 126 fn associated_ty_value(
@@ -134,14 +134,14 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
134 fn trait_solve( 134 fn trait_solve(
135 &self, 135 &self,
136 krate: CrateId, 136 krate: CrateId,
137 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, 137 goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
138 ) -> Option<crate::Solution>; 138 ) -> Option<crate::Solution>;
139 139
140 #[salsa::invoke(crate::traits::trait_solve_query)] 140 #[salsa::invoke(crate::traits::trait_solve_query)]
141 fn trait_solve_query( 141 fn trait_solve_query(
142 &self, 142 &self,
143 krate: CrateId, 143 krate: CrateId,
144 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, 144 goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
145 ) -> Option<crate::Solution>; 145 ) -> Option<crate::Solution>;
146 146
147 #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)] 147 #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)]
@@ -168,7 +168,7 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
168fn trait_solve_wait( 168fn trait_solve_wait(
169 db: &dyn HirDatabase, 169 db: &dyn HirDatabase,
170 krate: CrateId, 170 krate: CrateId,
171 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, 171 goal: crate::Canonical<crate::InEnvironment<crate::Goal>>,
172) -> Option<crate::Solution> { 172) -> Option<crate::Solution> {
173 let _p = profile::span("trait_solve::wait"); 173 let _p = profile::span("trait_solve::wait");
174 db.trait_solve_query(krate, goal) 174 db.trait_solve_query(krate, goal)
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 0ee851a74..f1cebbdb9 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -13,8 +13,6 @@
13//! to certain types. To record this, we use the union-find implementation from 13//! to certain types. To record this, we use the union-find implementation from
14//! the `ena` crate, which is extracted from rustc. 14//! the `ena` crate, which is extracted from rustc.
15 15
16use std::borrow::Cow;
17use std::mem;
18use std::ops::Index; 16use std::ops::Index;
19use std::sync::Arc; 17use std::sync::Arc;
20 18
@@ -27,8 +25,8 @@ use hir_def::{
27 path::{path, Path}, 25 path::{path, Path},
28 resolver::{HasResolver, Resolver, TypeNs}, 26 resolver::{HasResolver, Resolver, TypeNs},
29 type_ref::TypeRef, 27 type_ref::TypeRef,
30 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, Lookup, TraitId, 28 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, FunctionId, HasModule, Lookup,
31 TypeAliasId, VariantId, 29 TraitId, TypeAliasId, VariantId,
32}; 30};
33use hir_expand::{diagnostics::DiagnosticSink, name::name}; 31use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use la_arena::ArenaMap; 32use la_arena::ArenaMap;
@@ -36,13 +34,11 @@ use rustc_hash::FxHashMap;
36use stdx::impl_from; 34use stdx::impl_from;
37use syntax::SmolStr; 35use syntax::SmolStr;
38 36
39use super::{ 37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
40 DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty,
41};
42use crate::{ 38use crate::{
43 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, 39 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
44 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner, 40 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, TyBuilder,
45 TyBuilder, TyExt, TyKind, 41 TyExt, TyKind,
46}; 42};
47 43
48// This lint has a false positive here. See the link below for details. 44// This lint has a false positive here. See the link below for details.
@@ -106,6 +102,14 @@ impl Default for BindingMode {
106 } 102 }
107} 103}
108 104
105#[derive(Debug)]
106pub(crate) struct InferOk {
107 goals: Vec<InEnvironment<Goal>>,
108}
109#[derive(Debug)]
110pub(crate) struct TypeError;
111pub(crate) type InferResult = Result<InferOk, TypeError>;
112
109/// A mismatch between an expected and an inferred type. 113/// A mismatch between an expected and an inferred type.
110#[derive(Clone, PartialEq, Eq, Debug, Hash)] 114#[derive(Clone, PartialEq, Eq, Debug, Hash)]
111pub struct TypeMismatch { 115pub struct TypeMismatch {
@@ -217,10 +221,8 @@ struct InferenceContext<'a> {
217 owner: DefWithBodyId, 221 owner: DefWithBodyId,
218 body: Arc<Body>, 222 body: Arc<Body>,
219 resolver: Resolver, 223 resolver: Resolver,
220 table: unify::InferenceTable, 224 table: unify::InferenceTable<'a>,
221 trait_env: Arc<TraitEnvironment>, 225 trait_env: Arc<TraitEnvironment>,
222 obligations: Vec<DomainGoal>,
223 last_obligations_check: Option<u32>,
224 result: InferenceResult, 226 result: InferenceResult,
225 /// The return type of the function being inferred, or the closure if we're 227 /// The return type of the function being inferred, or the closure if we're
226 /// currently within one. 228 /// currently within one.
@@ -252,15 +254,15 @@ fn find_breakable<'c>(
252 254
253impl<'a> InferenceContext<'a> { 255impl<'a> InferenceContext<'a> {
254 fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Self { 256 fn new(db: &'a dyn HirDatabase, owner: DefWithBodyId, resolver: Resolver) -> Self {
257 let krate = owner.module(db.upcast()).krate();
258 let trait_env = owner
259 .as_generic_def_id()
260 .map_or_else(|| Arc::new(TraitEnvironment::empty(krate)), |d| db.trait_environment(d));
255 InferenceContext { 261 InferenceContext {
256 result: InferenceResult::default(), 262 result: InferenceResult::default(),
257 table: unify::InferenceTable::new(), 263 table: unify::InferenceTable::new(db, trait_env.clone()),
258 obligations: Vec::default(), 264 trait_env,
259 last_obligations_check: None,
260 return_ty: TyKind::Error.intern(&Interner), // set in collect_fn_signature 265 return_ty: TyKind::Error.intern(&Interner), // set in collect_fn_signature
261 trait_env: owner
262 .as_generic_def_id()
263 .map_or_else(Default::default, |d| db.trait_environment(d)),
264 db, 266 db,
265 owner, 267 owner,
266 body: db.body(owner), 268 body: db.body(owner),
@@ -271,19 +273,25 @@ impl<'a> InferenceContext<'a> {
271 } 273 }
272 274
273 fn err_ty(&self) -> Ty { 275 fn err_ty(&self) -> Ty {
274 TyKind::Error.intern(&Interner) 276 self.result.standard_types.unknown.clone()
275 } 277 }
276 278
277 fn resolve_all(mut self) -> InferenceResult { 279 fn resolve_all(mut self) -> InferenceResult {
278 // FIXME resolve obligations as well (use Guidance if necessary) 280 // FIXME resolve obligations as well (use Guidance if necessary)
281 self.table.resolve_obligations_as_possible();
282
283 // make sure diverging type variables are marked as such
284 self.table.propagate_diverging_flag();
279 let mut result = std::mem::take(&mut self.result); 285 let mut result = std::mem::take(&mut self.result);
280 for ty in result.type_of_expr.values_mut() { 286 for ty in result.type_of_expr.values_mut() {
281 let resolved = self.table.resolve_ty_completely(ty.clone()); 287 *ty = self.table.resolve_ty_completely(ty.clone());
282 *ty = resolved;
283 } 288 }
284 for ty in result.type_of_pat.values_mut() { 289 for ty in result.type_of_pat.values_mut() {
285 let resolved = self.table.resolve_ty_completely(ty.clone()); 290 *ty = self.table.resolve_ty_completely(ty.clone());
286 *ty = resolved; 291 }
292 for mismatch in result.type_mismatches.values_mut() {
293 mismatch.expected = self.table.resolve_ty_completely(mismatch.expected.clone());
294 mismatch.actual = self.table.resolve_ty_completely(mismatch.actual.clone());
287 } 295 }
288 result 296 result
289 } 297 }
@@ -337,6 +345,14 @@ impl<'a> InferenceContext<'a> {
337 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 345 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
338 match ty.kind(&Interner) { 346 match ty.kind(&Interner) {
339 TyKind::Error => self.table.new_type_var(), 347 TyKind::Error => self.table.new_type_var(),
348 TyKind::InferenceVar(..) => {
349 let ty_resolved = self.resolve_ty_shallow(&ty);
350 if ty_resolved.is_unknown() {
351 self.table.new_type_var()
352 } else {
353 ty
354 }
355 }
340 _ => ty, 356 _ => ty,
341 } 357 }
342 } 358 }
@@ -346,66 +362,19 @@ impl<'a> InferenceContext<'a> {
346 } 362 }
347 363
348 fn resolve_obligations_as_possible(&mut self) { 364 fn resolve_obligations_as_possible(&mut self) {
349 if self.last_obligations_check == Some(self.table.revision) { 365 self.table.resolve_obligations_as_possible();
350 // no change
351 return;
352 }
353 let _span = profile::span("resolve_obligations_as_possible");
354
355 self.last_obligations_check = Some(self.table.revision);
356 let obligations = mem::replace(&mut self.obligations, Vec::new());
357 for obligation in obligations {
358 let in_env = InEnvironment::new(&self.trait_env.env, obligation.clone());
359 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env);
360 let solution =
361 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
362
363 match solution {
364 Some(Solution::Unique(canonical_subst)) => {
365 canonicalized.apply_solution(
366 self,
367 Canonical {
368 binders: canonical_subst.binders,
369 // FIXME: handle constraints
370 value: canonical_subst.value.subst,
371 },
372 );
373 }
374 Some(Solution::Ambig(Guidance::Definite(substs))) => {
375 canonicalized.apply_solution(self, substs);
376 self.obligations.push(obligation);
377 }
378 Some(_) => {
379 // FIXME use this when trying to resolve everything at the end
380 self.obligations.push(obligation);
381 }
382 None => {
383 // FIXME obligation cannot be fulfilled => diagnostic
384 }
385 };
386 }
387 } 366 }
388 367
389 fn push_obligation(&mut self, o: DomainGoal) { 368 fn push_obligation(&mut self, o: DomainGoal) {
390 self.obligations.push(o); 369 self.table.register_obligation(o.cast(&Interner));
391 self.last_obligations_check = None;
392 } 370 }
393 371
394 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 372 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
395 self.table.unify(ty1, ty2) 373 self.table.unify(ty1, ty2)
396 } 374 }
397 375
398 /// Resolves the type as far as currently possible, replacing type variables 376 fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
399 /// by their known types. All types returned by the infer_* functions should
400 /// be resolved as far as possible, i.e. contain no type variables with
401 /// known type.
402 fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
403 self.resolve_obligations_as_possible(); 377 self.resolve_obligations_as_possible();
404
405 self.table.resolve_ty_as_possible(ty)
406 }
407
408 fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
409 self.table.resolve_ty_shallow(ty) 378 self.table.resolve_ty_shallow(ty)
410 } 379 }
411 380
@@ -439,7 +408,7 @@ impl<'a> InferenceContext<'a> {
439 }; 408 };
440 self.push_obligation(trait_ref.cast(&Interner)); 409 self.push_obligation(trait_ref.cast(&Interner));
441 self.push_obligation(alias_eq.cast(&Interner)); 410 self.push_obligation(alias_eq.cast(&Interner));
442 self.resolve_ty_as_possible(ty) 411 ty
443 } 412 }
444 None => self.err_ty(), 413 None => self.err_ty(),
445 } 414 }
@@ -452,25 +421,7 @@ impl<'a> InferenceContext<'a> {
452 /// call). `make_ty` handles this already, but e.g. for field types we need 421 /// call). `make_ty` handles this already, but e.g. for field types we need
453 /// to do it as well. 422 /// to do it as well.
454 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 423 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
455 let ty = self.resolve_ty_as_possible(ty); 424 self.table.normalize_associated_types_in(ty)
456 fold_tys(
457 ty,
458 |ty, _| match ty.kind(&Interner) {
459 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
460 self.normalize_projection_ty(proj_ty.clone())
461 }
462 _ => ty,
463 },
464 DebruijnIndex::INNERMOST,
465 )
466 }
467
468 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
469 let var = self.table.new_type_var();
470 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
471 let obligation = alias_eq.cast(&Interner);
472 self.push_obligation(obligation);
473 var
474 } 425 }
475 426
476 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) { 427 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) {
@@ -720,17 +671,23 @@ impl<'a> InferenceContext<'a> {
720/// When inferring an expression, we propagate downward whatever type hint we 671/// When inferring an expression, we propagate downward whatever type hint we
721/// are able in the form of an `Expectation`. 672/// are able in the form of an `Expectation`.
722#[derive(Clone, PartialEq, Eq, Debug)] 673#[derive(Clone, PartialEq, Eq, Debug)]
723struct Expectation { 674enum Expectation {
724 ty: Ty, 675 None,
725 /// See the `rvalue_hint` method. 676 HasType(Ty),
726 rvalue_hint: bool, 677 // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
678 RValueLikeUnsized(Ty),
727} 679}
728 680
729impl Expectation { 681impl Expectation {
730 /// The expectation that the type of the expression needs to equal the given 682 /// The expectation that the type of the expression needs to equal the given
731 /// type. 683 /// type.
732 fn has_type(ty: Ty) -> Self { 684 fn has_type(ty: Ty) -> Self {
733 Expectation { ty, rvalue_hint: false } 685 if ty.is_unknown() {
686 // FIXME: get rid of this?
687 Expectation::None
688 } else {
689 Expectation::HasType(ty)
690 }
734 } 691 }
735 692
736 /// The following explanation is copied straight from rustc: 693 /// The following explanation is copied straight from rustc:
@@ -754,24 +711,41 @@ impl Expectation {
754 /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 711 /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169
755 /// for examples of where this comes up,. 712 /// for examples of where this comes up,.
756 fn rvalue_hint(ty: Ty) -> Self { 713 fn rvalue_hint(ty: Ty) -> Self {
757 Expectation { ty, rvalue_hint: true } 714 match ty.strip_references().kind(&Interner) {
715 TyKind::Slice(_) | TyKind::Str | TyKind::Dyn(_) => Expectation::RValueLikeUnsized(ty),
716 _ => Expectation::has_type(ty),
717 }
758 } 718 }
759 719
760 /// This expresses no expectation on the type. 720 /// This expresses no expectation on the type.
761 fn none() -> Self { 721 fn none() -> Self {
762 Expectation { 722 Expectation::None
763 // FIXME 723 }
764 ty: TyKind::Error.intern(&Interner), 724
765 rvalue_hint: false, 725 fn resolve(&self, table: &mut unify::InferenceTable) -> Expectation {
726 match self {
727 Expectation::None => Expectation::None,
728 Expectation::HasType(t) => Expectation::HasType(table.resolve_ty_shallow(t)),
729 Expectation::RValueLikeUnsized(t) => {
730 Expectation::RValueLikeUnsized(table.resolve_ty_shallow(t))
731 }
766 } 732 }
767 } 733 }
768 734
769 fn coercion_target(&self) -> Ty { 735 fn to_option(&self, table: &mut unify::InferenceTable) -> Option<Ty> {
770 if self.rvalue_hint { 736 match self.resolve(table) {
771 // FIXME 737 Expectation::None => None,
772 TyKind::Error.intern(&Interner) 738 Expectation::HasType(t) |
773 } else { 739 // Expectation::Castable(t) |
774 self.ty.clone() 740 Expectation::RValueLikeUnsized(t) => Some(t),
741 }
742 }
743
744 fn only_has_type(&self, table: &mut unify::InferenceTable) -> Option<Ty> {
745 match self {
746 Expectation::HasType(t) => Some(table.resolve_ty_shallow(t)),
747 // Expectation::Castable(_) |
748 Expectation::RValueLikeUnsized(_) | Expectation::None => None,
775 } 749 }
776 } 750 }
777} 751}
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 1f463a425..765a02b1c 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -2,156 +2,414 @@
2//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions 2//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions
3//! like going from `&Vec<T>` to `&[T]`. 3//! like going from `&Vec<T>` to `&[T]`.
4//! 4//!
5//! See: https://doc.rust-lang.org/nomicon/coercions.html 5//! See https://doc.rust-lang.org/nomicon/coercions.html and
6//! librustc_typeck/check/coercion.rs.
6 7
7use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 8use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
8use hir_def::lang_item::LangItemTarget; 9use hir_def::{expr::ExprId, lang_item::LangItemTarget};
9 10
10use crate::{autoderef, Canonical, Interner, Solution, Ty, TyBuilder, TyExt, TyKind}; 11use crate::{
12 autoderef, infer::TypeMismatch, static_lifetime, Canonical, DomainGoal, FnPointer, FnSig,
13 Interner, Solution, Substitution, Ty, TyBuilder, TyExt, TyKind,
14};
11 15
12use super::{InEnvironment, InferenceContext}; 16use super::{InEnvironment, InferOk, InferResult, InferenceContext, TypeError};
13 17
14impl<'a> InferenceContext<'a> { 18impl<'a> InferenceContext<'a> {
15 /// Unify two types, but may coerce the first one to the second one 19 /// Unify two types, but may coerce the first one to the second one
16 /// using "implicit coercion rules" if needed. 20 /// using "implicit coercion rules" if needed.
17 pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { 21 pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
18 let from_ty = self.resolve_ty_shallow(from_ty).into_owned(); 22 let from_ty = self.resolve_ty_shallow(from_ty);
19 let to_ty = self.resolve_ty_shallow(to_ty); 23 let to_ty = self.resolve_ty_shallow(to_ty);
20 self.coerce_inner(from_ty, &to_ty) 24 match self.coerce_inner(from_ty, &to_ty) {
25 Ok(result) => {
26 self.table.register_infer_ok(result);
27 true
28 }
29 Err(_) => {
30 // FIXME deal with error
31 false
32 }
33 }
21 } 34 }
22 35
23 /// Merge two types from different branches, with possible coercion. 36 /// Merge two types from different branches, with possible coercion.
24 /// 37 ///
25 /// Mostly this means trying to coerce one to the other, but 38 /// Mostly this means trying to coerce one to the other, but
26 /// - if we have two function types for different functions, we need to 39 /// - if we have two function types for different functions or closures, we need to
27 /// coerce both to function pointers; 40 /// coerce both to function pointers;
28 /// - if we were concerned with lifetime subtyping, we'd need to look for a 41 /// - if we were concerned with lifetime subtyping, we'd need to look for a
29 /// least upper bound. 42 /// least upper bound.
30 pub(super) fn coerce_merge_branch(&mut self, ty1: &Ty, ty2: &Ty) -> Ty { 43 pub(super) fn coerce_merge_branch(&mut self, id: Option<ExprId>, ty1: &Ty, ty2: &Ty) -> Ty {
31 if self.coerce(ty1, ty2) { 44 let ty1 = self.resolve_ty_shallow(ty1);
32 ty2.clone() 45 let ty2 = self.resolve_ty_shallow(ty2);
33 } else if self.coerce(ty2, ty1) { 46 // Special case: two function types. Try to coerce both to
47 // pointers to have a chance at getting a match. See
48 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
49 let sig = match (ty1.kind(&Interner), ty2.kind(&Interner)) {
50 (TyKind::FnDef(..), TyKind::FnDef(..))
51 | (TyKind::Closure(..), TyKind::FnDef(..))
52 | (TyKind::FnDef(..), TyKind::Closure(..))
53 | (TyKind::Closure(..), TyKind::Closure(..)) => {
54 // FIXME: we're ignoring safety here. To be more correct, if we have one FnDef and one Closure,
55 // we should be coercing the closure to a fn pointer of the safety of the FnDef
56 cov_mark::hit!(coerce_fn_reification);
57 let sig = ty1.callable_sig(self.db).expect("FnDef without callable sig");
58 Some(sig)
59 }
60 _ => None,
61 };
62 if let Some(sig) = sig {
63 let target_ty = TyKind::Function(sig.to_fn_ptr()).intern(&Interner);
64 let result1 = self.coerce_inner(ty1.clone(), &target_ty);
65 let result2 = self.coerce_inner(ty2.clone(), &target_ty);
66 if let (Ok(result1), Ok(result2)) = (result1, result2) {
67 self.table.register_infer_ok(result1);
68 self.table.register_infer_ok(result2);
69 return target_ty;
70 }
71 }
72
73 // It might not seem like it, but order is important here: ty1 is our
74 // "previous" type, ty2 is the "new" one being added. If the previous
75 // type is a type variable and the new one is `!`, trying it the other
76 // way around first would mean we make the type variable `!`, instead of
77 // just marking it as possibly diverging.
78 if self.coerce(&ty2, &ty1) {
34 ty1.clone() 79 ty1.clone()
80 } else if self.coerce(&ty1, &ty2) {
81 ty2.clone()
35 } else { 82 } else {
36 if let (TyKind::FnDef(..), TyKind::FnDef(..)) = 83 if let Some(id) = id {
37 (ty1.kind(&Interner), ty2.kind(&Interner)) 84 self.result
38 { 85 .type_mismatches
39 cov_mark::hit!(coerce_fn_reification); 86 .insert(id.into(), TypeMismatch { expected: ty1.clone(), actual: ty2.clone() });
40 // Special case: two function types. Try to coerce both to
41 // pointers to have a chance at getting a match. See
42 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
43 let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig");
44 let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig");
45 let ptr_ty1 = TyBuilder::fn_ptr(sig1);
46 let ptr_ty2 = TyBuilder::fn_ptr(sig2);
47 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2)
48 } else {
49 cov_mark::hit!(coerce_merge_fail_fallback);
50 ty1.clone()
51 } 87 }
88 cov_mark::hit!(coerce_merge_fail_fallback);
89 ty1.clone()
52 } 90 }
53 } 91 }
54 92
55 fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { 93 fn coerce_inner(&mut self, from_ty: Ty, to_ty: &Ty) -> InferResult {
56 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { 94 if from_ty.is_never() {
57 // Never type will make type variable to fallback to Never Type instead of Unknown. 95 // Subtle: If we are coercing from `!` to `?T`, where `?T` is an unbound
58 (TyKind::Never, TyKind::InferenceVar(tv, TyVariableKind::General)) => { 96 // type variable, we want `?T` to fallback to `!` if not
59 self.table.type_variable_table.set_diverging(*tv, true); 97 // otherwise constrained. An example where this arises:
60 return true; 98 //
99 // let _: Option<?T> = Some({ return; });
100 //
101 // here, we would coerce from `!` to `?T`.
102 match to_ty.kind(&Interner) {
103 TyKind::InferenceVar(tv, TyVariableKind::General) => {
104 self.table.set_diverging(*tv, true);
105 }
106 _ => {}
61 } 107 }
62 (TyKind::Never, _) => return true, 108 return Ok(InferOk { goals: Vec::new() });
109 }
63 110
64 // Trivial cases, this should go after `never` check to 111 // Consider coercing the subtype to a DST
65 // avoid infer result type to be never 112 if let Ok(ret) = self.try_coerce_unsized(&from_ty, &to_ty) {
66 _ => { 113 return Ok(ret);
67 if self.table.unify_inner_trivial(&from_ty, &to_ty, 0) { 114 }
68 return true; 115
69 } 116 // Examine the supertype and consider auto-borrowing.
117 match to_ty.kind(&Interner) {
118 TyKind::Raw(mt, _) => {
119 return self.coerce_ptr(from_ty, to_ty, *mt);
70 } 120 }
121 TyKind::Ref(mt, _, _) => {
122 return self.coerce_ref(from_ty, to_ty, *mt);
123 }
124 _ => {}
71 } 125 }
72 126
73 // Pointer weakening and function to pointer 127 match from_ty.kind(&Interner) {
74 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { 128 TyKind::FnDef(..) => {
75 // `*mut T` -> `*const T` 129 // Function items are coercible to any closure
76 (TyKind::Raw(_, inner), TyKind::Raw(m2 @ Mutability::Not, ..)) => { 130 // type; function pointers are not (that would
77 from_ty = TyKind::Raw(*m2, inner.clone()).intern(&Interner); 131 // require double indirection).
132 // Additionally, we permit coercion of function
133 // items to drop the unsafe qualifier.
134 self.coerce_from_fn_item(from_ty, to_ty)
78 } 135 }
79 // `&mut T` -> `&T` 136 TyKind::Function(from_fn_ptr) => {
80 (TyKind::Ref(_, lt, inner), TyKind::Ref(m2 @ Mutability::Not, ..)) => { 137 // We permit coercion of fn pointers to drop the
81 from_ty = TyKind::Ref(*m2, lt.clone(), inner.clone()).intern(&Interner); 138 // unsafe qualifier.
139 self.coerce_from_fn_pointer(from_ty.clone(), from_fn_ptr, to_ty)
82 } 140 }
83 // `&T` -> `*const T` 141 TyKind::Closure(_, from_substs) => {
84 // `&mut T` -> `*mut T`/`*const T` 142 // Non-capturing closures are coercible to
85 (TyKind::Ref(.., substs), &TyKind::Raw(m2 @ Mutability::Not, ..)) 143 // function pointers or unsafe function pointers.
86 | (TyKind::Ref(Mutability::Mut, _, substs), &TyKind::Raw(m2, ..)) => { 144 // It cannot convert closures that require unsafe.
87 from_ty = TyKind::Raw(m2, substs.clone()).intern(&Interner); 145 self.coerce_closure_to_fn(from_ty.clone(), from_substs, to_ty)
88 } 146 }
147 _ => {
148 // Otherwise, just use unification rules.
149 self.table.try_unify(&from_ty, to_ty)
150 }
151 }
152 }
89 153
90 // Illegal mutability conversion 154 fn coerce_ptr(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> InferResult {
91 (TyKind::Raw(Mutability::Not, ..), TyKind::Raw(Mutability::Mut, ..)) 155 let (_is_ref, from_mt, from_inner) = match from_ty.kind(&Interner) {
92 | (TyKind::Ref(Mutability::Not, ..), TyKind::Ref(Mutability::Mut, ..)) => return false, 156 TyKind::Ref(mt, _, ty) => (true, mt, ty),
157 TyKind::Raw(mt, ty) => (false, mt, ty),
158 _ => return self.table.try_unify(&from_ty, to_ty),
159 };
93 160
94 // `{function_type}` -> `fn()` 161 coerce_mutabilities(*from_mt, to_mt)?;
95 (TyKind::FnDef(..), TyKind::Function { .. }) => match from_ty.callable_sig(self.db) { 162
96 None => return false, 163 // Check that the types which they point at are compatible.
97 Some(sig) => { 164 let from_raw = TyKind::Raw(to_mt, from_inner.clone()).intern(&Interner);
98 from_ty = TyBuilder::fn_ptr(sig); 165 // FIXME: behavior differs based on is_ref once we're computing adjustments
99 } 166 self.table.try_unify(&from_raw, to_ty)
167 }
168
169 /// Reborrows `&mut A` to `&mut B` and `&(mut) A` to `&B`.
170 /// To match `A` with `B`, autoderef will be performed,
171 /// calling `deref`/`deref_mut` where necessary.
172 fn coerce_ref(&mut self, from_ty: Ty, to_ty: &Ty, to_mt: Mutability) -> InferResult {
173 match from_ty.kind(&Interner) {
174 TyKind::Ref(mt, _, _) => {
175 coerce_mutabilities(*mt, to_mt)?;
176 }
177 _ => return self.table.try_unify(&from_ty, to_ty),
178 };
179
180 // NOTE: this code is mostly copied and adapted from rustc, and
181 // currently more complicated than necessary, carrying errors around
182 // etc.. This complication will become necessary when we actually track
183 // details of coercion errors though, so I think it's useful to leave
184 // the structure like it is.
185
186 let canonicalized = self.canonicalize(from_ty.clone());
187 let autoderef = autoderef::autoderef(
188 self.db,
189 self.resolver.krate(),
190 InEnvironment {
191 goal: canonicalized.value.clone(),
192 environment: self.trait_env.env.clone(),
100 }, 193 },
194 );
195 let mut first_error = None;
196 let mut found = None;
101 197
102 (TyKind::Closure(.., substs), TyKind::Function { .. }) => { 198 for (autoderefs, referent_ty) in autoderef.enumerate() {
103 from_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone(); 199 if autoderefs == 0 {
200 // Don't let this pass, otherwise it would cause
201 // &T to autoref to &&T.
202 continue;
104 } 203 }
105 204
106 _ => {} 205 let referent_ty = canonicalized.decanonicalize_ty(referent_ty.value);
206
207 // At this point, we have deref'd `a` to `referent_ty`. So
208 // imagine we are coercing from `&'a mut Vec<T>` to `&'b mut [T]`.
209 // In the autoderef loop for `&'a mut Vec<T>`, we would get
210 // three callbacks:
211 //
212 // - `&'a mut Vec<T>` -- 0 derefs, just ignore it
213 // - `Vec<T>` -- 1 deref
214 // - `[T]` -- 2 deref
215 //
216 // At each point after the first callback, we want to
217 // check to see whether this would match out target type
218 // (`&'b mut [T]`) if we autoref'd it. We can't just
219 // compare the referent types, though, because we still
220 // have to consider the mutability. E.g., in the case
221 // we've been considering, we have an `&mut` reference, so
222 // the `T` in `[T]` needs to be unified with equality.
223 //
224 // Therefore, we construct reference types reflecting what
225 // the types will be after we do the final auto-ref and
226 // compare those. Note that this means we use the target
227 // mutability [1], since it may be that we are coercing
228 // from `&mut T` to `&U`.
229 let lt = static_lifetime(); // FIXME: handle lifetimes correctly, see rustc
230 let derefd_from_ty = TyKind::Ref(to_mt, lt, referent_ty).intern(&Interner);
231 match self.table.try_unify(&derefd_from_ty, to_ty) {
232 Ok(result) => {
233 found = Some(result);
234 break;
235 }
236 Err(err) => {
237 if first_error.is_none() {
238 first_error = Some(err);
239 }
240 }
241 }
107 } 242 }
108 243
109 if let Some(ret) = self.try_coerce_unsized(&from_ty, &to_ty) { 244 // Extract type or return an error. We return the first error
110 return ret; 245 // we got, which should be from relating the "base" type
246 // (e.g., in example above, the failure from relating `Vec<T>`
247 // to the target type), since that should be the least
248 // confusing.
249 let result = match found {
250 Some(d) => d,
251 None => {
252 let err = first_error.expect("coerce_borrowed_pointer had no error");
253 return Err(err);
254 }
255 };
256
257 Ok(result)
258 }
259
260 /// Attempts to coerce from the type of a Rust function item into a function pointer.
261 fn coerce_from_fn_item(&mut self, from_ty: Ty, to_ty: &Ty) -> InferResult {
262 match to_ty.kind(&Interner) {
263 TyKind::Function(_) => {
264 let from_sig = from_ty.callable_sig(self.db).expect("FnDef had no sig");
265
266 // FIXME check ABI: Intrinsics are not coercible to function pointers
267 // FIXME Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396)
268
269 // FIXME rustc normalizes assoc types in the sig here, not sure if necessary
270
271 let from_sig = from_sig.to_fn_ptr();
272 let from_fn_pointer = TyKind::Function(from_sig.clone()).intern(&Interner);
273 let ok = self.coerce_from_safe_fn(from_fn_pointer, &from_sig, to_ty)?;
274
275 Ok(ok)
276 }
277 _ => self.table.try_unify(&from_ty, to_ty),
111 } 278 }
279 }
280
281 fn coerce_from_fn_pointer(
282 &mut self,
283 from_ty: Ty,
284 from_f: &FnPointer,
285 to_ty: &Ty,
286 ) -> InferResult {
287 self.coerce_from_safe_fn(from_ty, from_f, to_ty)
288 }
112 289
113 // Auto Deref if cannot coerce 290 fn coerce_from_safe_fn(
114 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { 291 &mut self,
115 // FIXME: DerefMut 292 from_ty: Ty,
116 (TyKind::Ref(.., st1), TyKind::Ref(.., st2)) => { 293 from_fn_ptr: &FnPointer,
117 self.unify_autoderef_behind_ref(st1, st2) 294 to_ty: &Ty,
295 ) -> InferResult {
296 if let TyKind::Function(to_fn_ptr) = to_ty.kind(&Interner) {
297 if let (chalk_ir::Safety::Safe, chalk_ir::Safety::Unsafe) =
298 (from_fn_ptr.sig.safety, to_fn_ptr.sig.safety)
299 {
300 let from_unsafe =
301 TyKind::Function(safe_to_unsafe_fn_ty(from_fn_ptr.clone())).intern(&Interner);
302 return self.table.try_unify(&from_unsafe, to_ty);
118 } 303 }
304 }
305 self.table.try_unify(&from_ty, to_ty)
306 }
119 307
120 // Otherwise, normal unify 308 /// Attempts to coerce from the type of a non-capturing closure into a
121 _ => self.unify(&from_ty, to_ty), 309 /// function pointer.
310 fn coerce_closure_to_fn(
311 &mut self,
312 from_ty: Ty,
313 from_substs: &Substitution,
314 to_ty: &Ty,
315 ) -> InferResult {
316 match to_ty.kind(&Interner) {
317 TyKind::Function(fn_ty) /* if from_substs is non-capturing (FIXME) */ => {
318 // We coerce the closure, which has fn type
319 // `extern "rust-call" fn((arg0,arg1,...)) -> _`
320 // to
321 // `fn(arg0,arg1,...) -> _`
322 // or
323 // `unsafe fn(arg0,arg1,...) -> _`
324 let safety = fn_ty.sig.safety;
325 let pointer_ty = coerce_closure_fn_ty(from_substs, safety);
326 self.table.try_unify(&pointer_ty, to_ty)
327 }
328 _ => self.table.try_unify(&from_ty, to_ty),
122 } 329 }
123 } 330 }
124 331
125 /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>` 332 /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>`
126 /// 333 ///
127 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html 334 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html
128 fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> { 335 fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> InferResult {
336 // These 'if' statements require some explanation.
337 // The `CoerceUnsized` trait is special - it is only
338 // possible to write `impl CoerceUnsized<B> for A` where
339 // A and B have 'matching' fields. This rules out the following
340 // two types of blanket impls:
341 //
342 // `impl<T> CoerceUnsized<T> for SomeType`
343 // `impl<T> CoerceUnsized<SomeType> for T`
344 //
345 // Both of these trigger a special `CoerceUnsized`-related error (E0376)
346 //
347 // We can take advantage of this fact to avoid performing unecessary work.
348 // If either `source` or `target` is a type variable, then any applicable impl
349 // would need to be generic over the self-type (`impl<T> CoerceUnsized<SomeType> for T`)
350 // or generic over the `CoerceUnsized` type parameter (`impl<T> CoerceUnsized<T> for
351 // SomeType`).
352 //
353 // However, these are exactly the kinds of impls which are forbidden by
354 // the compiler! Therefore, we can be sure that coercion will always fail
355 // when either the source or target type is a type variable. This allows us
356 // to skip performing any trait selection, and immediately bail out.
357 if from_ty.is_ty_var() {
358 return Err(TypeError);
359 }
360 if to_ty.is_ty_var() {
361 return Err(TypeError);
362 }
363
364 // Handle reborrows before trying to solve `Source: CoerceUnsized<Target>`.
365 let coerce_from = match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
366 (TyKind::Ref(from_mt, _, from_inner), TyKind::Ref(to_mt, _, _)) => {
367 coerce_mutabilities(*from_mt, *to_mt)?;
368
369 let lt = static_lifetime();
370 TyKind::Ref(*to_mt, lt, from_inner.clone()).intern(&Interner)
371 }
372 (TyKind::Ref(from_mt, _, from_inner), TyKind::Raw(to_mt, _)) => {
373 coerce_mutabilities(*from_mt, *to_mt)?;
374
375 TyKind::Raw(*to_mt, from_inner.clone()).intern(&Interner)
376 }
377 _ => from_ty.clone(),
378 };
379
129 let krate = self.resolver.krate().unwrap(); 380 let krate = self.resolver.krate().unwrap();
130 let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) { 381 let coerce_unsized_trait = match self.db.lang_item(krate, "coerce_unsized".into()) {
131 Some(LangItemTarget::TraitId(trait_)) => trait_, 382 Some(LangItemTarget::TraitId(trait_)) => trait_,
132 _ => return None, 383 _ => return Err(TypeError),
133 }; 384 };
134 385
135 let trait_ref = { 386 let trait_ref = {
136 let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait); 387 let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);
137 if b.remaining() != 2 { 388 if b.remaining() != 2 {
138 // The CoerceUnsized trait should have two generic params: Self and T. 389 // The CoerceUnsized trait should have two generic params: Self and T.
139 return None; 390 return Err(TypeError);
140 } 391 }
141 b.push(from_ty.clone()).push(to_ty.clone()).build() 392 b.push(coerce_from.clone()).push(to_ty.clone()).build()
142 }; 393 };
143 394
144 let goal = InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner)); 395 let goal: InEnvironment<DomainGoal> =
396 InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner));
145 397
146 let canonicalizer = self.canonicalizer(); 398 let canonicalized = self.canonicalize(goal);
147 let canonicalized = canonicalizer.canonicalize_obligation(goal);
148 399
149 let solution = self.db.trait_solve(krate, canonicalized.value.clone())?; 400 // FIXME: rustc's coerce_unsized is more specialized -- it only tries to
401 // solve `CoerceUnsized` and `Unsize` goals at this point and leaves the
402 // rest for later. Also, there's some logic about sized type variables.
403 // Need to find out in what cases this is necessary
404 let solution = self
405 .db
406 .trait_solve(krate, canonicalized.value.clone().cast(&Interner))
407 .ok_or(TypeError)?;
150 408
151 match solution { 409 match solution {
152 Solution::Unique(v) => { 410 Solution::Unique(v) => {
153 canonicalized.apply_solution( 411 canonicalized.apply_solution(
154 self, 412 &mut self.table,
155 Canonical { 413 Canonical {
156 binders: v.binders, 414 binders: v.binders,
157 // FIXME handle constraints 415 // FIXME handle constraints
@@ -159,38 +417,40 @@ impl<'a> InferenceContext<'a> {
159 }, 417 },
160 ); 418 );
161 } 419 }
162 _ => return None, 420 // FIXME: should we accept ambiguous results here?
421 _ => return Err(TypeError),
163 }; 422 };
164 423
165 Some(true) 424 Ok(InferOk { goals: Vec::new() })
166 } 425 }
426}
167 427
168 /// Unify `from_ty` to `to_ty` with optional auto Deref 428fn coerce_closure_fn_ty(closure_substs: &Substitution, safety: chalk_ir::Safety) -> Ty {
169 /// 429 let closure_sig = closure_substs.at(&Interner, 0).assert_ty_ref(&Interner).clone();
170 /// Note that the parameters are already stripped the outer reference. 430 match closure_sig.kind(&Interner) {
171 fn unify_autoderef_behind_ref(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool { 431 TyKind::Function(fn_ty) => TyKind::Function(FnPointer {
172 let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone()); 432 num_binders: fn_ty.num_binders,
173 let to_ty = self.resolve_ty_shallow(&to_ty); 433 sig: FnSig { safety, ..fn_ty.sig },
174 // FIXME: Auto DerefMut 434 substitution: fn_ty.substitution.clone(),
175 for derefed_ty in autoderef::autoderef( 435 })
176 self.db, 436 .intern(&Interner),
177 self.resolver.krate(), 437 _ => TyKind::Error.intern(&Interner),
178 InEnvironment { 438 }
179 goal: canonicalized.value.clone(), 439}
180 environment: self.trait_env.env.clone(), 440
181 }, 441fn safe_to_unsafe_fn_ty(fn_ty: FnPointer) -> FnPointer {
182 ) { 442 FnPointer {
183 let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value); 443 num_binders: fn_ty.num_binders,
184 let from_ty = self.resolve_ty_shallow(&derefed_ty); 444 sig: FnSig { safety: chalk_ir::Safety::Unsafe, ..fn_ty.sig },
185 // Stop when constructor matches. 445 substitution: fn_ty.substitution,
186 if from_ty.equals_ctor(&to_ty) { 446 }
187 // It will not recurse to `coerce`. 447}
188 return self.table.unify(&from_ty, &to_ty);
189 } else if self.table.unify_inner_trivial(&derefed_ty, &to_ty, 0) {
190 return true;
191 }
192 }
193 448
194 false 449fn coerce_mutabilities(from: Mutability, to: Mutability) -> Result<(), TypeError> {
450 match (from, to) {
451 (Mutability::Mut, Mutability::Mut)
452 | (Mutability::Mut, Mutability::Not)
453 | (Mutability::Not, Mutability::Not) => Ok(()),
454 (Mutability::Not, Mutability::Mut) => Err(TypeError),
195 } 455 }
196} 456}
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 7278faeec..08c05c67c 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -35,39 +35,43 @@ use super::{
35impl<'a> InferenceContext<'a> { 35impl<'a> InferenceContext<'a> {
36 pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 36 pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
37 let ty = self.infer_expr_inner(tgt_expr, expected); 37 let ty = self.infer_expr_inner(tgt_expr, expected);
38 if ty.is_never() { 38 if self.resolve_ty_shallow(&ty).is_never() {
39 // Any expression that produces a value of type `!` must have diverged 39 // Any expression that produces a value of type `!` must have diverged
40 self.diverges = Diverges::Always; 40 self.diverges = Diverges::Always;
41 } 41 }
42 let could_unify = self.unify(&ty, &expected.ty); 42 if let Some(expected_ty) = expected.only_has_type(&mut self.table) {
43 if !could_unify { 43 let could_unify = self.unify(&ty, &expected_ty);
44 self.result.type_mismatches.insert( 44 if !could_unify {
45 tgt_expr.into(), 45 self.result.type_mismatches.insert(
46 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, 46 tgt_expr.into(),
47 ); 47 TypeMismatch { expected: expected_ty.clone(), actual: ty.clone() },
48 );
49 }
48 } 50 }
49 self.resolve_ty_as_possible(ty) 51 ty
50 } 52 }
51 53
52 /// Infer type of expression with possibly implicit coerce to the expected type. 54 /// Infer type of expression with possibly implicit coerce to the expected type.
53 /// Return the type after possible coercion. 55 /// Return the type after possible coercion.
54 pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { 56 pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
55 let ty = self.infer_expr_inner(expr, &expected); 57 let ty = self.infer_expr_inner(expr, &expected);
56 let ty = if !self.coerce(&ty, &expected.coercion_target()) { 58 let ty = if let Some(target) = expected.only_has_type(&mut self.table) {
57 self.result.type_mismatches.insert( 59 if !self.coerce(&ty, &target) {
58 expr.into(), 60 self.result.type_mismatches.insert(
59 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, 61 expr.into(),
60 ); 62 TypeMismatch { expected: target.clone(), actual: ty.clone() },
61 // Return actual type when type mismatch. 63 );
62 // This is needed for diagnostic when return type mismatch. 64 // Return actual type when type mismatch.
63 ty 65 // This is needed for diagnostic when return type mismatch.
64 } else if expected.coercion_target().is_unknown() { 66 ty
65 ty 67 } else {
68 target.clone()
69 }
66 } else { 70 } else {
67 expected.ty.clone() 71 ty
68 }; 72 };
69 73
70 self.resolve_ty_as_possible(ty) 74 ty
71 } 75 }
72 76
73 fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { 77 fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> {
@@ -98,10 +102,10 @@ impl<'a> InferenceContext<'a> {
98 goal: projection.trait_ref(self.db).cast(&Interner), 102 goal: projection.trait_ref(self.db).cast(&Interner),
99 environment: trait_env, 103 environment: trait_env,
100 }; 104 };
101 let canonical = self.canonicalizer().canonicalize_obligation(obligation.clone()); 105 let canonical = self.canonicalize(obligation.clone());
102 if self.db.trait_solve(krate, canonical.value).is_some() { 106 if self.db.trait_solve(krate, canonical.value.cast(&Interner)).is_some() {
103 self.push_obligation(obligation.goal); 107 self.push_obligation(obligation.goal);
104 let return_ty = self.normalize_projection_ty(projection); 108 let return_ty = self.table.normalize_projection_ty(projection);
105 Some((arg_tys, return_ty)) 109 Some((arg_tys, return_ty))
106 } else { 110 } else {
107 None 111 None
@@ -131,17 +135,21 @@ impl<'a> InferenceContext<'a> {
131 let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); 135 let condition_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
132 let mut both_arms_diverge = Diverges::Always; 136 let mut both_arms_diverge = Diverges::Always;
133 137
138 let mut result_ty = self.table.new_type_var();
134 let then_ty = self.infer_expr_inner(*then_branch, &expected); 139 let then_ty = self.infer_expr_inner(*then_branch, &expected);
135 both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); 140 both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
141 result_ty = self.coerce_merge_branch(Some(*then_branch), &result_ty, &then_ty);
136 let else_ty = match else_branch { 142 let else_ty = match else_branch {
137 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), 143 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
138 None => TyBuilder::unit(), 144 None => TyBuilder::unit(),
139 }; 145 };
140 both_arms_diverge &= self.diverges; 146 both_arms_diverge &= self.diverges;
147 // FIXME: create a synthetic `else {}` so we have something to refer to here instead of None?
148 result_ty = self.coerce_merge_branch(*else_branch, &result_ty, &else_ty);
141 149
142 self.diverges = condition_diverges | both_arms_diverge; 150 self.diverges = condition_diverges | both_arms_diverge;
143 151
144 self.coerce_merge_branch(&then_ty, &else_ty) 152 result_ty
145 } 153 }
146 Expr::Block { statements, tail, label, id: _ } => { 154 Expr::Block { statements, tail, label, id: _ } => {
147 let old_resolver = mem::replace( 155 let old_resolver = mem::replace(
@@ -277,12 +285,13 @@ impl<'a> InferenceContext<'a> {
277 // Eagerly try to relate the closure type with the expected 285 // Eagerly try to relate the closure type with the expected
278 // type, otherwise we often won't have enough information to 286 // type, otherwise we often won't have enough information to
279 // infer the body. 287 // infer the body.
280 self.coerce(&closure_ty, &expected.ty); 288 if let Some(t) = expected.only_has_type(&mut self.table) {
289 self.coerce(&closure_ty, &t);
290 }
281 291
282 // Now go through the argument patterns 292 // Now go through the argument patterns
283 for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { 293 for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
284 let resolved = self.resolve_ty_as_possible(arg_ty); 294 self.infer_pat(*arg_pat, &arg_ty, BindingMode::default());
285 self.infer_pat(*arg_pat, &resolved, BindingMode::default());
286 } 295 }
287 296
288 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); 297 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
@@ -297,13 +306,13 @@ impl<'a> InferenceContext<'a> {
297 } 306 }
298 Expr::Call { callee, args } => { 307 Expr::Call { callee, args } => {
299 let callee_ty = self.infer_expr(*callee, &Expectation::none()); 308 let callee_ty = self.infer_expr(*callee, &Expectation::none());
300 let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone()); 309 let canonicalized = self.canonicalize(callee_ty.clone());
301 let mut derefs = autoderef( 310 let mut derefs = autoderef(
302 self.db, 311 self.db,
303 self.resolver.krate(), 312 self.resolver.krate(),
304 InEnvironment { 313 InEnvironment {
305 goal: canonicalized.value.clone(), 314 goal: canonicalized.value.clone(),
306 environment: self.trait_env.env.clone(), 315 environment: self.table.trait_env.env.clone(),
307 }, 316 },
308 ); 317 );
309 let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs 318 let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs
@@ -350,7 +359,7 @@ impl<'a> InferenceContext<'a> {
350 359
351 let arm_ty = self.infer_expr_inner(arm.expr, &expected); 360 let arm_ty = self.infer_expr_inner(arm.expr, &expected);
352 all_arms_diverge &= self.diverges; 361 all_arms_diverge &= self.diverges;
353 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty); 362 result_ty = self.coerce_merge_branch(Some(arm.expr), &result_ty, &arm_ty);
354 } 363 }
355 364
356 self.diverges = matchee_diverges | all_arms_diverge; 365 self.diverges = matchee_diverges | all_arms_diverge;
@@ -364,12 +373,6 @@ impl<'a> InferenceContext<'a> {
364 } 373 }
365 Expr::Continue { .. } => TyKind::Never.intern(&Interner), 374 Expr::Continue { .. } => TyKind::Never.intern(&Interner),
366 Expr::Break { expr, label } => { 375 Expr::Break { expr, label } => {
367 let val_ty = if let Some(expr) = expr {
368 self.infer_expr(*expr, &Expectation::none())
369 } else {
370 TyBuilder::unit()
371 };
372
373 let last_ty = 376 let last_ty =
374 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { 377 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
375 ctxt.break_ty.clone() 378 ctxt.break_ty.clone()
@@ -377,7 +380,14 @@ impl<'a> InferenceContext<'a> {
377 self.err_ty() 380 self.err_ty()
378 }; 381 };
379 382
380 let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); 383 let val_ty = if let Some(expr) = expr {
384 self.infer_expr(*expr, &Expectation::none())
385 } else {
386 TyBuilder::unit()
387 };
388
389 // FIXME: create a synthetic `()` during lowering so we have something to refer to here?
390 let merged_type = self.coerce_merge_branch(*expr, &last_ty, &val_ty);
381 391
382 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { 392 if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) {
383 ctxt.break_ty = merged_type; 393 ctxt.break_ty = merged_type;
@@ -411,7 +421,9 @@ impl<'a> InferenceContext<'a> {
411 self.write_variant_resolution(tgt_expr.into(), variant); 421 self.write_variant_resolution(tgt_expr.into(), variant);
412 } 422 }
413 423
414 self.unify(&ty, &expected.ty); 424 if let Some(t) = expected.only_has_type(&mut self.table) {
425 self.unify(&ty, &t);
426 }
415 427
416 let substs = ty 428 let substs = ty
417 .as_adt() 429 .as_adt()
@@ -442,7 +454,7 @@ impl<'a> InferenceContext<'a> {
442 } 454 }
443 Expr::Field { expr, name } => { 455 Expr::Field { expr, name } => {
444 let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none()); 456 let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none());
445 let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); 457 let canonicalized = self.canonicalize(receiver_ty);
446 let ty = autoderef::autoderef( 458 let ty = autoderef::autoderef(
447 self.db, 459 self.db,
448 self.resolver.krate(), 460 self.resolver.krate(),
@@ -514,6 +526,7 @@ impl<'a> InferenceContext<'a> {
514 self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok()) 526 self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok())
515 } 527 }
516 Expr::Cast { expr, type_ref } => { 528 Expr::Cast { expr, type_ref } => {
529 // FIXME: propagate the "castable to" expectation (and find a test case that shows this is necessary)
517 let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 530 let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
518 let cast_ty = self.make_ty(type_ref); 531 let cast_ty = self.make_ty(type_ref);
519 // FIXME check the cast... 532 // FIXME check the cast...
@@ -521,15 +534,17 @@ impl<'a> InferenceContext<'a> {
521 } 534 }
522 Expr::Ref { expr, rawness, mutability } => { 535 Expr::Ref { expr, rawness, mutability } => {
523 let mutability = lower_to_chalk_mutability(*mutability); 536 let mutability = lower_to_chalk_mutability(*mutability);
524 let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = 537 let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = expected
525 &expected.ty.as_reference_or_ptr() 538 .only_has_type(&mut self.table)
539 .as_ref()
540 .and_then(|t| t.as_reference_or_ptr())
526 { 541 {
527 if *exp_mutability == Mutability::Mut && mutability == Mutability::Not { 542 if exp_mutability == Mutability::Mut && mutability == Mutability::Not {
528 // FIXME: throw type error - expected mut reference but found shared ref, 543 // FIXME: record type error - expected mut reference but found shared ref,
529 // which cannot be coerced 544 // which cannot be coerced
530 } 545 }
531 if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { 546 if exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr {
532 // FIXME: throw type error - expected reference but found ptr, 547 // FIXME: record type error - expected reference but found ptr,
533 // which cannot be coerced 548 // which cannot be coerced
534 } 549 }
535 Expectation::rvalue_hint(Ty::clone(exp_inner)) 550 Expectation::rvalue_hint(Ty::clone(exp_inner))
@@ -556,10 +571,11 @@ impl<'a> InferenceContext<'a> {
556 } 571 }
557 Expr::UnaryOp { expr, op } => { 572 Expr::UnaryOp { expr, op } => {
558 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 573 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
574 let inner_ty = self.resolve_ty_shallow(&inner_ty);
559 match op { 575 match op {
560 UnaryOp::Deref => match self.resolver.krate() { 576 UnaryOp::Deref => match self.resolver.krate() {
561 Some(krate) => { 577 Some(krate) => {
562 let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty); 578 let canonicalized = self.canonicalize(inner_ty);
563 match autoderef::deref( 579 match autoderef::deref(
564 self.db, 580 self.db,
565 krate, 581 krate,
@@ -612,8 +628,10 @@ impl<'a> InferenceContext<'a> {
612 _ => Expectation::none(), 628 _ => Expectation::none(),
613 }; 629 };
614 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation); 630 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation);
631 let lhs_ty = self.resolve_ty_shallow(&lhs_ty);
615 let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty.clone()); 632 let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty.clone());
616 let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation)); 633 let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation));
634 let rhs_ty = self.resolve_ty_shallow(&rhs_ty);
617 635
618 let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone()); 636 let ret = op::binary_op_return_ty(*op, lhs_ty.clone(), rhs_ty.clone());
619 637
@@ -676,7 +694,7 @@ impl<'a> InferenceContext<'a> {
676 if let (Some(index_trait), Some(krate)) = 694 if let (Some(index_trait), Some(krate)) =
677 (self.resolve_ops_index(), self.resolver.krate()) 695 (self.resolve_ops_index(), self.resolver.krate())
678 { 696 {
679 let canonicalized = self.canonicalizer().canonicalize_ty(base_ty); 697 let canonicalized = self.canonicalize(base_ty);
680 let self_ty = method_resolution::resolve_indexing_op( 698 let self_ty = method_resolution::resolve_indexing_op(
681 self.db, 699 self.db,
682 &canonicalized.value, 700 &canonicalized.value,
@@ -696,8 +714,12 @@ impl<'a> InferenceContext<'a> {
696 } 714 }
697 } 715 }
698 Expr::Tuple { exprs } => { 716 Expr::Tuple { exprs } => {
699 let mut tys = match expected.ty.kind(&Interner) { 717 let mut tys = match expected
700 TyKind::Tuple(_, substs) => substs 718 .only_has_type(&mut self.table)
719 .as_ref()
720 .map(|t| t.kind(&Interner))
721 {
722 Some(TyKind::Tuple(_, substs)) => substs
701 .iter(&Interner) 723 .iter(&Interner)
702 .map(|a| a.assert_ty_ref(&Interner).clone()) 724 .map(|a| a.assert_ty_ref(&Interner).clone())
703 .chain(repeat_with(|| self.table.new_type_var())) 725 .chain(repeat_with(|| self.table.new_type_var()))
@@ -713,14 +735,16 @@ impl<'a> InferenceContext<'a> {
713 TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner) 735 TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner)
714 } 736 }
715 Expr::Array(array) => { 737 Expr::Array(array) => {
716 let elem_ty = match expected.ty.kind(&Interner) { 738 let elem_ty =
717 TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(), 739 match expected.to_option(&mut self.table).as_ref().map(|t| t.kind(&Interner)) {
718 _ => self.table.new_type_var(), 740 Some(TyKind::Array(st, _)) | Some(TyKind::Slice(st)) => st.clone(),
719 }; 741 _ => self.table.new_type_var(),
742 };
720 743
721 let len = match array { 744 let len = match array {
722 Array::ElementList(items) => { 745 Array::ElementList(items) => {
723 for expr in items.iter() { 746 for expr in items.iter() {
747 // FIXME: use CoerceMany (coerce_merge_branch)
724 self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone())); 748 self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
725 } 749 }
726 Some(items.len() as u64) 750 Some(items.len() as u64)
@@ -785,7 +809,6 @@ impl<'a> InferenceContext<'a> {
785 }; 809 };
786 // use a new type variable if we got unknown here 810 // use a new type variable if we got unknown here
787 let ty = self.insert_type_vars_shallow(ty); 811 let ty = self.insert_type_vars_shallow(ty);
788 let ty = self.resolve_ty_as_possible(ty);
789 self.write_expr_ty(tgt_expr, ty.clone()); 812 self.write_expr_ty(tgt_expr, ty.clone());
790 ty 813 ty
791 } 814 }
@@ -813,7 +836,6 @@ impl<'a> InferenceContext<'a> {
813 } 836 }
814 } 837 }
815 838
816 let ty = self.resolve_ty_as_possible(ty);
817 self.infer_pat(*pat, &ty, BindingMode::default()); 839 self.infer_pat(*pat, &ty, BindingMode::default());
818 } 840 }
819 Statement::Expr { expr, .. } => { 841 Statement::Expr { expr, .. } => {
@@ -836,7 +858,9 @@ impl<'a> InferenceContext<'a> {
836 // we don't even make an attempt at coercion 858 // we don't even make an attempt at coercion
837 self.table.new_maybe_never_var() 859 self.table.new_maybe_never_var()
838 } else { 860 } else {
839 self.coerce(&TyBuilder::unit(), &expected.coercion_target()); 861 if let Some(t) = expected.only_has_type(&mut self.table) {
862 self.coerce(&TyBuilder::unit(), &t);
863 }
840 TyBuilder::unit() 864 TyBuilder::unit()
841 } 865 }
842 }; 866 };
@@ -852,7 +876,7 @@ impl<'a> InferenceContext<'a> {
852 generic_args: Option<&GenericArgs>, 876 generic_args: Option<&GenericArgs>,
853 ) -> Ty { 877 ) -> Ty {
854 let receiver_ty = self.infer_expr(receiver, &Expectation::none()); 878 let receiver_ty = self.infer_expr(receiver, &Expectation::none());
855 let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone()); 879 let canonicalized_receiver = self.canonicalize(receiver_ty.clone());
856 880
857 let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); 881 let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
858 882
@@ -891,7 +915,8 @@ impl<'a> InferenceContext<'a> {
891 }; 915 };
892 // Apply autoref so the below unification works correctly 916 // Apply autoref so the below unification works correctly
893 // FIXME: return correct autorefs from lookup_method 917 // FIXME: return correct autorefs from lookup_method
894 let actual_receiver_ty = match expected_receiver_ty.as_reference() { 918 let actual_receiver_ty = match self.resolve_ty_shallow(&expected_receiver_ty).as_reference()
919 {
895 Some((_, lifetime, mutability)) => { 920 Some((_, lifetime, mutability)) => {
896 TyKind::Ref(mutability, lifetime, derefed_receiver_ty).intern(&Interner) 921 TyKind::Ref(mutability, lifetime, derefed_receiver_ty).intern(&Interner)
897 } 922 }
@@ -971,6 +996,7 @@ impl<'a> InferenceContext<'a> {
971 } 996 }
972 997
973 fn register_obligations_for_call(&mut self, callable_ty: &Ty) { 998 fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
999 let callable_ty = self.resolve_ty_shallow(&callable_ty);
974 if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(&Interner) { 1000 if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(&Interner) {
975 let def: CallableDefId = from_chalk(self.db, *fn_def); 1001 let def: CallableDefId = from_chalk(self.db, *fn_def);
976 let generic_predicates = self.db.generic_predicates(def.into()); 1002 let generic_predicates = self.db.generic_predicates(def.into());
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index b15f4977d..9c8e3b6ae 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -94,14 +94,15 @@ impl<'a> InferenceContext<'a> {
94 pub(super) fn infer_pat( 94 pub(super) fn infer_pat(
95 &mut self, 95 &mut self,
96 pat: PatId, 96 pat: PatId,
97 mut expected: &Ty, 97 expected: &Ty,
98 mut default_bm: BindingMode, 98 mut default_bm: BindingMode,
99 ) -> Ty { 99 ) -> Ty {
100 let body = Arc::clone(&self.body); // avoid borrow checker problem 100 let body = Arc::clone(&self.body); // avoid borrow checker problem
101 let mut expected = self.resolve_ty_shallow(expected);
101 102
102 if is_non_ref_pat(&body, pat) { 103 if is_non_ref_pat(&body, pat) {
103 while let Some((inner, _lifetime, mutability)) = expected.as_reference() { 104 while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
104 expected = inner; 105 expected = self.resolve_ty_shallow(inner);
105 default_bm = match default_bm { 106 default_bm = match default_bm {
106 BindingMode::Move => BindingMode::Ref(mutability), 107 BindingMode::Move => BindingMode::Ref(mutability),
107 BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not), 108 BindingMode::Ref(Mutability::Not) => BindingMode::Ref(Mutability::Not),
@@ -147,9 +148,9 @@ impl<'a> InferenceContext<'a> {
147 } 148 }
148 Pat::Or(ref pats) => { 149 Pat::Or(ref pats) => {
149 if let Some((first_pat, rest)) = pats.split_first() { 150 if let Some((first_pat, rest)) = pats.split_first() {
150 let ty = self.infer_pat(*first_pat, expected, default_bm); 151 let ty = self.infer_pat(*first_pat, &expected, default_bm);
151 for pat in rest { 152 for pat in rest {
152 self.infer_pat(*pat, expected, default_bm); 153 self.infer_pat(*pat, &expected, default_bm);
153 } 154 }
154 ty 155 ty
155 } else { 156 } else {
@@ -173,13 +174,13 @@ impl<'a> InferenceContext<'a> {
173 Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat( 174 Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat(
174 p.as_deref(), 175 p.as_deref(),
175 subpats, 176 subpats,
176 expected, 177 &expected,
177 default_bm, 178 default_bm,
178 pat, 179 pat,
179 *ellipsis, 180 *ellipsis,
180 ), 181 ),
181 Pat::Record { path: p, args: fields, ellipsis: _ } => { 182 Pat::Record { path: p, args: fields, ellipsis: _ } => {
182 self.infer_record_pat(p.as_deref(), fields, expected, default_bm, pat) 183 self.infer_record_pat(p.as_deref(), fields, &expected, default_bm, pat)
183 } 184 }
184 Pat::Path(path) => { 185 Pat::Path(path) => {
185 // FIXME use correct resolver for the surrounding expression 186 // FIXME use correct resolver for the surrounding expression
@@ -193,7 +194,7 @@ impl<'a> InferenceContext<'a> {
193 BindingMode::convert(*mode) 194 BindingMode::convert(*mode)
194 }; 195 };
195 let inner_ty = if let Some(subpat) = subpat { 196 let inner_ty = if let Some(subpat) = subpat {
196 self.infer_pat(*subpat, expected, default_bm) 197 self.infer_pat(*subpat, &expected, default_bm)
197 } else { 198 } else {
198 expected.clone() 199 expected.clone()
199 }; 200 };
@@ -206,7 +207,6 @@ impl<'a> InferenceContext<'a> {
206 } 207 }
207 BindingMode::Move => inner_ty.clone(), 208 BindingMode::Move => inner_ty.clone(),
208 }; 209 };
209 let bound_ty = self.resolve_ty_as_possible(bound_ty);
210 self.write_pat_ty(pat, bound_ty); 210 self.write_pat_ty(pat, bound_ty);
211 return inner_ty; 211 return inner_ty;
212 } 212 }
@@ -265,13 +265,12 @@ impl<'a> InferenceContext<'a> {
265 }; 265 };
266 // use a new type variable if we got error type here 266 // use a new type variable if we got error type here
267 let ty = self.insert_type_vars_shallow(ty); 267 let ty = self.insert_type_vars_shallow(ty);
268 if !self.unify(&ty, expected) { 268 if !self.unify(&ty, &expected) {
269 self.result.type_mismatches.insert( 269 self.result.type_mismatches.insert(
270 pat.into(), 270 pat.into(),
271 TypeMismatch { expected: expected.clone(), actual: ty.clone() }, 271 TypeMismatch { expected: expected.clone(), actual: ty.clone() },
272 ); 272 );
273 } 273 }
274 let ty = self.resolve_ty_as_possible(ty);
275 self.write_pat_ty(pat, ty.clone()); 274 self.write_pat_ty(pat, ty.clone());
276 ty 275 ty
277 } 276 }
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 495282eba..14c99eafd 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -65,7 +65,6 @@ impl<'a> InferenceContext<'a> {
65 let typable: ValueTyDefId = match value { 65 let typable: ValueTyDefId = match value {
66 ValueNs::LocalBinding(pat) => { 66 ValueNs::LocalBinding(pat) => {
67 let ty = self.result.type_of_pat.get(pat)?.clone(); 67 let ty = self.result.type_of_pat.get(pat)?.clone();
68 let ty = self.resolve_ty_as_possible(ty);
69 return Some(ty); 68 return Some(ty);
70 } 69 }
71 ValueNs::FunctionId(it) => it.into(), 70 ValueNs::FunctionId(it) => it.into(),
@@ -218,14 +217,14 @@ impl<'a> InferenceContext<'a> {
218 return Some(result); 217 return Some(result);
219 } 218 }
220 219
221 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); 220 let canonical_ty = self.canonicalize(ty.clone());
222 let krate = self.resolver.krate()?; 221 let krate = self.resolver.krate()?;
223 let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast()); 222 let traits_in_scope = self.resolver.traits_in_scope(self.db.upcast());
224 223
225 method_resolution::iterate_method_candidates( 224 method_resolution::iterate_method_candidates(
226 &canonical_ty.value, 225 &canonical_ty.value,
227 self.db, 226 self.db,
228 self.trait_env.clone(), 227 self.table.trait_env.clone(),
229 krate, 228 krate,
230 &traits_in_scope, 229 &traits_in_scope,
231 None, 230 None,
@@ -275,6 +274,7 @@ impl<'a> InferenceContext<'a> {
275 name: &Name, 274 name: &Name,
276 id: ExprOrPatId, 275 id: ExprOrPatId,
277 ) -> Option<(ValueNs, Option<Substitution>)> { 276 ) -> Option<(ValueNs, Option<Substitution>)> {
277 let ty = self.resolve_ty_shallow(ty);
278 let (enum_id, subst) = match ty.as_adt() { 278 let (enum_id, subst) = match ty.as_adt() {
279 Some((AdtId::EnumId(e), subst)) => (e, subst), 279 Some((AdtId::EnumId(e), subst)) => (e, subst),
280 _ => return None, 280 _ => return None,
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index d8e0b4320..21d3fb54e 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -1,177 +1,95 @@
1//! Unification and canonicalization logic. 1//! Unification and canonicalization logic.
2 2
3use std::borrow::Cow; 3use std::{fmt, mem, sync::Arc};
4 4
5use chalk_ir::{ 5use chalk_ir::{
6 cast::Cast, fold::Fold, interner::HasInterner, FloatTy, IntTy, TyVariableKind, UniverseIndex, 6 cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, TyVariableKind,
7 VariableKind, 7 UniverseIndex,
8}; 8};
9use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 9use chalk_solve::infer::ParameterEnaVariableExt;
10use ena::unify::UnifyKey;
10 11
11use super::{DomainGoal, InferenceContext}; 12use super::{InferOk, InferResult, InferenceContext, TypeError};
12use crate::{ 13use crate::{
13 fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, 14 db::HirDatabase, fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical,
14 DebruijnIndex, FnPointer, FnSubst, InEnvironment, InferenceVar, Interner, Scalar, Substitution, 15 DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar, Interner, ProjectionTy,
15 Ty, TyExt, TyKind, WhereClause, 16 Scalar, Solution, Substitution, TraitEnvironment, Ty, TyKind, VariableKind,
16}; 17};
17 18
18impl<'a> InferenceContext<'a> { 19impl<'a> InferenceContext<'a> {
19 pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b> 20 pub(super) fn canonicalize<T: Fold<Interner> + HasInterner<Interner = Interner>>(
21 &mut self,
22 t: T,
23 ) -> Canonicalized<T::Result>
20 where 24 where
21 'a: 'b, 25 T::Result: HasInterner<Interner = Interner>,
22 { 26 {
23 Canonicalizer { ctx: self, free_vars: Vec::new(), var_stack: Vec::new() } 27 // try to resolve obligations before canonicalizing, since this might
28 // result in new knowledge about variables
29 self.resolve_obligations_as_possible();
30 self.table.canonicalize(t)
24 } 31 }
25} 32}
26 33
27pub(super) struct Canonicalizer<'a, 'b> 34#[derive(Debug, Clone)]
28where
29 'a: 'b,
30{
31 ctx: &'b mut InferenceContext<'a>,
32 free_vars: Vec<(InferenceVar, TyVariableKind)>,
33 /// A stack of type variables that is used to detect recursive types (which
34 /// are an error, but we need to protect against them to avoid stack
35 /// overflows).
36 var_stack: Vec<TypeVarId>,
37}
38
39#[derive(Debug)]
40pub(super) struct Canonicalized<T> 35pub(super) struct Canonicalized<T>
41where 36where
42 T: HasInterner<Interner = Interner>, 37 T: HasInterner<Interner = Interner>,
43{ 38{
44 pub(super) value: Canonical<T>, 39 pub(super) value: Canonical<T>,
45 free_vars: Vec<(InferenceVar, TyVariableKind)>, 40 free_vars: Vec<GenericArg>,
46}
47
48impl<'a, 'b> Canonicalizer<'a, 'b> {
49 fn add(&mut self, free_var: InferenceVar, kind: TyVariableKind) -> usize {
50 self.free_vars.iter().position(|&(v, _)| v == free_var).unwrap_or_else(|| {
51 let next_index = self.free_vars.len();
52 self.free_vars.push((free_var, kind));
53 next_index
54 })
55 }
56
57 fn do_canonicalize<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
58 &mut self,
59 t: T,
60 binders: DebruijnIndex,
61 ) -> T {
62 fold_tys(
63 t,
64 |ty, binders| match ty.kind(&Interner) {
65 &TyKind::InferenceVar(var, kind) => {
66 let inner = from_inference_var(var);
67 if self.var_stack.contains(&inner) {
68 // recursive type
69 return self.ctx.table.type_variable_table.fallback_value(var, kind);
70 }
71 if let Some(known_ty) =
72 self.ctx.table.var_unification_table.inlined_probe_value(inner).known()
73 {
74 self.var_stack.push(inner);
75 let result = self.do_canonicalize(known_ty.clone(), binders);
76 self.var_stack.pop();
77 result
78 } else {
79 let root = self.ctx.table.var_unification_table.find(inner);
80 let position = self.add(to_inference_var(root), kind);
81 TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner)
82 }
83 }
84 _ => ty,
85 },
86 binders,
87 )
88 }
89
90 fn into_canonicalized<T: HasInterner<Interner = Interner>>(
91 self,
92 result: T,
93 ) -> Canonicalized<T> {
94 let kinds = self
95 .free_vars
96 .iter()
97 .map(|&(_, k)| chalk_ir::WithKind::new(VariableKind::Ty(k), UniverseIndex::ROOT));
98 Canonicalized {
99 value: Canonical {
100 value: result,
101 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
102 },
103 free_vars: self.free_vars,
104 }
105 }
106
107 pub(crate) fn canonicalize_ty(mut self, ty: Ty) -> Canonicalized<Ty> {
108 let result = self.do_canonicalize(ty, DebruijnIndex::INNERMOST);
109 self.into_canonicalized(result)
110 }
111
112 pub(crate) fn canonicalize_obligation(
113 mut self,
114 obligation: InEnvironment<DomainGoal>,
115 ) -> Canonicalized<InEnvironment<DomainGoal>> {
116 let result = match obligation.goal {
117 DomainGoal::Holds(wc) => {
118 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST))
119 }
120 _ => unimplemented!(),
121 };
122 self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment })
123 }
124} 41}
125 42
126impl<T: HasInterner<Interner = Interner>> Canonicalized<T> { 43impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
127 pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty { 44 pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty {
128 crate::fold_free_vars(ty, |bound, _binders| { 45 chalk_ir::Substitute::apply(&self.free_vars, ty, &Interner)
129 let (v, k) = self.free_vars[bound.index];
130 TyKind::InferenceVar(v, k).intern(&Interner)
131 })
132 } 46 }
133 47
134 pub(super) fn apply_solution( 48 pub(super) fn apply_solution(
135 &self, 49 &self,
136 ctx: &mut InferenceContext<'_>, 50 ctx: &mut InferenceTable,
137 solution: Canonical<Substitution>, 51 solution: Canonical<Substitution>,
138 ) { 52 ) {
139 // the solution may contain new variables, which we need to convert to new inference vars 53 // the solution may contain new variables, which we need to convert to new inference vars
140 let new_vars = Substitution::from_iter( 54 let new_vars = Substitution::from_iter(
141 &Interner, 55 &Interner,
142 solution.binders.iter(&Interner).map(|k| match k.kind { 56 solution.binders.iter(&Interner).map(|k| match k.kind {
143 VariableKind::Ty(TyVariableKind::General) => { 57 VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(&Interner),
144 ctx.table.new_type_var().cast(&Interner) 58 VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(&Interner),
145 } 59 VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(&Interner),
146 VariableKind::Ty(TyVariableKind::Integer) => {
147 ctx.table.new_integer_var().cast(&Interner)
148 }
149 VariableKind::Ty(TyVariableKind::Float) => {
150 ctx.table.new_float_var().cast(&Interner)
151 }
152 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere 60 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
153 VariableKind::Lifetime => static_lifetime().cast(&Interner), 61 VariableKind::Lifetime => static_lifetime().cast(&Interner),
154 _ => panic!("const variable in solution"), 62 _ => panic!("const variable in solution"),
155 }), 63 }),
156 ); 64 );
157 for (i, ty) in solution.value.iter(&Interner).enumerate() { 65 for (i, v) in solution.value.iter(&Interner).enumerate() {
158 let (v, k) = self.free_vars[i]; 66 let var = self.free_vars[i].clone();
159 // eagerly replace projections in the type; we may be getting types 67 if let Some(ty) = v.ty(&Interner) {
160 // e.g. from where clauses where this hasn't happened yet 68 // eagerly replace projections in the type; we may be getting types
161 let ty = ctx.normalize_associated_types_in( 69 // e.g. from where clauses where this hasn't happened yet
162 new_vars.apply(ty.assert_ty_ref(&Interner).clone(), &Interner), 70 let ty = ctx.normalize_associated_types_in(new_vars.apply(ty.clone(), &Interner));
163 ); 71 ctx.unify(var.assert_ty_ref(&Interner), &ty);
164 ctx.table.unify(&TyKind::InferenceVar(v, k).intern(&Interner), &ty); 72 } else {
73 let _ = ctx.try_unify(&var, &new_vars.apply(v.clone(), &Interner));
74 }
165 } 75 }
166 } 76 }
167} 77}
168 78
169pub fn could_unify(t1: &Ty, t2: &Ty) -> bool { 79pub fn could_unify(
170 InferenceTable::new().unify(t1, t2) 80 db: &dyn HirDatabase,
81 env: Arc<TraitEnvironment>,
82 tys: &Canonical<(Ty, Ty)>,
83) -> bool {
84 unify(db, env, tys).is_some()
171} 85}
172 86
173pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { 87pub(crate) fn unify(
174 let mut table = InferenceTable::new(); 88 db: &dyn HirDatabase,
89 env: Arc<TraitEnvironment>,
90 tys: &Canonical<(Ty, Ty)>,
91) -> Option<Substitution> {
92 let mut table = InferenceTable::new(db, env);
175 let vars = Substitution::from_iter( 93 let vars = Substitution::from_iter(
176 &Interner, 94 &Interner,
177 tys.binders 95 tys.binders
@@ -187,77 +105,151 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
187 } 105 }
188 // default any type vars that weren't unified back to their original bound vars 106 // default any type vars that weren't unified back to their original bound vars
189 // (kind of hacky) 107 // (kind of hacky)
190 for (i, var) in vars.iter(&Interner).enumerate() { 108 let find_var = |iv| {
191 let var = var.assert_ty_ref(&Interner); 109 vars.iter(&Interner).position(|v| match v.interned() {
192 if &*table.resolve_ty_shallow(var) == var { 110 chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(&Interner),
193 table.unify( 111 chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(&Interner),
194 var, 112 chalk_ir::GenericArgData::Const(c) => c.inference_var(&Interner),
195 &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i)).intern(&Interner), 113 } == Some(iv))
196 ); 114 };
197 } 115 let fallback = |iv, kind, default, binder| match kind {
198 } 116 chalk_ir::VariableKind::Ty(_ty_kind) => find_var(iv)
117 .map_or(default, |i| BoundVar::new(binder, i).to_ty(&Interner).cast(&Interner)),
118 chalk_ir::VariableKind::Lifetime => find_var(iv)
119 .map_or(default, |i| BoundVar::new(binder, i).to_lifetime(&Interner).cast(&Interner)),
120 chalk_ir::VariableKind::Const(ty) => find_var(iv)
121 .map_or(default, |i| BoundVar::new(binder, i).to_const(&Interner, ty).cast(&Interner)),
122 };
199 Some(Substitution::from_iter( 123 Some(Substitution::from_iter(
200 &Interner, 124 &Interner,
201 vars.iter(&Interner) 125 vars.iter(&Interner)
202 .map(|v| table.resolve_ty_completely(v.assert_ty_ref(&Interner).clone())), 126 .map(|v| table.resolve_with_fallback(v.assert_ty_ref(&Interner).clone(), fallback)),
203 )) 127 ))
204} 128}
205 129
206#[derive(Clone, Debug)] 130#[derive(Copy, Clone, Debug)]
207pub(super) struct TypeVariableTable { 131pub(crate) struct TypeVariableData {
208 inner: Vec<TypeVariableData>, 132 diverging: bool,
209} 133}
210 134
211impl TypeVariableTable { 135type ChalkInferenceTable = chalk_solve::infer::InferenceTable<Interner>;
212 fn push(&mut self, data: TypeVariableData) { 136
213 self.inner.push(data); 137#[derive(Clone)]
138pub(crate) struct InferenceTable<'a> {
139 pub(crate) db: &'a dyn HirDatabase,
140 pub(crate) trait_env: Arc<TraitEnvironment>,
141 var_unification_table: ChalkInferenceTable,
142 type_variable_table: Vec<TypeVariableData>,
143 pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
144}
145
146impl<'a> InferenceTable<'a> {
147 pub(crate) fn new(db: &'a dyn HirDatabase, trait_env: Arc<TraitEnvironment>) -> Self {
148 InferenceTable {
149 db,
150 trait_env,
151 var_unification_table: ChalkInferenceTable::new(),
152 type_variable_table: Vec::new(),
153 pending_obligations: Vec::new(),
154 }
214 } 155 }
215 156
216 pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { 157 /// Chalk doesn't know about the `diverging` flag, so when it unifies two
217 self.inner[from_inference_var(iv).0 as usize].diverging = diverging; 158 /// type variables of which one is diverging, the chosen root might not be
159 /// diverging and we have no way of marking it as such at that time. This
160 /// function goes through all type variables and make sure their root is
161 /// marked as diverging if necessary, so that resolving them gives the right
162 /// result.
163 pub(super) fn propagate_diverging_flag(&mut self) {
164 for i in 0..self.type_variable_table.len() {
165 if !self.type_variable_table[i].diverging {
166 continue;
167 }
168 let v = InferenceVar::from(i as u32);
169 let root = self.var_unification_table.inference_var_root(v);
170 if let Some(data) = self.type_variable_table.get_mut(root.index() as usize) {
171 data.diverging = true;
172 }
173 }
218 } 174 }
219 175
220 fn is_diverging(&mut self, iv: InferenceVar) -> bool { 176 pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
221 self.inner[from_inference_var(iv).0 as usize].diverging 177 self.type_variable_table[iv.index() as usize].diverging = diverging;
222 } 178 }
223 179
224 fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { 180 fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
225 match kind { 181 match kind {
226 _ if self.inner[from_inference_var(iv).0 as usize].diverging => TyKind::Never, 182 _ if self
183 .type_variable_table
184 .get(iv.index() as usize)
185 .map_or(false, |data| data.diverging) =>
186 {
187 TyKind::Never
188 }
227 TyVariableKind::General => TyKind::Error, 189 TyVariableKind::General => TyKind::Error,
228 TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), 190 TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
229 TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), 191 TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
230 } 192 }
231 .intern(&Interner) 193 .intern(&Interner)
232 } 194 }
233}
234 195
235#[derive(Copy, Clone, Debug)] 196 pub(super) fn canonicalize<T: Fold<Interner> + HasInterner<Interner = Interner>>(
236pub(crate) struct TypeVariableData { 197 &mut self,
237 diverging: bool, 198 t: T,
238} 199 ) -> Canonicalized<T::Result>
200 where
201 T::Result: HasInterner<Interner = Interner>,
202 {
203 let result = self.var_unification_table.canonicalize(&Interner, t);
204 let free_vars = result
205 .free_vars
206 .into_iter()
207 .map(|free_var| free_var.to_generic_arg(&Interner))
208 .collect();
209 Canonicalized { value: result.quantified, free_vars }
210 }
211
212 /// Recurses through the given type, normalizing associated types mentioned
213 /// in it by replacing them by type variables and registering obligations to
214 /// resolve later. This should be done once for every type we get from some
215 /// type annotation (e.g. from a let type annotation, field type or function
216 /// call). `make_ty` handles this already, but e.g. for field types we need
217 /// to do it as well.
218 pub(super) fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
219 fold_tys(
220 ty,
221 |ty, _| match ty.kind(&Interner) {
222 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
223 self.normalize_projection_ty(proj_ty.clone())
224 }
225 _ => ty,
226 },
227 DebruijnIndex::INNERMOST,
228 )
229 }
239 230
240#[derive(Clone, Debug)] 231 pub(super) fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
241pub(crate) struct InferenceTable { 232 let var = self.new_type_var();
242 pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>, 233 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
243 pub(super) type_variable_table: TypeVariableTable, 234 let obligation = alias_eq.cast(&Interner);
244 pub(super) revision: u32, 235 self.register_obligation(obligation);
245} 236 var
237 }
246 238
247impl InferenceTable { 239 fn extend_type_variable_table(&mut self, to_index: usize) {
248 pub(crate) fn new() -> Self { 240 self.type_variable_table.extend(
249 InferenceTable { 241 (0..1 + to_index - self.type_variable_table.len())
250 var_unification_table: InPlaceUnificationTable::new(), 242 .map(|_| TypeVariableData { diverging: false }),
251 type_variable_table: TypeVariableTable { inner: Vec::new() }, 243 );
252 revision: 0,
253 }
254 } 244 }
255 245
256 fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty { 246 fn new_var(&mut self, kind: TyVariableKind, diverging: bool) -> Ty {
257 self.type_variable_table.push(TypeVariableData { diverging }); 247 let var = self.var_unification_table.new_variable(UniverseIndex::ROOT);
258 let key = self.var_unification_table.new_key(TypeVarValue::Unknown); 248 // Chalk might have created some type variables for its own purposes that we don't know about...
259 assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1); 249 self.extend_type_variable_table(var.index() as usize);
260 TyKind::InferenceVar(to_inference_var(key), kind).intern(&Interner) 250 assert_eq!(var.index() as usize, self.type_variable_table.len() - 1);
251 self.type_variable_table[var.index() as usize].diverging = diverging;
252 var.to_ty_with_kind(&Interner, kind)
261 } 253 }
262 254
263 pub(crate) fn new_type_var(&mut self) -> Ty { 255 pub(crate) fn new_type_var(&mut self) -> Ty {
@@ -276,350 +268,261 @@ impl InferenceTable {
276 self.new_var(TyVariableKind::General, true) 268 self.new_var(TyVariableKind::General, true)
277 } 269 }
278 270
279 pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { 271 pub(crate) fn resolve_with_fallback<T>(
280 self.resolve_ty_completely_inner(&mut Vec::new(), ty) 272 &mut self,
273 t: T,
274 fallback: impl Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
275 ) -> T::Result
276 where
277 T: HasInterner<Interner = Interner> + Fold<Interner>,
278 {
279 self.resolve_with_fallback_inner(&mut Vec::new(), t, &fallback)
281 } 280 }
282 281
283 pub(crate) fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty { 282 fn resolve_with_fallback_inner<T>(
284 self.resolve_ty_as_possible_inner(&mut Vec::new(), ty) 283 &mut self,
284 var_stack: &mut Vec<InferenceVar>,
285 t: T,
286 fallback: &impl Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg,
287 ) -> T::Result
288 where
289 T: HasInterner<Interner = Interner> + Fold<Interner>,
290 {
291 t.fold_with(
292 &mut resolve::Resolver { table: self, var_stack, fallback },
293 DebruijnIndex::INNERMOST,
294 )
295 .expect("fold failed unexpectedly")
285 } 296 }
286 297
287 pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 298 pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
288 self.unify_inner(ty1, ty2, 0) 299 self.resolve_with_fallback(ty, |_, _, d, _| d)
289 } 300 }
290 301
291 pub(crate) fn unify_substs( 302 /// Unify two types and register new trait goals that arise from that.
292 &mut self, 303 pub(crate) fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
293 substs1: &Substitution, 304 let result = if let Ok(r) = self.try_unify(ty1, ty2) {
294 substs2: &Substitution, 305 r
295 depth: usize, 306 } else {
296 ) -> bool { 307 return false;
297 substs1.iter(&Interner).zip(substs2.iter(&Interner)).all(|(t1, t2)| { 308 };
298 self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth) 309 self.register_infer_ok(result);
299 }) 310 true
300 } 311 }
301 312
302 fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { 313 /// Unify two types and return new trait goals arising from it, so the
303 if depth > 1000 { 314 /// caller needs to deal with them.
304 // prevent stackoverflows 315 pub(crate) fn try_unify<T: Zip<Interner>>(&mut self, t1: &T, t2: &T) -> InferResult {
305 panic!("infinite recursion in unification"); 316 match self.var_unification_table.relate(
306 } 317 &Interner,
307 if ty1 == ty2 { 318 &self.db,
308 return true; 319 &self.trait_env.env,
309 } 320 chalk_ir::Variance::Invariant,
310 // try to resolve type vars first 321 t1,
311 let ty1 = self.resolve_ty_shallow(ty1); 322 t2,
312 let ty2 = self.resolve_ty_shallow(ty2); 323 ) {
313 if ty1.equals_ctor(&ty2) { 324 Ok(result) => Ok(InferOk { goals: result.goals }),
314 match (ty1.kind(&Interner), ty2.kind(&Interner)) { 325 Err(chalk_ir::NoSolution) => Err(TypeError),
315 (TyKind::Adt(_, substs1), TyKind::Adt(_, substs2))
316 | (TyKind::FnDef(_, substs1), TyKind::FnDef(_, substs2))
317 | (
318 TyKind::Function(FnPointer { substitution: FnSubst(substs1), .. }),
319 TyKind::Function(FnPointer { substitution: FnSubst(substs2), .. }),
320 )
321 | (TyKind::Tuple(_, substs1), TyKind::Tuple(_, substs2))
322 | (TyKind::OpaqueType(_, substs1), TyKind::OpaqueType(_, substs2))
323 | (TyKind::AssociatedType(_, substs1), TyKind::AssociatedType(_, substs2))
324 | (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) => {
325 self.unify_substs(substs1, substs2, depth + 1)
326 }
327 (TyKind::Array(ty1, c1), TyKind::Array(ty2, c2)) if c1 == c2 => {
328 self.unify_inner(ty1, ty2, depth + 1)
329 }
330 (TyKind::Ref(_, _, ty1), TyKind::Ref(_, _, ty2))
331 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2))
332 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1),
333 _ => true, /* we checked equals_ctor already */
334 }
335 } else if let (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) =
336 (ty1.kind(&Interner), ty2.kind(&Interner))
337 {
338 self.unify_substs(substs1, substs2, depth + 1)
339 } else {
340 self.unify_inner_trivial(&ty1, &ty2, depth)
341 } 326 }
342 } 327 }
343 328
344 pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { 329 /// If `ty` is a type variable with known type, returns that type;
345 match (ty1.kind(&Interner), ty2.kind(&Interner)) { 330 /// otherwise, return ty.
346 (TyKind::Error, _) | (_, TyKind::Error) => true, 331 pub(crate) fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
332 self.var_unification_table.normalize_ty_shallow(&Interner, ty).unwrap_or_else(|| ty.clone())
333 }
347 334
348 (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true, 335 pub(crate) fn register_obligation(&mut self, goal: Goal) {
336 let in_env = InEnvironment::new(&self.trait_env.env, goal);
337 self.register_obligation_in_env(in_env)
338 }
349 339
350 (TyKind::Dyn(dyn1), TyKind::Dyn(dyn2)) 340 fn register_obligation_in_env(&mut self, goal: InEnvironment<Goal>) {
351 if dyn1.bounds.skip_binders().interned().len() 341 let canonicalized = self.canonicalize(goal);
352 == dyn2.bounds.skip_binders().interned().len() => 342 if !self.try_resolve_obligation(&canonicalized) {
353 { 343 self.pending_obligations.push(canonicalized);
354 for (pred1, pred2) in dyn1 344 }
355 .bounds 345 }
356 .skip_binders()
357 .interned()
358 .iter()
359 .zip(dyn2.bounds.skip_binders().interned().iter())
360 {
361 if !self.unify_preds(pred1.skip_binders(), pred2.skip_binders(), depth + 1) {
362 return false;
363 }
364 }
365 true
366 }
367 346
368 ( 347 pub(crate) fn register_infer_ok(&mut self, infer_ok: InferOk) {
369 TyKind::InferenceVar(tv1, TyVariableKind::General), 348 infer_ok.goals.into_iter().for_each(|goal| self.register_obligation_in_env(goal));
370 TyKind::InferenceVar(tv2, TyVariableKind::General), 349 }
371 )
372 | (
373 TyKind::InferenceVar(tv1, TyVariableKind::Integer),
374 TyKind::InferenceVar(tv2, TyVariableKind::Integer),
375 )
376 | (
377 TyKind::InferenceVar(tv1, TyVariableKind::Float),
378 TyKind::InferenceVar(tv2, TyVariableKind::Float),
379 ) if self.type_variable_table.is_diverging(*tv1)
380 == self.type_variable_table.is_diverging(*tv2) =>
381 {
382 // both type vars are unknown since we tried to resolve them
383 if !self
384 .var_unification_table
385 .unioned(from_inference_var(*tv1), from_inference_var(*tv2))
386 {
387 self.var_unification_table
388 .union(from_inference_var(*tv1), from_inference_var(*tv2));
389 self.revision += 1;
390 }
391 true
392 }
393 350
394 // The order of MaybeNeverTypeVar matters here. 351 pub(crate) fn resolve_obligations_as_possible(&mut self) {
395 // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar. 352 let _span = profile::span("resolve_obligations_as_possible");
396 // Unifying MaybeNeverTypeVar and other concrete type will let the former become it. 353 let mut changed = true;
397 (TyKind::InferenceVar(tv, TyVariableKind::General), other) 354 let mut obligations = Vec::new();
398 | (other, TyKind::InferenceVar(tv, TyVariableKind::General)) 355 while changed {
399 | ( 356 changed = false;
400 TyKind::InferenceVar(tv, TyVariableKind::Integer), 357 mem::swap(&mut self.pending_obligations, &mut obligations);
401 other @ TyKind::Scalar(Scalar::Int(_)), 358 for canonicalized in obligations.drain(..) {
402 ) 359 if !self.check_changed(&canonicalized) {
403 | ( 360 self.pending_obligations.push(canonicalized);
404 other @ TyKind::Scalar(Scalar::Int(_)), 361 continue;
405 TyKind::InferenceVar(tv, TyVariableKind::Integer), 362 }
406 ) 363 changed = true;
407 | ( 364 let uncanonical = chalk_ir::Substitute::apply(
408 TyKind::InferenceVar(tv, TyVariableKind::Integer), 365 &canonicalized.free_vars,
409 other @ TyKind::Scalar(Scalar::Uint(_)), 366 canonicalized.value.value,
410 ) 367 &Interner,
411 | (
412 other @ TyKind::Scalar(Scalar::Uint(_)),
413 TyKind::InferenceVar(tv, TyVariableKind::Integer),
414 )
415 | (
416 TyKind::InferenceVar(tv, TyVariableKind::Float),
417 other @ TyKind::Scalar(Scalar::Float(_)),
418 )
419 | (
420 other @ TyKind::Scalar(Scalar::Float(_)),
421 TyKind::InferenceVar(tv, TyVariableKind::Float),
422 ) => {
423 // the type var is unknown since we tried to resolve it
424 self.var_unification_table.union_value(
425 from_inference_var(*tv),
426 TypeVarValue::Known(other.clone().intern(&Interner)),
427 ); 368 );
428 self.revision += 1; 369 self.register_obligation_in_env(uncanonical);
429 true
430 } 370 }
431
432 _ => false,
433 } 371 }
434 } 372 }
435 373
436 fn unify_preds(&mut self, pred1: &WhereClause, pred2: &WhereClause, depth: usize) -> bool { 374 /// This checks whether any of the free variables in the `canonicalized`
437 match (pred1, pred2) { 375 /// have changed (either been unified with another variable, or with a
438 (WhereClause::Implemented(tr1), WhereClause::Implemented(tr2)) 376 /// value). If this is not the case, we don't need to try to solve the goal
439 if tr1.trait_id == tr2.trait_id => 377 /// again -- it'll give the same result as last time.
440 { 378 fn check_changed(&mut self, canonicalized: &Canonicalized<InEnvironment<Goal>>) -> bool {
441 self.unify_substs(&tr1.substitution, &tr2.substitution, depth + 1) 379 canonicalized.free_vars.iter().any(|var| {
380 let iv = match var.data(&Interner) {
381 chalk_ir::GenericArgData::Ty(ty) => ty.inference_var(&Interner),
382 chalk_ir::GenericArgData::Lifetime(lt) => lt.inference_var(&Interner),
383 chalk_ir::GenericArgData::Const(c) => c.inference_var(&Interner),
442 } 384 }
443 ( 385 .expect("free var is not inference var");
444 WhereClause::AliasEq(AliasEq { alias: alias1, ty: ty1 }), 386 if self.var_unification_table.probe_var(iv).is_some() {
445 WhereClause::AliasEq(AliasEq { alias: alias2, ty: ty2 }), 387 return true;
446 ) => {
447 let (substitution1, substitution2) = match (alias1, alias2) {
448 (AliasTy::Projection(projection_ty1), AliasTy::Projection(projection_ty2))
449 if projection_ty1.associated_ty_id == projection_ty2.associated_ty_id =>
450 {
451 (&projection_ty1.substitution, &projection_ty2.substitution)
452 }
453 (AliasTy::Opaque(opaque1), AliasTy::Opaque(opaque2))
454 if opaque1.opaque_ty_id == opaque2.opaque_ty_id =>
455 {
456 (&opaque1.substitution, &opaque2.substitution)
457 }
458 _ => return false,
459 };
460 self.unify_substs(&substitution1, &substitution2, depth + 1)
461 && self.unify_inner(&ty1, &ty2, depth + 1)
462 } 388 }
463 _ => false, 389 let root = self.var_unification_table.inference_var_root(iv);
464 } 390 iv != root
391 })
465 } 392 }
466 393
467 /// If `ty` is a type variable with known type, returns that type; 394 fn try_resolve_obligation(
468 /// otherwise, return ty. 395 &mut self,
469 pub(crate) fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { 396 canonicalized: &Canonicalized<InEnvironment<Goal>>,
470 let mut ty = Cow::Borrowed(ty); 397 ) -> bool {
471 // The type variable could resolve to a int/float variable. Hence try 398 let solution = self.db.trait_solve(self.trait_env.krate, canonicalized.value.clone());
472 // resolving up to three times; each type of variable shouldn't occur 399
473 // more than once 400 match solution {
474 for i in 0..3 { 401 Some(Solution::Unique(canonical_subst)) => {
475 if i > 0 { 402 canonicalized.apply_solution(
476 cov_mark::hit!(type_var_resolves_to_int_var); 403 self,
404 Canonical {
405 binders: canonical_subst.binders,
406 // FIXME: handle constraints
407 value: canonical_subst.value.subst,
408 },
409 );
410 true
477 } 411 }
478 match ty.kind(&Interner) { 412 Some(Solution::Ambig(Guidance::Definite(substs))) => {
479 TyKind::InferenceVar(tv, _) => { 413 canonicalized.apply_solution(self, substs);
480 let inner = from_inference_var(*tv); 414 false
481 match self.var_unification_table.inlined_probe_value(inner).known() { 415 }
482 Some(known_ty) => { 416 Some(_) => {
483 // The known_ty can't be a type var itself 417 // FIXME use this when trying to resolve everything at the end
484 ty = Cow::Owned(known_ty.clone()); 418 false
485 } 419 }
486 _ => return ty, 420 None => {
487 } 421 // FIXME obligation cannot be fulfilled => diagnostic
488 } 422 true
489 _ => return ty,
490 } 423 }
491 } 424 }
492 log::error!("Inference variable still not resolved: {:?}", ty);
493 ty
494 }
495
496 /// Resolves the type as far as currently possible, replacing type variables
497 /// by their known types. All types returned by the infer_* functions should
498 /// be resolved as far as possible, i.e. contain no type variables with
499 /// known type.
500 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
501 fold_tys(
502 ty,
503 |ty, _| match ty.kind(&Interner) {
504 &TyKind::InferenceVar(tv, kind) => {
505 let inner = from_inference_var(tv);
506 if tv_stack.contains(&inner) {
507 cov_mark::hit!(type_var_cycles_resolve_as_possible);
508 // recursive type
509 return self.type_variable_table.fallback_value(tv, kind);
510 }
511 if let Some(known_ty) =
512 self.var_unification_table.inlined_probe_value(inner).known()
513 {
514 // known_ty may contain other variables that are known by now
515 tv_stack.push(inner);
516 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
517 tv_stack.pop();
518 result
519 } else {
520 ty
521 }
522 }
523 _ => ty,
524 },
525 DebruijnIndex::INNERMOST,
526 )
527 }
528
529 /// Resolves the type completely; type variables without known type are
530 /// replaced by TyKind::Unknown.
531 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
532 fold_tys(
533 ty,
534 |ty, _| match ty.kind(&Interner) {
535 &TyKind::InferenceVar(tv, kind) => {
536 let inner = from_inference_var(tv);
537 if tv_stack.contains(&inner) {
538 cov_mark::hit!(type_var_cycles_resolve_completely);
539 // recursive type
540 return self.type_variable_table.fallback_value(tv, kind);
541 }
542 if let Some(known_ty) =
543 self.var_unification_table.inlined_probe_value(inner).known()
544 {
545 // known_ty may contain other variables that are known by now
546 tv_stack.push(inner);
547 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
548 tv_stack.pop();
549 result
550 } else {
551 self.type_variable_table.fallback_value(tv, kind)
552 }
553 }
554 _ => ty,
555 },
556 DebruijnIndex::INNERMOST,
557 )
558 } 425 }
559} 426}
560 427
561/// The ID of a type variable. 428impl<'a> fmt::Debug for InferenceTable<'a> {
562#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] 429 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
563pub(super) struct TypeVarId(pub(super) u32); 430 f.debug_struct("InferenceTable").field("num_vars", &self.type_variable_table.len()).finish()
564
565impl UnifyKey for TypeVarId {
566 type Value = TypeVarValue;
567
568 fn index(&self) -> u32 {
569 self.0
570 }
571
572 fn from_index(i: u32) -> Self {
573 TypeVarId(i)
574 } 431 }
575
576 fn tag() -> &'static str {
577 "TypeVarId"
578 }
579}
580
581fn from_inference_var(var: InferenceVar) -> TypeVarId {
582 TypeVarId(var.index())
583}
584
585fn to_inference_var(TypeVarId(index): TypeVarId) -> InferenceVar {
586 index.into()
587}
588
589/// The value of a type variable: either we already know the type, or we don't
590/// know it yet.
591#[derive(Clone, PartialEq, Eq, Debug)]
592pub(super) enum TypeVarValue {
593 Known(Ty),
594 Unknown,
595} 432}
596 433
597impl TypeVarValue { 434mod resolve {
598 fn known(&self) -> Option<&Ty> { 435 use super::InferenceTable;
599 match self { 436 use crate::{
600 TypeVarValue::Known(ty) => Some(ty), 437 ConcreteConst, Const, ConstData, ConstValue, DebruijnIndex, GenericArg, InferenceVar,
601 TypeVarValue::Unknown => None, 438 Interner, Ty, TyVariableKind, VariableKind,
439 };
440 use chalk_ir::{
441 cast::Cast,
442 fold::{Fold, Folder},
443 Fallible,
444 };
445 use hir_def::type_ref::ConstScalar;
446
447 pub(super) struct Resolver<'a, 'b, F> {
448 pub(super) table: &'a mut InferenceTable<'b>,
449 pub(super) var_stack: &'a mut Vec<InferenceVar>,
450 pub(super) fallback: F,
451 }
452 impl<'a, 'b, 'i, F> Folder<'i, Interner> for Resolver<'a, 'b, F>
453 where
454 F: Fn(InferenceVar, VariableKind, GenericArg, DebruijnIndex) -> GenericArg + 'i,
455 {
456 fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
457 self
602 } 458 }
603 }
604}
605
606impl UnifyValue for TypeVarValue {
607 type Error = NoError;
608 459
609 fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { 460 fn interner(&self) -> &'i Interner {
610 match (value1, value2) { 461 &Interner
611 // We should never equate two type variables, both of which have 462 }
612 // known types. Instead, we recursively equate those types.
613 (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!(
614 "equating two type variables, both of which have known types: {:?} and {:?}",
615 t1, t2
616 ),
617 463
618 // If one side is known, prefer that one. 464 fn fold_inference_ty(
619 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), 465 &mut self,
620 (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()), 466 var: InferenceVar,
467 kind: TyVariableKind,
468 outer_binder: DebruijnIndex,
469 ) -> Fallible<Ty> {
470 let var = self.table.var_unification_table.inference_var_root(var);
471 if self.var_stack.contains(&var) {
472 // recursive type
473 let default = self.table.fallback_value(var, kind).cast(&Interner);
474 return Ok((self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
475 .assert_ty_ref(&Interner)
476 .clone());
477 }
478 let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
479 // known_ty may contain other variables that are known by now
480 self.var_stack.push(var);
481 let result =
482 known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
483 self.var_stack.pop();
484 result.assert_ty_ref(&Interner).clone()
485 } else {
486 let default = self.table.fallback_value(var, kind).cast(&Interner);
487 (self.fallback)(var, VariableKind::Ty(kind), default, outer_binder)
488 .assert_ty_ref(&Interner)
489 .clone()
490 };
491 Ok(result)
492 }
621 493
622 (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown), 494 fn fold_inference_const(
495 &mut self,
496 ty: Ty,
497 var: InferenceVar,
498 outer_binder: DebruijnIndex,
499 ) -> Fallible<Const> {
500 let var = self.table.var_unification_table.inference_var_root(var);
501 let default = ConstData {
502 ty: ty.clone(),
503 value: ConstValue::Concrete(ConcreteConst { interned: ConstScalar::Unknown }),
504 }
505 .intern(&Interner)
506 .cast(&Interner);
507 if self.var_stack.contains(&var) {
508 // recursive
509 return Ok((self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
510 .assert_const_ref(&Interner)
511 .clone());
512 }
513 let result = if let Some(known_ty) = self.table.var_unification_table.probe_var(var) {
514 // known_ty may contain other variables that are known by now
515 self.var_stack.push(var);
516 let result =
517 known_ty.fold_with(self, outer_binder).expect("fold failed unexpectedly");
518 self.var_stack.pop();
519 result.assert_const_ref(&Interner).clone()
520 } else {
521 (self.fallback)(var, VariableKind::Const(ty), default, outer_binder)
522 .assert_const_ref(&Interner)
523 .clone()
524 };
525 Ok(result)
623 } 526 }
624 } 527 }
625} 528}
diff --git a/crates/hir_ty/src/interner.rs b/crates/hir_ty/src/interner.rs
index 7b4119747..29ffdd9b7 100644
--- a/crates/hir_ty/src/interner.rs
+++ b/crates/hir_ty/src/interner.rs
@@ -15,9 +15,15 @@ use std::{fmt, sync::Arc};
15#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] 15#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
16pub struct Interner; 16pub struct Interner;
17 17
18#[derive(PartialEq, Eq, Hash, Debug)] 18#[derive(PartialEq, Eq, Hash)]
19pub struct InternedWrapper<T>(T); 19pub struct InternedWrapper<T>(T);
20 20
21impl<T: fmt::Debug> fmt::Debug for InternedWrapper<T> {
22 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
23 fmt::Debug::fmt(&self.0, f)
24 }
25}
26
21impl<T> std::ops::Deref for InternedWrapper<T> { 27impl<T> std::ops::Deref for InternedWrapper<T> {
22 type Target = T; 28 type Target = T;
23 29
@@ -101,66 +107,65 @@ impl chalk_ir::interner::Interner for Interner {
101 opaque_ty: &chalk_ir::OpaqueTy<Interner>, 107 opaque_ty: &chalk_ir::OpaqueTy<Interner>,
102 fmt: &mut fmt::Formatter<'_>, 108 fmt: &mut fmt::Formatter<'_>,
103 ) -> Option<fmt::Result> { 109 ) -> Option<fmt::Result> {
104 tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt))) 110 Some(write!(fmt, "{:?}", opaque_ty.opaque_ty_id))
105 } 111 }
106 112
107 fn debug_opaque_ty_id( 113 fn debug_opaque_ty_id(
108 opaque_ty_id: chalk_ir::OpaqueTyId<Self>, 114 opaque_ty_id: chalk_ir::OpaqueTyId<Self>,
109 fmt: &mut fmt::Formatter<'_>, 115 fmt: &mut fmt::Formatter<'_>,
110 ) -> Option<fmt::Result> { 116 ) -> Option<fmt::Result> {
111 tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt))) 117 Some(fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish())
112 } 118 }
113 119
114 fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 120 fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
115 tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) 121 Some(write!(fmt, "{:?}", ty.data(&Interner)))
116 } 122 }
117 123
118 fn debug_lifetime( 124 fn debug_lifetime(
119 lifetime: &chalk_ir::Lifetime<Interner>, 125 lifetime: &chalk_ir::Lifetime<Interner>,
120 fmt: &mut fmt::Formatter<'_>, 126 fmt: &mut fmt::Formatter<'_>,
121 ) -> Option<fmt::Result> { 127 ) -> Option<fmt::Result> {
122 tls::with_current_program(|prog| Some(prog?.debug_lifetime(lifetime, fmt))) 128 Some(write!(fmt, "{:?}", lifetime.data(&Interner)))
123 } 129 }
124 130
125 fn debug_generic_arg( 131 fn debug_generic_arg(
126 parameter: &GenericArg, 132 parameter: &GenericArg,
127 fmt: &mut fmt::Formatter<'_>, 133 fmt: &mut fmt::Formatter<'_>,
128 ) -> Option<fmt::Result> { 134 ) -> Option<fmt::Result> {
129 tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) 135 Some(write!(fmt, "{:?}", parameter.data(&Interner).inner_debug()))
130 } 136 }
131 137
132 fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 138 fn debug_goal(goal: &Goal<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
133 tls::with_current_program(|prog| Some(prog?.debug_goal(goal, fmt))) 139 let goal_data = goal.data(&Interner);
140 Some(write!(fmt, "{:?}", goal_data))
134 } 141 }
135 142
136 fn debug_goals( 143 fn debug_goals(
137 goals: &chalk_ir::Goals<Interner>, 144 goals: &chalk_ir::Goals<Interner>,
138 fmt: &mut fmt::Formatter<'_>, 145 fmt: &mut fmt::Formatter<'_>,
139 ) -> Option<fmt::Result> { 146 ) -> Option<fmt::Result> {
140 tls::with_current_program(|prog| Some(prog?.debug_goals(goals, fmt))) 147 Some(write!(fmt, "{:?}", goals.debug(&Interner)))
141 } 148 }
142 149
143 fn debug_program_clause_implication( 150 fn debug_program_clause_implication(
144 pci: &chalk_ir::ProgramClauseImplication<Interner>, 151 pci: &chalk_ir::ProgramClauseImplication<Interner>,
145 fmt: &mut fmt::Formatter<'_>, 152 fmt: &mut fmt::Formatter<'_>,
146 ) -> Option<fmt::Result> { 153 ) -> Option<fmt::Result> {
147 tls::with_current_program(|prog| Some(prog?.debug_program_clause_implication(pci, fmt))) 154 Some(write!(fmt, "{:?}", pci.debug(&Interner)))
148 } 155 }
149 156
150 fn debug_substitution( 157 fn debug_substitution(
151 substitution: &chalk_ir::Substitution<Interner>, 158 substitution: &chalk_ir::Substitution<Interner>,
152 fmt: &mut fmt::Formatter<'_>, 159 fmt: &mut fmt::Formatter<'_>,
153 ) -> Option<fmt::Result> { 160 ) -> Option<fmt::Result> {
154 tls::with_current_program(|prog| Some(prog?.debug_substitution(substitution, fmt))) 161 Some(write!(fmt, "{:?}", substitution.debug(&Interner)))
155 } 162 }
156 163
157 fn debug_separator_trait_ref( 164 fn debug_separator_trait_ref(
158 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>, 165 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
159 fmt: &mut fmt::Formatter<'_>, 166 fmt: &mut fmt::Formatter<'_>,
160 ) -> Option<fmt::Result> { 167 ) -> Option<fmt::Result> {
161 tls::with_current_program(|prog| { 168 Some(write!(fmt, "{:?}", separator_trait_ref.debug(&Interner)))
162 Some(prog?.debug_separator_trait_ref(separator_trait_ref, fmt))
163 })
164 } 169 }
165 170
166 fn debug_fn_def_id( 171 fn debug_fn_def_id(
@@ -173,47 +178,43 @@ impl chalk_ir::interner::Interner for Interner {
173 constant: &chalk_ir::Const<Self>, 178 constant: &chalk_ir::Const<Self>,
174 fmt: &mut fmt::Formatter<'_>, 179 fmt: &mut fmt::Formatter<'_>,
175 ) -> Option<fmt::Result> { 180 ) -> Option<fmt::Result> {
176 tls::with_current_program(|prog| Some(prog?.debug_const(constant, fmt))) 181 Some(write!(fmt, "{:?}", constant.data(&Interner)))
177 } 182 }
178 fn debug_variable_kinds( 183 fn debug_variable_kinds(
179 variable_kinds: &chalk_ir::VariableKinds<Self>, 184 variable_kinds: &chalk_ir::VariableKinds<Self>,
180 fmt: &mut fmt::Formatter<'_>, 185 fmt: &mut fmt::Formatter<'_>,
181 ) -> Option<fmt::Result> { 186 ) -> Option<fmt::Result> {
182 tls::with_current_program(|prog| Some(prog?.debug_variable_kinds(variable_kinds, fmt))) 187 Some(write!(fmt, "{:?}", variable_kinds.as_slice(&Interner)))
183 } 188 }
184 fn debug_variable_kinds_with_angles( 189 fn debug_variable_kinds_with_angles(
185 variable_kinds: &chalk_ir::VariableKinds<Self>, 190 variable_kinds: &chalk_ir::VariableKinds<Self>,
186 fmt: &mut fmt::Formatter<'_>, 191 fmt: &mut fmt::Formatter<'_>,
187 ) -> Option<fmt::Result> { 192 ) -> Option<fmt::Result> {
188 tls::with_current_program(|prog| { 193 Some(write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner)))
189 Some(prog?.debug_variable_kinds_with_angles(variable_kinds, fmt))
190 })
191 } 194 }
192 fn debug_canonical_var_kinds( 195 fn debug_canonical_var_kinds(
193 canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Self>, 196 canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Self>,
194 fmt: &mut fmt::Formatter<'_>, 197 fmt: &mut fmt::Formatter<'_>,
195 ) -> Option<fmt::Result> { 198 ) -> Option<fmt::Result> {
196 tls::with_current_program(|prog| { 199 Some(write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner)))
197 Some(prog?.debug_canonical_var_kinds(canonical_var_kinds, fmt))
198 })
199 } 200 }
200 fn debug_program_clause( 201 fn debug_program_clause(
201 clause: &chalk_ir::ProgramClause<Self>, 202 clause: &chalk_ir::ProgramClause<Self>,
202 fmt: &mut fmt::Formatter<'_>, 203 fmt: &mut fmt::Formatter<'_>,
203 ) -> Option<fmt::Result> { 204 ) -> Option<fmt::Result> {
204 tls::with_current_program(|prog| Some(prog?.debug_program_clause(clause, fmt))) 205 Some(write!(fmt, "{:?}", clause.data(&Interner)))
205 } 206 }
206 fn debug_program_clauses( 207 fn debug_program_clauses(
207 clauses: &chalk_ir::ProgramClauses<Self>, 208 clauses: &chalk_ir::ProgramClauses<Self>,
208 fmt: &mut fmt::Formatter<'_>, 209 fmt: &mut fmt::Formatter<'_>,
209 ) -> Option<fmt::Result> { 210 ) -> Option<fmt::Result> {
210 tls::with_current_program(|prog| Some(prog?.debug_program_clauses(clauses, fmt))) 211 Some(write!(fmt, "{:?}", clauses.as_slice(&Interner)))
211 } 212 }
212 fn debug_quantified_where_clauses( 213 fn debug_quantified_where_clauses(
213 clauses: &chalk_ir::QuantifiedWhereClauses<Self>, 214 clauses: &chalk_ir::QuantifiedWhereClauses<Self>,
214 fmt: &mut fmt::Formatter<'_>, 215 fmt: &mut fmt::Formatter<'_>,
215 ) -> Option<fmt::Result> { 216 ) -> Option<fmt::Result> {
216 tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt))) 217 Some(write!(fmt, "{:?}", clauses.as_slice(&Interner)))
217 } 218 }
218 219
219 fn intern_ty(&self, kind: chalk_ir::TyKind<Self>) -> Self::InternedType { 220 fn intern_ty(&self, kind: chalk_ir::TyKind<Self>) -> Self::InternedType {
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 15b61bedc..72093d75a 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -43,8 +43,9 @@ use hir_def::{
43 type_ref::{ConstScalar, Rawness}, 43 type_ref::{ConstScalar, Rawness},
44 TypeParamId, 44 TypeParamId,
45}; 45};
46use stdx::always;
46 47
47use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; 48use crate::{db::HirDatabase, utils::generics};
48 49
49pub use autoderef::autoderef; 50pub use autoderef::autoderef;
50pub use builder::TyBuilder; 51pub use builder::TyBuilder;
@@ -113,6 +114,7 @@ pub type FnSig = chalk_ir::FnSig<Interner>;
113 114
114pub type InEnvironment<T> = chalk_ir::InEnvironment<T>; 115pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
115pub type DomainGoal = chalk_ir::DomainGoal<Interner>; 116pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
117pub type Goal = chalk_ir::Goal<Interner>;
116pub type AliasEq = chalk_ir::AliasEq<Interner>; 118pub type AliasEq = chalk_ir::AliasEq<Interner>;
117pub type Solution = chalk_solve::Solution<Interner>; 119pub type Solution = chalk_solve::Solution<Interner>;
118pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>; 120pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
@@ -167,6 +169,7 @@ pub fn make_canonical<T: HasInterner<Interner = Interner>>(
167 Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) } 169 Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
168} 170}
169 171
172// FIXME: get rid of this, just replace it by FnPointer
170/// A function signature as seen by type inference: Several parameter types and 173/// A function signature as seen by type inference: Several parameter types and
171/// one return type. 174/// one return type.
172#[derive(Clone, PartialEq, Eq, Debug)] 175#[derive(Clone, PartialEq, Eq, Debug)]
@@ -203,6 +206,17 @@ impl CallableSig {
203 } 206 }
204 } 207 }
205 208
209 pub fn to_fn_ptr(&self) -> FnPointer {
210 FnPointer {
211 num_binders: 0,
212 sig: FnSig { abi: (), safety: Safety::Safe, variadic: self.is_varargs },
213 substitution: FnSubst(Substitution::from_iter(
214 &Interner,
215 self.params_and_return.iter().cloned(),
216 )),
217 }
218 }
219
206 pub fn params(&self) -> &[Ty] { 220 pub fn params(&self) -> &[Ty] {
207 &self.params_and_return[0..self.params_and_return.len() - 1] 221 &self.params_and_return[0..self.params_and_return.len() - 1]
208 } 222 }
@@ -314,3 +328,58 @@ pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
314 } 328 }
315 t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly") 329 t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
316} 330}
331
332pub fn replace_errors_with_variables<T>(t: T) -> Canonical<T::Result>
333where
334 T: HasInterner<Interner = Interner> + Fold<Interner>,
335 T::Result: HasInterner<Interner = Interner>,
336{
337 use chalk_ir::{
338 fold::{Folder, SuperFold},
339 Fallible,
340 };
341 struct ErrorReplacer {
342 vars: usize,
343 }
344 impl<'i> Folder<'i, Interner> for ErrorReplacer {
345 fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
346 self
347 }
348
349 fn interner(&self) -> &'i Interner {
350 &Interner
351 }
352
353 fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
354 if let TyKind::Error = ty.kind(&Interner) {
355 let index = self.vars;
356 self.vars += 1;
357 Ok(TyKind::BoundVar(BoundVar::new(outer_binder, index)).intern(&Interner))
358 } else {
359 let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
360 Ok(ty)
361 }
362 }
363
364 fn fold_inference_ty(
365 &mut self,
366 var: InferenceVar,
367 kind: TyVariableKind,
368 _outer_binder: DebruijnIndex,
369 ) -> Fallible<Ty> {
370 always!(false);
371 Ok(TyKind::InferenceVar(var, kind).intern(&Interner))
372 }
373 }
374 let mut error_replacer = ErrorReplacer { vars: 0 };
375 let value = t
376 .fold_with(&mut error_replacer, DebruijnIndex::INNERMOST)
377 .expect("fold failed unexpectedly");
378 let kinds = (0..error_replacer.vars).map(|_| {
379 chalk_ir::CanonicalVarKind::new(
380 chalk_ir::VariableKind::Ty(TyVariableKind::General),
381 chalk_ir::UniverseIndex::ROOT,
382 )
383 });
384 Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
385}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index bd8bb6028..8a375b973 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -1035,9 +1035,11 @@ pub(crate) fn trait_environment_query(
1035 clauses.push(program_clause.into_from_env_clause(&Interner)); 1035 clauses.push(program_clause.into_from_env_clause(&Interner));
1036 } 1036 }
1037 1037
1038 let krate = def.module(db.upcast()).krate();
1039
1038 let env = chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses); 1040 let env = chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses);
1039 1041
1040 Arc::new(TraitEnvironment { traits_from_clauses: traits_in_scope, env }) 1042 Arc::new(TraitEnvironment { krate, traits_from_clauses: traits_in_scope, env })
1041} 1043}
1042 1044
1043/// Resolve the where clause(s) of an item with generics. 1045/// Resolve the where clause(s) of an item with generics.
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 48bbcfd9f..08e385a42 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -577,6 +577,7 @@ fn iterate_method_candidates_by_receiver(
577 if iterate_inherent_methods( 577 if iterate_inherent_methods(
578 self_ty, 578 self_ty,
579 db, 579 db,
580 env.clone(),
580 name, 581 name,
581 Some(receiver_ty), 582 Some(receiver_ty),
582 krate, 583 krate,
@@ -613,8 +614,16 @@ fn iterate_method_candidates_for_self_ty(
613 name: Option<&Name>, 614 name: Option<&Name>,
614 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 615 mut callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
615) -> bool { 616) -> bool {
616 if iterate_inherent_methods(self_ty, db, name, None, krate, visible_from_module, &mut callback) 617 if iterate_inherent_methods(
617 { 618 self_ty,
619 db,
620 env.clone(),
621 name,
622 None,
623 krate,
624 visible_from_module,
625 &mut callback,
626 ) {
618 return true; 627 return true;
619 } 628 }
620 iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback) 629 iterate_trait_method_candidates(self_ty, db, env, krate, traits_in_scope, name, None, callback)
@@ -653,12 +662,12 @@ fn iterate_trait_method_candidates(
653 for (_name, item) in data.items.iter() { 662 for (_name, item) in data.items.iter() {
654 // Don't pass a `visible_from_module` down to `is_valid_candidate`, 663 // Don't pass a `visible_from_module` down to `is_valid_candidate`,
655 // since only inherent methods should be included into visibility checking. 664 // since only inherent methods should be included into visibility checking.
656 if !is_valid_candidate(db, name, receiver_ty, *item, self_ty, None) { 665 if !is_valid_candidate(db, env.clone(), name, receiver_ty, *item, self_ty, None) {
657 continue; 666 continue;
658 } 667 }
659 if !known_implemented { 668 if !known_implemented {
660 let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone()); 669 let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone());
661 if db.trait_solve(krate, goal).is_none() { 670 if db.trait_solve(krate, goal.cast(&Interner)).is_none() {
662 continue 'traits; 671 continue 'traits;
663 } 672 }
664 } 673 }
@@ -675,6 +684,7 @@ fn iterate_trait_method_candidates(
675fn iterate_inherent_methods( 684fn iterate_inherent_methods(
676 self_ty: &Canonical<Ty>, 685 self_ty: &Canonical<Ty>,
677 db: &dyn HirDatabase, 686 db: &dyn HirDatabase,
687 env: Arc<TraitEnvironment>,
678 name: Option<&Name>, 688 name: Option<&Name>,
679 receiver_ty: Option<&Canonical<Ty>>, 689 receiver_ty: Option<&Canonical<Ty>>,
680 krate: CrateId, 690 krate: CrateId,
@@ -690,14 +700,24 @@ fn iterate_inherent_methods(
690 700
691 for &impl_def in impls.for_self_ty(&self_ty.value) { 701 for &impl_def in impls.for_self_ty(&self_ty.value) {
692 for &item in db.impl_data(impl_def).items.iter() { 702 for &item in db.impl_data(impl_def).items.iter() {
693 if !is_valid_candidate(db, name, receiver_ty, item, self_ty, visible_from_module) { 703 if !is_valid_candidate(
704 db,
705 env.clone(),
706 name,
707 receiver_ty,
708 item,
709 self_ty,
710 visible_from_module,
711 ) {
694 continue; 712 continue;
695 } 713 }
696 // we have to check whether the self type unifies with the type 714 // we have to check whether the self type unifies with the type
697 // that the impl is for. If we have a receiver type, this 715 // that the impl is for. If we have a receiver type, this
698 // already happens in `is_valid_candidate` above; if not, we 716 // already happens in `is_valid_candidate` above; if not, we
699 // check it here 717 // check it here
700 if receiver_ty.is_none() && inherent_impl_substs(db, impl_def, self_ty).is_none() { 718 if receiver_ty.is_none()
719 && inherent_impl_substs(db, env.clone(), impl_def, self_ty).is_none()
720 {
701 cov_mark::hit!(impl_self_type_match_without_receiver); 721 cov_mark::hit!(impl_self_type_match_without_receiver);
702 continue; 722 continue;
703 } 723 }
@@ -722,7 +742,7 @@ pub fn resolve_indexing_op(
722 let deref_chain = autoderef_method_receiver(db, krate, ty); 742 let deref_chain = autoderef_method_receiver(db, krate, ty);
723 for ty in deref_chain { 743 for ty in deref_chain {
724 let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone()); 744 let goal = generic_implements_goal(db, env.clone(), index_trait, ty.clone());
725 if db.trait_solve(krate, goal).is_some() { 745 if db.trait_solve(krate, goal.cast(&Interner)).is_some() {
726 return Some(ty); 746 return Some(ty);
727 } 747 }
728 } 748 }
@@ -731,6 +751,7 @@ pub fn resolve_indexing_op(
731 751
732fn is_valid_candidate( 752fn is_valid_candidate(
733 db: &dyn HirDatabase, 753 db: &dyn HirDatabase,
754 env: Arc<TraitEnvironment>,
734 name: Option<&Name>, 755 name: Option<&Name>,
735 receiver_ty: Option<&Canonical<Ty>>, 756 receiver_ty: Option<&Canonical<Ty>>,
736 item: AssocItemId, 757 item: AssocItemId,
@@ -749,7 +770,7 @@ fn is_valid_candidate(
749 if !data.has_self_param() { 770 if !data.has_self_param() {
750 return false; 771 return false;
751 } 772 }
752 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { 773 let transformed_receiver_ty = match transform_receiver_ty(db, env, m, self_ty) {
753 Some(ty) => ty, 774 Some(ty) => ty,
754 None => return false, 775 None => return false,
755 }; 776 };
@@ -776,6 +797,7 @@ fn is_valid_candidate(
776 797
777pub(crate) fn inherent_impl_substs( 798pub(crate) fn inherent_impl_substs(
778 db: &dyn HirDatabase, 799 db: &dyn HirDatabase,
800 env: Arc<TraitEnvironment>,
779 impl_id: ImplId, 801 impl_id: ImplId,
780 self_ty: &Canonical<Ty>, 802 self_ty: &Canonical<Ty>,
781) -> Option<Substitution> { 803) -> Option<Substitution> {
@@ -798,7 +820,7 @@ pub(crate) fn inherent_impl_substs(
798 binders: CanonicalVarKinds::from_iter(&Interner, kinds), 820 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
799 value: (self_ty_with_vars, self_ty.value.clone()), 821 value: (self_ty_with_vars, self_ty.value.clone()),
800 }; 822 };
801 let substs = super::infer::unify(&tys)?; 823 let substs = super::infer::unify(db, env, &tys)?;
802 // We only want the substs for the vars we added, not the ones from self_ty. 824 // We only want the substs for the vars we added, not the ones from self_ty.
803 // Also, if any of the vars we added are still in there, we replace them by 825 // Also, if any of the vars we added are still in there, we replace them by
804 // Unknown. I think this can only really happen if self_ty contained 826 // Unknown. I think this can only really happen if self_ty contained
@@ -823,6 +845,7 @@ fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution
823 845
824fn transform_receiver_ty( 846fn transform_receiver_ty(
825 db: &dyn HirDatabase, 847 db: &dyn HirDatabase,
848 env: Arc<TraitEnvironment>,
826 function_id: FunctionId, 849 function_id: FunctionId,
827 self_ty: &Canonical<Ty>, 850 self_ty: &Canonical<Ty>,
828) -> Option<Ty> { 851) -> Option<Ty> {
@@ -832,7 +855,7 @@ fn transform_receiver_ty(
832 .fill_with_unknown() 855 .fill_with_unknown()
833 .build(), 856 .build(),
834 AssocContainerId::ImplId(impl_id) => { 857 AssocContainerId::ImplId(impl_id) => {
835 let impl_substs = inherent_impl_substs(db, impl_id, &self_ty)?; 858 let impl_substs = inherent_impl_substs(db, env, impl_id, &self_ty)?;
836 TyBuilder::subst_for_def(db, function_id) 859 TyBuilder::subst_for_def(db, function_id)
837 .use_parent_substs(&impl_substs) 860 .use_parent_substs(&impl_substs)
838 .fill_with_unknown() 861 .fill_with_unknown()
@@ -852,7 +875,7 @@ pub fn implements_trait(
852 trait_: TraitId, 875 trait_: TraitId,
853) -> bool { 876) -> bool {
854 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 877 let goal = generic_implements_goal(db, env, trait_, ty.clone());
855 let solution = db.trait_solve(krate, goal); 878 let solution = db.trait_solve(krate, goal.cast(&Interner));
856 879
857 solution.is_some() 880 solution.is_some()
858} 881}
@@ -865,7 +888,7 @@ pub fn implements_trait_unique(
865 trait_: TraitId, 888 trait_: TraitId,
866) -> bool { 889) -> bool {
867 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 890 let goal = generic_implements_goal(db, env, trait_, ty.clone());
868 let solution = db.trait_solve(krate, goal); 891 let solution = db.trait_solve(krate, goal.cast(&Interner));
869 892
870 matches!(solution, Some(crate::Solution::Unique(_))) 893 matches!(solution, Some(crate::Solution::Unique(_)))
871} 894}
diff --git a/crates/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index 190471069..bb568ea37 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches}; 3use super::{check_infer, check_infer_with_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_block_expr_type_mismatch() { 6fn infer_block_expr_type_mismatch() {
@@ -858,3 +858,57 @@ fn coerce_unsize_generic() {
858 "]], 858 "]],
859 ); 859 );
860} 860}
861
862#[test]
863fn infer_two_closures_lub() {
864 check_types(
865 r#"
866fn foo(c: i32) {
867 let add = |a: i32, b: i32| a + b;
868 let sub = |a, b| a - b;
869 //^ |i32, i32| -> i32
870 if c > 42 { add } else { sub };
871 //^ fn(i32, i32) -> i32
872}
873 "#,
874 )
875}
876
877#[test]
878fn infer_match_diverging_branch_1() {
879 check_types(
880 r#"
881enum Result<T> { Ok(T), Err }
882fn parse<T>() -> T { loop {} }
883
884fn test() -> i32 {
885 let a = match parse() {
886 Ok(val) => val,
887 Err => return 0,
888 };
889 a
890 //^ i32
891}
892 "#,
893 )
894}
895
896#[test]
897fn infer_match_diverging_branch_2() {
898 // same as 1 except for order of branches
899 check_types(
900 r#"
901enum Result<T> { Ok(T), Err }
902fn parse<T>() -> T { loop {} }
903
904fn test() -> i32 {
905 let a = match parse() {
906 Err => return 0,
907 Ok(val) => val,
908 };
909 a
910 //^ i32
911}
912 "#,
913 )
914}
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index ddbadbe40..cd08b5c7a 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -747,7 +747,7 @@ fn foo(tuple: (u8, i16, f32)) {
747 209..210 '_': (u8, i16, f32) 747 209..210 '_': (u8, i16, f32)
748 214..216 '{}': () 748 214..216 '{}': ()
749 136..142: expected (u8, i16, f32), got (u8, i16) 749 136..142: expected (u8, i16, f32), got (u8, i16)
750 170..182: expected (u8, i16, f32), got (u8, i16, f32, _) 750 170..182: expected (u8, i16, f32), got (u8, i16, f32, {unknown})
751 "#]], 751 "#]],
752 ); 752 );
753} 753}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 431861712..ad9edf11c 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -86,8 +86,6 @@ fn bug_651() {
86 86
87#[test] 87#[test]
88fn recursive_vars() { 88fn recursive_vars() {
89 cov_mark::check!(type_var_cycles_resolve_completely);
90 cov_mark::check!(type_var_cycles_resolve_as_possible);
91 check_infer( 89 check_infer(
92 r#" 90 r#"
93 fn test() { 91 fn test() {
@@ -97,12 +95,12 @@ fn recursive_vars() {
97 "#, 95 "#,
98 expect![[r#" 96 expect![[r#"
99 10..47 '{ ...&y]; }': () 97 10..47 '{ ...&y]; }': ()
100 20..21 'y': &{unknown} 98 20..21 'y': {unknown}
101 24..31 'unknown': &{unknown} 99 24..31 'unknown': {unknown}
102 37..44 '[y, &y]': [&&{unknown}; 2] 100 37..44 '[y, &y]': [{unknown}; 2]
103 38..39 'y': &{unknown} 101 38..39 'y': {unknown}
104 41..43 '&y': &&{unknown} 102 41..43 '&y': &{unknown}
105 42..43 'y': &{unknown} 103 42..43 'y': {unknown}
106 "#]], 104 "#]],
107 ); 105 );
108} 106}
@@ -119,19 +117,19 @@ fn recursive_vars_2() {
119 "#, 117 "#,
120 expect![[r#" 118 expect![[r#"
121 10..79 '{ ...x)]; }': () 119 10..79 '{ ...x)]; }': ()
122 20..21 'x': &&{unknown} 120 20..21 'x': &{unknown}
123 24..31 'unknown': &&{unknown} 121 24..31 'unknown': &{unknown}
124 41..42 'y': &&{unknown} 122 41..42 'y': {unknown}
125 45..52 'unknown': &&{unknown} 123 45..52 'unknown': {unknown}
126 58..76 '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown}); 2] 124 58..76 '[(x, y..., &x)]': [(&{unknown}, {unknown}); 2]
127 59..65 '(x, y)': (&&&{unknown}, &&&{unknown}) 125 59..65 '(x, y)': (&{unknown}, {unknown})
128 60..61 'x': &&{unknown} 126 60..61 'x': &{unknown}
129 63..64 'y': &&{unknown} 127 63..64 'y': {unknown}
130 67..75 '(&y, &x)': (&&&{unknown}, &&&{unknown}) 128 67..75 '(&y, &x)': (&{unknown}, {unknown})
131 68..70 '&y': &&&{unknown} 129 68..70 '&y': &{unknown}
132 69..70 'y': &&{unknown} 130 69..70 'y': {unknown}
133 72..74 '&x': &&&{unknown} 131 72..74 '&x': &&{unknown}
134 73..74 'x': &&{unknown} 132 73..74 'x': &{unknown}
135 "#]], 133 "#]],
136 ); 134 );
137} 135}
@@ -165,7 +163,6 @@ fn infer_std_crash_1() {
165 163
166#[test] 164#[test]
167fn infer_std_crash_2() { 165fn infer_std_crash_2() {
168 cov_mark::check!(type_var_resolves_to_int_var);
169 // caused "equating two type variables, ...", taken from std 166 // caused "equating two type variables, ...", taken from std
170 check_infer( 167 check_infer(
171 r#" 168 r#"
@@ -257,27 +254,27 @@ fn infer_std_crash_5() {
257 expect![[r#" 254 expect![[r#"
258 26..322 '{ ... } }': () 255 26..322 '{ ... } }': ()
259 32..320 'for co... }': () 256 32..320 'for co... }': ()
260 36..43 'content': &{unknown} 257 36..43 'content': {unknown}
261 47..60 'doesnt_matter': {unknown} 258 47..60 'doesnt_matter': {unknown}
262 61..320 '{ ... }': () 259 61..320 '{ ... }': ()
263 75..79 'name': &&{unknown} 260 75..79 'name': &{unknown}
264 82..166 'if doe... }': &&{unknown} 261 82..166 'if doe... }': &{unknown}
265 85..98 'doesnt_matter': bool 262 85..98 'doesnt_matter': bool
266 99..128 '{ ... }': &&{unknown} 263 99..128 '{ ... }': &{unknown}
267 113..118 'first': &&{unknown} 264 113..118 'first': &{unknown}
268 134..166 '{ ... }': &&{unknown} 265 134..166 '{ ... }': &{unknown}
269 148..156 '&content': &&{unknown} 266 148..156 '&content': &{unknown}
270 149..156 'content': &{unknown} 267 149..156 'content': {unknown}
271 181..188 'content': &{unknown} 268 181..188 'content': &{unknown}
272 191..313 'if ICE... }': &{unknown} 269 191..313 'if ICE... }': &{unknown}
273 194..231 'ICE_RE..._VALUE': {unknown} 270 194..231 'ICE_RE..._VALUE': {unknown}
274 194..247 'ICE_RE...&name)': bool 271 194..247 'ICE_RE...&name)': bool
275 241..246 '&name': &&&{unknown} 272 241..246 '&name': &&{unknown}
276 242..246 'name': &&{unknown} 273 242..246 'name': &{unknown}
277 248..276 '{ ... }': &&{unknown} 274 248..276 '{ ... }': &{unknown}
278 262..266 'name': &&{unknown} 275 262..266 'name': &{unknown}
279 282..313 '{ ... }': &{unknown} 276 282..313 '{ ... }': {unknown}
280 296..303 'content': &{unknown} 277 296..303 'content': {unknown}
281 "#]], 278 "#]],
282 ); 279 );
283} 280}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index a9cd42186..5c70a1fc0 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1040,42 +1040,6 @@ fn infer_in_elseif() {
1040} 1040}
1041 1041
1042#[test] 1042#[test]
1043fn infer_closure_unify() {
1044 check_infer(
1045 r#"
1046 fn foo(f: bool) {
1047 let a = |x| x;
1048 let b = |x| x;
1049 let id = if f { a } else { b };
1050 id(123);
1051 }
1052 "#,
1053 expect![[r#"
1054 7..8 'f': bool
1055 16..106 '{ ...23); }': ()
1056 26..27 'a': |i32| -> i32
1057 30..35 '|x| x': |i32| -> i32
1058 31..32 'x': i32
1059 34..35 'x': i32
1060 45..46 'b': |i32| -> i32
1061 49..54 '|x| x': |i32| -> i32
1062 50..51 'x': i32
1063 53..54 'x': i32
1064 64..66 'id': |i32| -> i32
1065 69..90 'if f {... { b }': |i32| -> i32
1066 72..73 'f': bool
1067 74..79 '{ a }': |i32| -> i32
1068 76..77 'a': |i32| -> i32
1069 85..90 '{ b }': |i32| -> i32
1070 87..88 'b': |i32| -> i32
1071 96..98 'id': |i32| -> i32
1072 96..103 'id(123)': i32
1073 99..102 '123': i32
1074 "#]],
1075 )
1076}
1077
1078#[test]
1079fn infer_if_match_with_return() { 1043fn infer_if_match_with_return() {
1080 check_infer( 1044 check_infer(
1081 r#" 1045 r#"
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index f80cf9879..a5a2df54c 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3104,7 +3104,7 @@ fn foo() {
3104 568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)> 3104 568..573 'f(&s)': FnOnce::Output<dyn FnOnce(&Option<i32>), (&Option<i32>,)>
3105 570..572 '&s': &Option<i32> 3105 570..572 '&s': &Option<i32>
3106 571..572 's': Option<i32> 3106 571..572 's': Option<i32>
3107 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|_| -> ()> 3107 549..562: expected Box<dyn FnOnce(&Option<i32>)>, got Box<|{unknown}| -> ()>
3108 "#]], 3108 "#]],
3109 ); 3109 );
3110} 3110}
diff --git a/crates/hir_ty/src/tls.rs b/crates/hir_ty/src/tls.rs
index 87c671a42..708797c47 100644
--- a/crates/hir_ty/src/tls.rs
+++ b/crates/hir_ty/src/tls.rs
@@ -1,7 +1,7 @@
1//! Implementation of Chalk debug helper functions using TLS. 1//! Implementation of Chalk debug helper functions using TLS.
2use std::fmt; 2use std::fmt::{self, Debug};
3 3
4use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication}; 4use chalk_ir::AliasTy;
5use itertools::Itertools; 5use itertools::Itertools;
6 6
7use crate::{ 7use crate::{
@@ -53,14 +53,6 @@ impl DebugContext<'_> {
53 write!(fmt, "{}::{}", trait_data.name, type_alias_data.name) 53 write!(fmt, "{}::{}", trait_data.name, type_alias_data.name)
54 } 54 }
55 55
56 pub(crate) fn debug_opaque_ty_id(
57 &self,
58 opaque_ty_id: chalk_ir::OpaqueTyId<Interner>,
59 fmt: &mut fmt::Formatter<'_>,
60 ) -> Result<(), fmt::Error> {
61 fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish()
62 }
63
64 pub(crate) fn debug_alias( 56 pub(crate) fn debug_alias(
65 &self, 57 &self,
66 alias_ty: &AliasTy<Interner>, 58 alias_ty: &AliasTy<Interner>,
@@ -68,7 +60,7 @@ impl DebugContext<'_> {
68 ) -> Result<(), fmt::Error> { 60 ) -> Result<(), fmt::Error> {
69 match alias_ty { 61 match alias_ty {
70 AliasTy::Projection(projection_ty) => self.debug_projection_ty(projection_ty, fmt), 62 AliasTy::Projection(projection_ty) => self.debug_projection_ty(projection_ty, fmt),
71 AliasTy::Opaque(opaque_ty) => self.debug_opaque_ty(opaque_ty, fmt), 63 AliasTy::Opaque(opaque_ty) => opaque_ty.fmt(fmt),
72 } 64 }
73 } 65 }
74 66
@@ -96,79 +88,6 @@ impl DebugContext<'_> {
96 write!(fmt, ">::{}", type_alias_data.name) 88 write!(fmt, ">::{}", type_alias_data.name)
97 } 89 }
98 90
99 pub(crate) fn debug_opaque_ty(
100 &self,
101 opaque_ty: &chalk_ir::OpaqueTy<Interner>,
102 fmt: &mut fmt::Formatter<'_>,
103 ) -> Result<(), fmt::Error> {
104 write!(fmt, "{:?}", opaque_ty.opaque_ty_id)
105 }
106
107 pub(crate) fn debug_ty(
108 &self,
109 ty: &chalk_ir::Ty<Interner>,
110 fmt: &mut fmt::Formatter<'_>,
111 ) -> Result<(), fmt::Error> {
112 write!(fmt, "{:?}", ty.data(&Interner))
113 }
114
115 pub(crate) fn debug_lifetime(
116 &self,
117 lifetime: &Lifetime<Interner>,
118 fmt: &mut fmt::Formatter<'_>,
119 ) -> Result<(), fmt::Error> {
120 write!(fmt, "{:?}", lifetime.data(&Interner))
121 }
122
123 pub(crate) fn debug_generic_arg(
124 &self,
125 parameter: &GenericArg<Interner>,
126 fmt: &mut fmt::Formatter<'_>,
127 ) -> Result<(), fmt::Error> {
128 write!(fmt, "{:?}", parameter.data(&Interner).inner_debug())
129 }
130
131 pub(crate) fn debug_goal(
132 &self,
133 goal: &Goal<Interner>,
134 fmt: &mut fmt::Formatter<'_>,
135 ) -> Result<(), fmt::Error> {
136 let goal_data = goal.data(&Interner);
137 write!(fmt, "{:?}", goal_data)
138 }
139
140 pub(crate) fn debug_goals(
141 &self,
142 goals: &Goals<Interner>,
143 fmt: &mut fmt::Formatter<'_>,
144 ) -> Result<(), fmt::Error> {
145 write!(fmt, "{:?}", goals.debug(&Interner))
146 }
147
148 pub(crate) fn debug_program_clause_implication(
149 &self,
150 pci: &ProgramClauseImplication<Interner>,
151 fmt: &mut fmt::Formatter<'_>,
152 ) -> Result<(), fmt::Error> {
153 write!(fmt, "{:?}", pci.debug(&Interner))
154 }
155
156 pub(crate) fn debug_substitution(
157 &self,
158 substitution: &chalk_ir::Substitution<Interner>,
159 fmt: &mut fmt::Formatter<'_>,
160 ) -> Result<(), fmt::Error> {
161 write!(fmt, "{:?}", substitution.debug(&Interner))
162 }
163
164 pub(crate) fn debug_separator_trait_ref(
165 &self,
166 separator_trait_ref: &chalk_ir::SeparatorTraitRef<Interner>,
167 fmt: &mut fmt::Formatter<'_>,
168 ) -> Result<(), fmt::Error> {
169 write!(fmt, "{:?}", separator_trait_ref.debug(&Interner))
170 }
171
172 pub(crate) fn debug_fn_def_id( 91 pub(crate) fn debug_fn_def_id(
173 &self, 92 &self,
174 fn_def_id: chalk_ir::FnDefId<Interner>, 93 fn_def_id: chalk_ir::FnDefId<Interner>,
@@ -190,57 +109,6 @@ impl DebugContext<'_> {
190 } 109 }
191 } 110 }
192 } 111 }
193
194 pub(crate) fn debug_const(
195 &self,
196 _constant: &chalk_ir::Const<Interner>,
197 fmt: &mut fmt::Formatter<'_>,
198 ) -> fmt::Result {
199 write!(fmt, "const")
200 }
201
202 pub(crate) fn debug_variable_kinds(
203 &self,
204 variable_kinds: &chalk_ir::VariableKinds<Interner>,
205 fmt: &mut fmt::Formatter<'_>,
206 ) -> fmt::Result {
207 write!(fmt, "{:?}", variable_kinds.as_slice(&Interner))
208 }
209 pub(crate) fn debug_variable_kinds_with_angles(
210 &self,
211 variable_kinds: &chalk_ir::VariableKinds<Interner>,
212 fmt: &mut fmt::Formatter<'_>,
213 ) -> fmt::Result {
214 write!(fmt, "{:?}", variable_kinds.inner_debug(&Interner))
215 }
216 pub(crate) fn debug_canonical_var_kinds(
217 &self,
218 canonical_var_kinds: &chalk_ir::CanonicalVarKinds<Interner>,
219 fmt: &mut fmt::Formatter<'_>,
220 ) -> fmt::Result {
221 write!(fmt, "{:?}", canonical_var_kinds.as_slice(&Interner))
222 }
223 pub(crate) fn debug_program_clause(
224 &self,
225 clause: &chalk_ir::ProgramClause<Interner>,
226 fmt: &mut fmt::Formatter<'_>,
227 ) -> fmt::Result {
228 write!(fmt, "{:?}", clause.data(&Interner))
229 }
230 pub(crate) fn debug_program_clauses(
231 &self,
232 clauses: &chalk_ir::ProgramClauses<Interner>,
233 fmt: &mut fmt::Formatter<'_>,
234 ) -> fmt::Result {
235 write!(fmt, "{:?}", clauses.as_slice(&Interner))
236 }
237 pub(crate) fn debug_quantified_where_clauses(
238 &self,
239 clauses: &chalk_ir::QuantifiedWhereClauses<Interner>,
240 fmt: &mut fmt::Formatter<'_>,
241 ) -> fmt::Result {
242 write!(fmt, "{:?}", clauses.as_slice(&Interner))
243 }
244} 112}
245 113
246mod unsafe_tls { 114mod unsafe_tls {
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 9936d0803..294cb531c 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -2,7 +2,7 @@
2 2
3use std::env::var; 3use std::env::var;
4 4
5use chalk_ir::cast::Cast; 5use chalk_ir::GoalData;
6use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver}; 6use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
7 7
8use base_db::CrateId; 8use base_db::CrateId;
@@ -10,7 +10,7 @@ use hir_def::{lang_item::LangItemTarget, TraitId};
10use stdx::panic_context; 10use stdx::panic_context;
11 11
12use crate::{ 12use crate::{
13 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment, 13 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
14 Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause, 14 Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
15}; 15};
16 16
@@ -38,6 +38,7 @@ fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
38/// we assume that `T: Default`. 38/// we assume that `T: Default`.
39#[derive(Debug, Clone, PartialEq, Eq, Hash)] 39#[derive(Debug, Clone, PartialEq, Eq, Hash)]
40pub struct TraitEnvironment { 40pub struct TraitEnvironment {
41 pub krate: CrateId,
41 // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord, 42 // When we're using Chalk's Ty we can make this a BTreeMap since it's Ord,
42 // but for now it's too annoying... 43 // but for now it's too annoying...
43 pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>, 44 pub(crate) traits_from_clauses: Vec<(Ty, TraitId)>,
@@ -45,6 +46,14 @@ pub struct TraitEnvironment {
45} 46}
46 47
47impl TraitEnvironment { 48impl TraitEnvironment {
49 pub fn empty(krate: CrateId) -> Self {
50 TraitEnvironment {
51 krate,
52 traits_from_clauses: Vec::new(),
53 env: chalk_ir::Environment::new(&Interner),
54 }
55 }
56
48 pub(crate) fn traits_in_scope_from_clauses<'a>( 57 pub(crate) fn traits_in_scope_from_clauses<'a>(
49 &'a self, 58 &'a self,
50 ty: &'a Ty, 59 ty: &'a Ty,
@@ -59,34 +68,25 @@ impl TraitEnvironment {
59 } 68 }
60} 69}
61 70
62impl Default for TraitEnvironment {
63 fn default() -> Self {
64 TraitEnvironment {
65 traits_from_clauses: Vec::new(),
66 env: chalk_ir::Environment::new(&Interner),
67 }
68 }
69}
70
71/// Solve a trait goal using Chalk. 71/// Solve a trait goal using Chalk.
72pub(crate) fn trait_solve_query( 72pub(crate) fn trait_solve_query(
73 db: &dyn HirDatabase, 73 db: &dyn HirDatabase,
74 krate: CrateId, 74 krate: CrateId,
75 goal: Canonical<InEnvironment<DomainGoal>>, 75 goal: Canonical<InEnvironment<Goal>>,
76) -> Option<Solution> { 76) -> Option<Solution> {
77 let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal { 77 let _p = profile::span("trait_solve_query").detail(|| match &goal.value.goal.data(&Interner) {
78 DomainGoal::Holds(WhereClause::Implemented(it)) => { 78 GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
79 db.trait_data(it.hir_trait_id()).name.to_string() 79 db.trait_data(it.hir_trait_id()).name.to_string()
80 } 80 }
81 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(), 81 GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
82 _ => "??".to_string(), 82 _ => "??".to_string(),
83 }); 83 });
84 log::info!("trait_solve_query({})", goal.value.goal.display(db)); 84 log::info!("trait_solve_query({:?})", goal.value.goal);
85 85
86 if let DomainGoal::Holds(WhereClause::AliasEq(AliasEq { 86 if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
87 alias: AliasTy::Projection(projection_ty), 87 alias: AliasTy::Projection(projection_ty),
88 .. 88 ..
89 })) = &goal.value.goal 89 }))) = &goal.value.goal.data(&Interner)
90 { 90 {
91 if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(&Interner).kind(&Interner) { 91 if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(&Interner).kind(&Interner) {
92 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible 92 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
@@ -94,11 +94,9 @@ pub(crate) fn trait_solve_query(
94 } 94 }
95 } 95 }
96 96
97 let canonical = goal.cast(&Interner);
98
99 // We currently don't deal with universes (I think / hope they're not yet 97 // We currently don't deal with universes (I think / hope they're not yet
100 // relevant for our use cases?) 98 // relevant for our use cases?)
101 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 99 let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };
102 solve(db, krate, &u_canonical) 100 solve(db, krate, &u_canonical)
103} 101}
104 102
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index f4b90db3a..ff2a54117 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -50,6 +50,7 @@ mod typing;
50mod markdown_remove; 50mod markdown_remove;
51mod doc_links; 51mod doc_links;
52mod view_crate_graph; 52mod view_crate_graph;
53mod view_item_tree;
53 54
54use std::sync::Arc; 55use std::sync::Arc;
55 56
@@ -288,6 +289,10 @@ impl Analysis {
288 self.with_db(|db| view_hir::view_hir(&db, position)) 289 self.with_db(|db| view_hir::view_hir(&db, position))
289 } 290 }
290 291
292 pub fn view_item_tree(&self, file_id: FileId) -> Cancelable<String> {
293 self.with_db(|db| view_item_tree::view_item_tree(&db, file_id))
294 }
295
291 /// Renders the crate graph to GraphViz "dot" syntax. 296 /// Renders the crate graph to GraphViz "dot" syntax.
292 pub fn view_crate_graph(&self) -> Cancelable<Result<String, String>> { 297 pub fn view_crate_graph(&self) -> Cancelable<Result<String, String>> {
293 self.with_db(|db| view_crate_graph::view_crate_graph(&db)) 298 self.with_db(|db| view_crate_graph::view_crate_graph(&db))
diff --git a/crates/ide/src/view_item_tree.rs b/crates/ide/src/view_item_tree.rs
new file mode 100644
index 000000000..3dc03085d
--- /dev/null
+++ b/crates/ide/src/view_item_tree.rs
@@ -0,0 +1,16 @@
1use hir::db::DefDatabase;
2use ide_db::base_db::FileId;
3use ide_db::RootDatabase;
4
5// Feature: Debug ItemTree
6//
7// Displays the ItemTree of the currently open file, for debugging.
8//
9// |===
10// | Editor | Action Name
11//
12// | VS Code | **Rust Analyzer: Debug ItemTree**
13// |===
14pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String {
15 db.file_item_tree(file_id.into()).pretty_print()
16}
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index dda5a6631..d4748ef3a 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -33,20 +33,19 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
33// use super::AssistContext; 33// use super::AssistContext;
34// ``` 34// ```
35// 35//
36// .Merge Behavior 36// .Import Granularity
37// 37//
38// It is possible to configure how use-trees are merged with the `importMergeBehavior` setting. 38// It is possible to configure how use-trees are merged with the `importGranularity` setting.
39// It has the following configurations: 39// It has the following configurations:
40// 40//
41// - `full`: This setting will cause auto-import to always completely merge use-trees that share the 41// - `crate`: Merge imports from the same crate into a single use statement. This kind of
42// same path prefix while also merging inner trees that share the same path-prefix. This kind of
43// nesting is only supported in Rust versions later than 1.24. 42// nesting is only supported in Rust versions later than 1.24.
44// - `last`: This setting will cause auto-import to merge use-trees as long as the resulting tree 43// - `module`: Merge imports from the same module into a single use statement.
45// will only contain a nesting of single segment paths at the very end. 44// - `item`: Don't merge imports at all, creating one import per item.
46// - `none`: This setting will cause auto-import to never merge use-trees keeping them as simple 45// - `preserve`: Do not change the granularity of any imports. For auto-import this has the same
47// paths. 46// effect as `item`.
48// 47//
49// In `VS Code` the configuration for this is `rust-analyzer.assist.importMergeBehavior`. 48// In `VS Code` the configuration for this is `rust-analyzer.assist.importGranularity`.
50// 49//
51// .Import Prefix 50// .Import Prefix
52// 51//
diff --git a/crates/ide_assists/src/handlers/merge_imports.rs b/crates/ide_assists/src/handlers/merge_imports.rs
index 31854840c..fc117bd9a 100644
--- a/crates/ide_assists/src/handlers/merge_imports.rs
+++ b/crates/ide_assists/src/handlers/merge_imports.rs
@@ -213,6 +213,20 @@ pub(crate) use std::fmt::{Debug, Display};
213 } 213 }
214 214
215 #[test] 215 #[test]
216 fn merge_pub_in_path_crate() {
217 check_assist(
218 merge_imports,
219 r"
220pub(in this::path) use std::fmt$0::Debug;
221pub(in this::path) use std::fmt::Display;
222",
223 r"
224pub(in this::path) use std::fmt::{Debug, Display};
225",
226 )
227 }
228
229 #[test]
216 fn test_merge_nested() { 230 fn test_merge_nested() {
217 check_assist( 231 check_assist(
218 merge_imports, 232 merge_imports,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index b091ab91a..6a9231e07 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -4,7 +4,10 @@ use expect_test::expect;
4use hir::Semantics; 4use hir::Semantics;
5use ide_db::{ 5use ide_db::{
6 base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, 6 base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
7 helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap}, 7 helpers::{
8 insert_use::{ImportGranularity, InsertUseConfig},
9 SnippetCap,
10 },
8 source_change::FileSystemEdit, 11 source_change::FileSystemEdit,
9 RootDatabase, 12 RootDatabase,
10}; 13};
@@ -21,8 +24,9 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
21 snippet_cap: SnippetCap::new(true), 24 snippet_cap: SnippetCap::new(true),
22 allowed: None, 25 allowed: None,
23 insert_use: InsertUseConfig { 26 insert_use: InsertUseConfig {
24 merge: Some(MergeBehavior::Crate), 27 granularity: ImportGranularity::Crate,
25 prefix_kind: hir::PrefixKind::Plain, 28 prefix_kind: hir::PrefixKind::Plain,
29 enforce_granularity: true,
26 group: true, 30 group: true,
27 }, 31 },
28}; 32};
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 1a762d3dc..6b04ee164 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -323,7 +323,7 @@ fn compute_type_match(
323 323
324 if completion_ty == expected_type { 324 if completion_ty == expected_type {
325 Some(CompletionRelevanceTypeMatch::Exact) 325 Some(CompletionRelevanceTypeMatch::Exact)
326 } else if expected_type.could_unify_with(completion_ty) { 326 } else if expected_type.could_unify_with(ctx.db, completion_ty) {
327 Some(CompletionRelevanceTypeMatch::CouldUnify) 327 Some(CompletionRelevanceTypeMatch::CouldUnify)
328 } else { 328 } else {
329 None 329 None
diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs
index 939fb2d47..37be575e5 100644
--- a/crates/ide_completion/src/test_utils.rs
+++ b/crates/ide_completion/src/test_utils.rs
@@ -3,7 +3,10 @@
3use hir::{PrefixKind, Semantics}; 3use hir::{PrefixKind, Semantics};
4use ide_db::{ 4use ide_db::{
5 base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, 5 base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
6 helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap}, 6 helpers::{
7 insert_use::{ImportGranularity, InsertUseConfig},
8 SnippetCap,
9 },
7 RootDatabase, 10 RootDatabase,
8}; 11};
9use itertools::Itertools; 12use itertools::Itertools;
@@ -20,8 +23,9 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
20 add_call_argument_snippets: true, 23 add_call_argument_snippets: true,
21 snippet_cap: SnippetCap::new(true), 24 snippet_cap: SnippetCap::new(true),
22 insert_use: InsertUseConfig { 25 insert_use: InsertUseConfig {
23 merge: Some(MergeBehavior::Crate), 26 granularity: ImportGranularity::Crate,
24 prefix_kind: PrefixKind::Plain, 27 prefix_kind: PrefixKind::Plain,
28 enforce_granularity: true,
25 group: true, 29 group: true,
26 }, 30 },
27}; 31};
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs
index 55cdc4da3..aa61c5bcb 100644
--- a/crates/ide_db/src/helpers/insert_use.rs
+++ b/crates/ide_db/src/helpers/insert_use.rs
@@ -4,20 +4,36 @@ use std::cmp::Ordering;
4use hir::Semantics; 4use hir::Semantics;
5use syntax::{ 5use syntax::{
6 algo, 6 algo,
7 ast::{self, make, AstNode, PathSegmentKind}, 7 ast::{self, make, AstNode, AttrsOwner, ModuleItemOwner, PathSegmentKind, VisibilityOwner},
8 ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken, 8 ted, AstToken, Direction, NodeOrToken, SyntaxNode, SyntaxToken,
9}; 9};
10 10
11use crate::{ 11use crate::{
12 helpers::merge_imports::{try_merge_imports, use_tree_path_cmp, MergeBehavior}, 12 helpers::merge_imports::{
13 common_prefix, eq_attrs, eq_visibility, try_merge_imports, use_tree_path_cmp, MergeBehavior,
14 },
13 RootDatabase, 15 RootDatabase,
14}; 16};
15 17
16pub use hir::PrefixKind; 18pub use hir::PrefixKind;
17 19
20/// How imports should be grouped into use statements.
21#[derive(Copy, Clone, Debug, PartialEq, Eq)]
22pub enum ImportGranularity {
23 /// Do not change the granularity of any imports and preserve the original structure written by the developer.
24 Preserve,
25 /// Merge imports from the same crate into a single use statement.
26 Crate,
27 /// Merge imports from the same module into a single use statement.
28 Module,
29 /// Flatten imports so that each has its own use statement.
30 Item,
31}
32
18#[derive(Clone, Copy, Debug, PartialEq, Eq)] 33#[derive(Clone, Copy, Debug, PartialEq, Eq)]
19pub struct InsertUseConfig { 34pub struct InsertUseConfig {
20 pub merge: Option<MergeBehavior>, 35 pub granularity: ImportGranularity,
36 pub enforce_granularity: bool,
21 pub prefix_kind: PrefixKind, 37 pub prefix_kind: PrefixKind,
22 pub group: bool, 38 pub group: bool,
23} 39}
@@ -65,15 +81,96 @@ impl ImportScope {
65 ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()), 81 ImportScope::Module(item_list) => ImportScope::Module(item_list.clone_for_update()),
66 } 82 }
67 } 83 }
84
85 fn guess_granularity_from_scope(&self) -> ImportGranularityGuess {
86 // The idea is simple, just check each import as well as the import and its precedent together for
87 // whether they fulfill a granularity criteria.
88 let use_stmt = |item| match item {
89 ast::Item::Use(use_) => {
90 let use_tree = use_.use_tree()?;
91 Some((use_tree, use_.visibility(), use_.attrs()))
92 }
93 _ => None,
94 };
95 let mut use_stmts = match self {
96 ImportScope::File(f) => f.items(),
97 ImportScope::Module(m) => m.items(),
98 }
99 .filter_map(use_stmt);
100 let mut res = ImportGranularityGuess::Unknown;
101 let (mut prev, mut prev_vis, mut prev_attrs) = match use_stmts.next() {
102 Some(it) => it,
103 None => return res,
104 };
105 loop {
106 if let Some(use_tree_list) = prev.use_tree_list() {
107 if use_tree_list.use_trees().any(|tree| tree.use_tree_list().is_some()) {
108 // Nested tree lists can only occur in crate style, or with no proper style being enforced in the file.
109 break ImportGranularityGuess::Crate;
110 } else {
111 // Could still be crate-style so continue looking.
112 res = ImportGranularityGuess::CrateOrModule;
113 }
114 }
115
116 let (curr, curr_vis, curr_attrs) = match use_stmts.next() {
117 Some(it) => it,
118 None => break res,
119 };
120 if eq_visibility(prev_vis, curr_vis.clone()) && eq_attrs(prev_attrs, curr_attrs.clone())
121 {
122 if let Some((prev_path, curr_path)) = prev.path().zip(curr.path()) {
123 if let Some(_) = common_prefix(&prev_path, &curr_path) {
124 if prev.use_tree_list().is_none() && curr.use_tree_list().is_none() {
125 // Same prefix but no use tree lists so this has to be of item style.
126 break ImportGranularityGuess::Item; // this overwrites CrateOrModule, technically the file doesn't adhere to anything here.
127 } else {
128 // Same prefix with item tree lists, has to be module style as it
129 // can't be crate style since the trees wouldn't share a prefix then.
130 break ImportGranularityGuess::Module;
131 }
132 }
133 }
134 }
135 prev = curr;
136 prev_vis = curr_vis;
137 prev_attrs = curr_attrs;
138 }
139 }
140}
141
142#[derive(PartialEq, PartialOrd, Debug, Clone, Copy)]
143enum ImportGranularityGuess {
144 Unknown,
145 Item,
146 Module,
147 Crate,
148 CrateOrModule,
68} 149}
69 150
70/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. 151/// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur.
71pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { 152pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) {
72 let _p = profile::span("insert_use"); 153 let _p = profile::span("insert_use");
154 let mut mb = match cfg.granularity {
155 ImportGranularity::Crate => Some(MergeBehavior::Crate),
156 ImportGranularity::Module => Some(MergeBehavior::Module),
157 ImportGranularity::Item | ImportGranularity::Preserve => None,
158 };
159 if !cfg.enforce_granularity {
160 let file_granularity = scope.guess_granularity_from_scope();
161 mb = match file_granularity {
162 ImportGranularityGuess::Unknown => mb,
163 ImportGranularityGuess::Item => None,
164 ImportGranularityGuess::Module => Some(MergeBehavior::Module),
165 ImportGranularityGuess::Crate => Some(MergeBehavior::Crate),
166 ImportGranularityGuess::CrateOrModule => mb.or(Some(MergeBehavior::Crate)),
167 };
168 }
169
73 let use_item = 170 let use_item =
74 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); 171 make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
75 // merge into existing imports if possible 172 // merge into existing imports if possible
76 if let Some(mb) = cfg.merge { 173 if let Some(mb) = mb {
77 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { 174 for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) {
78 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { 175 if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
79 ted::replace(existing_use.syntax(), merged.syntax()); 176 ted::replace(existing_use.syntax(), merged.syntax());
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs
index 248227d29..78a2a87b3 100644
--- a/crates/ide_db/src/helpers/insert_use/tests.rs
+++ b/crates/ide_db/src/helpers/insert_use/tests.rs
@@ -21,7 +21,7 @@ use crate::bar::A;
21use self::bar::A; 21use self::bar::A;
22use super::bar::A; 22use super::bar::A;
23use external_crate2::bar::A;", 23use external_crate2::bar::A;",
24 None, 24 ImportGranularity::Item,
25 false, 25 false,
26 false, 26 false,
27 ); 27 );
@@ -36,7 +36,7 @@ fn insert_not_group_empty() {
36 r"use external_crate2::bar::A; 36 r"use external_crate2::bar::A;
37 37
38", 38",
39 None, 39 ImportGranularity::Item,
40 false, 40 false,
41 false, 41 false,
42 ); 42 );
@@ -281,7 +281,7 @@ fn insert_empty_module() {
281 r"{ 281 r"{
282 use foo::bar; 282 use foo::bar;
283}", 283}",
284 None, 284 ImportGranularity::Item,
285 true, 285 true,
286 true, 286 true,
287 ) 287 )
@@ -631,11 +631,121 @@ fn merge_last_fail3() {
631 ); 631 );
632} 632}
633 633
634#[test]
635fn guess_empty() {
636 check_guess("", ImportGranularityGuess::Unknown);
637}
638
639#[test]
640fn guess_single() {
641 check_guess(r"use foo::{baz::{qux, quux}, bar};", ImportGranularityGuess::Crate);
642 check_guess(r"use foo::bar;", ImportGranularityGuess::Unknown);
643 check_guess(r"use foo::bar::{baz, qux};", ImportGranularityGuess::CrateOrModule);
644}
645
646#[test]
647fn guess_unknown() {
648 check_guess(
649 r"
650use foo::bar::baz;
651use oof::rab::xuq;
652",
653 ImportGranularityGuess::Unknown,
654 );
655}
656
657#[test]
658fn guess_item() {
659 check_guess(
660 r"
661use foo::bar::baz;
662use foo::bar::qux;
663",
664 ImportGranularityGuess::Item,
665 );
666}
667
668#[test]
669fn guess_module() {
670 check_guess(
671 r"
672use foo::bar::baz;
673use foo::bar::{qux, quux};
674",
675 ImportGranularityGuess::Module,
676 );
677 // this is a rather odd case, technically this file isn't following any style properly.
678 check_guess(
679 r"
680use foo::bar::baz;
681use foo::{baz::{qux, quux}, bar};
682",
683 ImportGranularityGuess::Module,
684 );
685}
686
687#[test]
688fn guess_crate_or_module() {
689 check_guess(
690 r"
691use foo::bar::baz;
692use oof::bar::{qux, quux};
693",
694 ImportGranularityGuess::CrateOrModule,
695 );
696}
697
698#[test]
699fn guess_crate() {
700 check_guess(
701 r"
702use frob::bar::baz;
703use foo::{baz::{qux, quux}, bar};
704",
705 ImportGranularityGuess::Crate,
706 );
707}
708
709#[test]
710fn guess_skips_differing_vis() {
711 check_guess(
712 r"
713use foo::bar::baz;
714pub use foo::bar::qux;
715",
716 ImportGranularityGuess::Unknown,
717 );
718}
719
720#[test]
721fn guess_skips_differing_attrs() {
722 check_guess(
723 r"
724pub use foo::bar::baz;
725#[doc(hidden)]
726pub use foo::bar::qux;
727",
728 ImportGranularityGuess::Unknown,
729 );
730}
731
732#[test]
733fn guess_grouping_matters() {
734 check_guess(
735 r"
736use foo::bar::baz;
737use oof::bar::baz;
738use foo::bar::qux;
739",
740 ImportGranularityGuess::Unknown,
741 );
742}
743
634fn check( 744fn check(
635 path: &str, 745 path: &str,
636 ra_fixture_before: &str, 746 ra_fixture_before: &str,
637 ra_fixture_after: &str, 747 ra_fixture_after: &str,
638 mb: Option<MergeBehavior>, 748 granularity: ImportGranularity,
639 module: bool, 749 module: bool,
640 group: bool, 750 group: bool,
641) { 751) {
@@ -651,21 +761,30 @@ fn check(
651 .find_map(ast::Path::cast) 761 .find_map(ast::Path::cast)
652 .unwrap(); 762 .unwrap();
653 763
654 insert_use(&file, path, InsertUseConfig { merge: mb, prefix_kind: PrefixKind::Plain, group }); 764 insert_use(
765 &file,
766 path,
767 InsertUseConfig {
768 granularity,
769 enforce_granularity: true,
770 prefix_kind: PrefixKind::Plain,
771 group,
772 },
773 );
655 let result = file.as_syntax_node().to_string(); 774 let result = file.as_syntax_node().to_string();
656 assert_eq_text!(ra_fixture_after, &result); 775 assert_eq_text!(ra_fixture_after, &result);
657} 776}
658 777
659fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 778fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
660 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Crate), false, true) 779 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate, false, true)
661} 780}
662 781
663fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 782fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
664 check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Module), false, true) 783 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module, false, true)
665} 784}
666 785
667fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { 786fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
668 check(path, ra_fixture_before, ra_fixture_after, None, false, true) 787 check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item, false, true)
669} 788}
670 789
671fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { 790fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) {
@@ -686,3 +805,9 @@ fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior
686 let result = try_merge_imports(&use0, &use1, mb); 805 let result = try_merge_imports(&use0, &use1, mb);
687 assert_eq!(result.map(|u| u.to_string()), None); 806 assert_eq!(result.map(|u| u.to_string()), None);
688} 807}
808
809fn check_guess(ra_fixture: &str, expected: ImportGranularityGuess) {
810 let syntax = ast::SourceFile::parse(ra_fixture).tree().syntax().clone();
811 let file = super::ImportScope::from(syntax).unwrap();
812 assert_eq!(file.guess_granularity_from_scope(), expected);
813}
diff --git a/crates/ide_db/src/helpers/merge_imports.rs b/crates/ide_db/src/helpers/merge_imports.rs
index 8fb40e837..0dbabb44f 100644
--- a/crates/ide_db/src/helpers/merge_imports.rs
+++ b/crates/ide_db/src/helpers/merge_imports.rs
@@ -181,7 +181,7 @@ fn recursive_merge(
181} 181}
182 182
183/// Traverses both paths until they differ, returning the common prefix of both. 183/// Traverses both paths until they differ, returning the common prefix of both.
184fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> { 184pub fn common_prefix(lhs: &ast::Path, rhs: &ast::Path) -> Option<(ast::Path, ast::Path)> {
185 let mut res = None; 185 let mut res = None;
186 let mut lhs_curr = lhs.first_qualifier_or_self(); 186 let mut lhs_curr = lhs.first_qualifier_or_self();
187 let mut rhs_curr = rhs.first_qualifier_or_self(); 187 let mut rhs_curr = rhs.first_qualifier_or_self();
@@ -289,23 +289,26 @@ fn path_segment_cmp(a: &ast::PathSegment, b: &ast::PathSegment) -> Ordering {
289 a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text)) 289 a.as_ref().map(ast::NameRef::text).cmp(&b.as_ref().map(ast::NameRef::text))
290} 290}
291 291
292fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool { 292pub fn eq_visibility(vis0: Option<ast::Visibility>, vis1: Option<ast::Visibility>) -> bool {
293 match (vis0, vis1) { 293 match (vis0, vis1) {
294 (None, None) => true, 294 (None, None) => true,
295 // FIXME: Don't use the string representation to check for equality 295 (Some(vis0), Some(vis1)) => vis0.is_eq_to(&vis1),
296 // spaces inside of the node would break this comparison
297 (Some(vis0), Some(vis1)) => vis0.to_string() == vis1.to_string(),
298 _ => false, 296 _ => false,
299 } 297 }
300} 298}
301 299
302fn eq_attrs( 300pub fn eq_attrs(
303 attrs0: impl Iterator<Item = ast::Attr>, 301 attrs0: impl Iterator<Item = ast::Attr>,
304 attrs1: impl Iterator<Item = ast::Attr>, 302 attrs1: impl Iterator<Item = ast::Attr>,
305) -> bool { 303) -> bool {
306 let attrs0 = attrs0.map(|attr| attr.to_string()); 304 // FIXME order of attributes should not matter
307 let attrs1 = attrs1.map(|attr| attr.to_string()); 305 let attrs0 = attrs0
308 attrs0.eq(attrs1) 306 .flat_map(|attr| attr.syntax().descendants_with_tokens())
307 .flat_map(|it| it.into_token());
308 let attrs1 = attrs1
309 .flat_map(|attr| attr.syntax().descendants_with_tokens())
310 .flat_map(|it| it.into_token());
311 stdx::iter_eq_by(attrs0, attrs1, |tok, tok2| tok.text() == tok2.text())
309} 312}
310 313
311fn path_is_self(path: &ast::Path) -> bool { 314fn path_is_self(path: &ast::Path) -> bool {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 339014fd3..b700d025f 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -12,8 +12,7 @@ use std::{ffi::OsString, iter, path::PathBuf};
12use flycheck::FlycheckConfig; 12use flycheck::FlycheckConfig;
13use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; 13use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig};
14use ide_db::helpers::{ 14use ide_db::helpers::{
15 insert_use::{InsertUseConfig, PrefixKind}, 15 insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
16 merge_imports::MergeBehavior,
17 SnippetCap, 16 SnippetCap,
18}; 17};
19use lsp_types::{ClientCapabilities, MarkupKind}; 18use lsp_types::{ClientCapabilities, MarkupKind};
@@ -35,15 +34,18 @@ use crate::{
35// be specified directly in `package.json`. 34// be specified directly in `package.json`.
36config_data! { 35config_data! {
37 struct ConfigData { 36 struct ConfigData {
38 /// The strategy to use when inserting new imports or merging imports. 37 /// How imports should be grouped into use statements.
38 assist_importGranularity |
39 assist_importMergeBehavior | 39 assist_importMergeBehavior |
40 assist_importMergeBehaviour: MergeBehaviorDef = "\"crate\"", 40 assist_importMergeBehaviour: ImportGranularityDef = "\"crate\"",
41 /// Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
42 assist_importEnforceGranularity: bool = "false",
41 /// The path structure for newly inserted paths to use. 43 /// The path structure for newly inserted paths to use.
42 assist_importPrefix: ImportPrefixDef = "\"plain\"", 44 assist_importPrefix: ImportPrefixDef = "\"plain\"",
43 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. 45 /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
44 assist_importGroup: bool = "true", 46 assist_importGroup: bool = "true",
45 /// Show function name and docs in parameter hints. 47 /// Show function name and docs in parameter hints.
46 callInfo_full: bool = "true", 48 callInfo_full: bool = "true",
47 49
48 /// Automatically refresh project info via `cargo metadata` on 50 /// Automatically refresh project info via `cargo metadata` on
49 /// `Cargo.toml` changes. 51 /// `Cargo.toml` changes.
@@ -624,11 +626,13 @@ impl Config {
624 } 626 }
625 fn insert_use_config(&self) -> InsertUseConfig { 627 fn insert_use_config(&self) -> InsertUseConfig {
626 InsertUseConfig { 628 InsertUseConfig {
627 merge: match self.data.assist_importMergeBehavior { 629 granularity: match self.data.assist_importGranularity {
628 MergeBehaviorDef::None => None, 630 ImportGranularityDef::Preserve => ImportGranularity::Preserve,
629 MergeBehaviorDef::Crate => Some(MergeBehavior::Crate), 631 ImportGranularityDef::Item => ImportGranularity::Item,
630 MergeBehaviorDef::Module => Some(MergeBehavior::Module), 632 ImportGranularityDef::Crate => ImportGranularity::Crate,
633 ImportGranularityDef::Module => ImportGranularity::Module,
631 }, 634 },
635 enforce_granularity: self.data.assist_importEnforceGranularity,
632 prefix_kind: match self.data.assist_importPrefix { 636 prefix_kind: match self.data.assist_importPrefix {
633 ImportPrefixDef::Plain => PrefixKind::Plain, 637 ImportPrefixDef::Plain => PrefixKind::Plain,
634 ImportPrefixDef::ByCrate => PrefixKind::ByCrate, 638 ImportPrefixDef::ByCrate => PrefixKind::ByCrate,
@@ -748,8 +752,10 @@ enum ManifestOrProjectJson {
748 752
749#[derive(Deserialize, Debug, Clone)] 753#[derive(Deserialize, Debug, Clone)]
750#[serde(rename_all = "snake_case")] 754#[serde(rename_all = "snake_case")]
751enum MergeBehaviorDef { 755enum ImportGranularityDef {
752 None, 756 Preserve,
757 #[serde(alias = "none")]
758 Item,
753 #[serde(alias = "full")] 759 #[serde(alias = "full")]
754 Crate, 760 Crate,
755 #[serde(alias = "last")] 761 #[serde(alias = "last")]
@@ -782,7 +788,7 @@ macro_rules! _config_data {
782 (struct $name:ident { 788 (struct $name:ident {
783 $( 789 $(
784 $(#[doc=$doc:literal])* 790 $(#[doc=$doc:literal])*
785 $field:ident $(| $alias:ident)?: $ty:ty = $default:expr, 791 $field:ident $(| $alias:ident)*: $ty:ty = $default:expr,
786 )* 792 )*
787 }) => { 793 }) => {
788 #[allow(non_snake_case)] 794 #[allow(non_snake_case)]
@@ -794,7 +800,7 @@ macro_rules! _config_data {
794 $field: get_field( 800 $field: get_field(
795 &mut json, 801 &mut json,
796 stringify!($field), 802 stringify!($field),
797 None$(.or(Some(stringify!($alias))))?, 803 None$(.or(Some(stringify!($alias))))*,
798 $default, 804 $default,
799 ), 805 ),
800 )*} 806 )*}
@@ -931,6 +937,16 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
931 "Merge imports from the same module into a single `use` statement." 937 "Merge imports from the same module into a single `use` statement."
932 ], 938 ],
933 }, 939 },
940 "ImportGranularityDef" => set! {
941 "type": "string",
942 "enum": ["preserve", "crate", "module", "item"],
943 "enumDescriptions": [
944 "Do not change the granularity of any imports and preserve the original structure written by the developer.",
945 "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
946 "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
947 "Flatten imports so that each has its own use statement."
948 ],
949 },
934 "ImportPrefixDef" => set! { 950 "ImportPrefixDef" => set! {
935 "type": "string", 951 "type": "string",
936 "enum": [ 952 "enum": [
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 51041d7a0..aa12fd94b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -117,6 +117,16 @@ pub(crate) fn handle_view_hir(
117 Ok(res) 117 Ok(res)
118} 118}
119 119
120pub(crate) fn handle_view_item_tree(
121 snap: GlobalStateSnapshot,
122 params: lsp_ext::ViewItemTreeParams,
123) -> Result<String> {
124 let _p = profile::span("handle_view_item_tree");
125 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
126 let res = snap.analysis.view_item_tree(file_id)?;
127 Ok(res)
128}
129
120pub(crate) fn handle_view_crate_graph(snap: GlobalStateSnapshot, (): ()) -> Result<String> { 130pub(crate) fn handle_view_crate_graph(snap: GlobalStateSnapshot, (): ()) -> Result<String> {
121 let _p = profile::span("handle_view_crate_graph"); 131 let _p = profile::span("handle_view_crate_graph");
122 let dot = snap.analysis.view_crate_graph()??; 132 let dot = snap.analysis.view_crate_graph()??;
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index ba2790acb..781073fe5 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -13,7 +13,10 @@
13use std::{convert::TryFrom, sync::Arc}; 13use std::{convert::TryFrom, sync::Arc};
14 14
15use ide::{Change, CompletionConfig, FilePosition, TextSize}; 15use ide::{Change, CompletionConfig, FilePosition, TextSize};
16use ide_db::helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap}; 16use ide_db::helpers::{
17 insert_use::{ImportGranularity, InsertUseConfig},
18 SnippetCap,
19};
17use test_utils::project_root; 20use test_utils::project_root;
18use vfs::{AbsPathBuf, VfsPath}; 21use vfs::{AbsPathBuf, VfsPath};
19 22
@@ -133,8 +136,9 @@ fn integrated_completion_benchmark() {
133 add_call_argument_snippets: true, 136 add_call_argument_snippets: true,
134 snippet_cap: SnippetCap::new(true), 137 snippet_cap: SnippetCap::new(true),
135 insert_use: InsertUseConfig { 138 insert_use: InsertUseConfig {
136 merge: Some(MergeBehavior::Crate), 139 granularity: ImportGranularity::Crate,
137 prefix_kind: hir::PrefixKind::ByCrate, 140 prefix_kind: hir::PrefixKind::ByCrate,
141 enforce_granularity: true,
138 group: true, 142 group: true,
139 }, 143 },
140 }; 144 };
@@ -166,8 +170,9 @@ fn integrated_completion_benchmark() {
166 add_call_argument_snippets: true, 170 add_call_argument_snippets: true,
167 snippet_cap: SnippetCap::new(true), 171 snippet_cap: SnippetCap::new(true),
168 insert_use: InsertUseConfig { 172 insert_use: InsertUseConfig {
169 merge: Some(MergeBehavior::Crate), 173 granularity: ImportGranularity::Crate,
170 prefix_kind: hir::PrefixKind::ByCrate, 174 prefix_kind: hir::PrefixKind::ByCrate,
175 enforce_granularity: true,
171 group: true, 176 group: true,
172 }, 177 },
173 }; 178 };
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 34b53a7a8..905048793 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -70,6 +70,20 @@ impl Request for ViewCrateGraph {
70 const METHOD: &'static str = "rust-analyzer/viewCrateGraph"; 70 const METHOD: &'static str = "rust-analyzer/viewCrateGraph";
71} 71}
72 72
73#[derive(Deserialize, Serialize, Debug)]
74#[serde(rename_all = "camelCase")]
75pub struct ViewItemTreeParams {
76 pub text_document: TextDocumentIdentifier,
77}
78
79pub enum ViewItemTree {}
80
81impl Request for ViewItemTree {
82 type Params = ViewItemTreeParams;
83 type Result = String;
84 const METHOD: &'static str = "rust-analyzer/viewItemTree";
85}
86
73pub enum ExpandMacro {} 87pub enum ExpandMacro {}
74 88
75impl Request for ExpandMacro { 89impl Request for ExpandMacro {
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index 4e0791611..f837b89dd 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -514,6 +514,7 @@ impl GlobalState {
514 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree) 514 .on::<lsp_ext::SyntaxTree>(handlers::handle_syntax_tree)
515 .on::<lsp_ext::ViewHir>(handlers::handle_view_hir) 515 .on::<lsp_ext::ViewHir>(handlers::handle_view_hir)
516 .on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph) 516 .on::<lsp_ext::ViewCrateGraph>(handlers::handle_view_crate_graph)
517 .on::<lsp_ext::ViewItemTree>(handlers::handle_view_item_tree)
517 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro) 518 .on::<lsp_ext::ExpandMacro>(handlers::handle_expand_macro)
518 .on::<lsp_ext::ParentModule>(handlers::handle_parent_module) 519 .on::<lsp_ext::ParentModule>(handlers::handle_parent_module)
519 .on::<lsp_ext::Runnables>(handlers::handle_runnables) 520 .on::<lsp_ext::Runnables>(handlers::handle_runnables)
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 9dec46c78..0a3a56773 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -270,9 +270,12 @@ pub(crate) fn completion_item(
270 set_score(&mut lsp_item_with_ref, relevance); 270 set_score(&mut lsp_item_with_ref, relevance);
271 lsp_item_with_ref.label = 271 lsp_item_with_ref.label =
272 format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label); 272 format!("&{}{}", mutability.as_keyword_for_ref(), lsp_item_with_ref.label);
273 if let Some(lsp_types::CompletionTextEdit::Edit(it)) = &mut lsp_item_with_ref.text_edit 273 if let Some(it) = &mut lsp_item_with_ref.text_edit {
274 { 274 let new_text = match it {
275 it.new_text = format!("&{}{}", mutability.as_keyword_for_ref(), it.new_text); 275 lsp_types::CompletionTextEdit::Edit(it) => &mut it.new_text,
276 lsp_types::CompletionTextEdit::InsertAndReplace(it) => &mut it.new_text,
277 };
278 *new_text = format!("&{}{}", mutability.as_keyword_for_ref(), new_text);
276 } 279 }
277 vec![lsp_item_with_ref, lsp_item] 280 vec![lsp_item_with_ref, lsp_item]
278 } 281 }
@@ -1145,7 +1148,7 @@ mod tests {
1145 1148
1146 use ide::Analysis; 1149 use ide::Analysis;
1147 use ide_db::helpers::{ 1150 use ide_db::helpers::{
1148 insert_use::{InsertUseConfig, PrefixKind}, 1151 insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
1149 SnippetCap, 1152 SnippetCap,
1150 }; 1153 };
1151 1154
@@ -1177,8 +1180,9 @@ mod tests {
1177 add_call_argument_snippets: true, 1180 add_call_argument_snippets: true,
1178 snippet_cap: SnippetCap::new(true), 1181 snippet_cap: SnippetCap::new(true),
1179 insert_use: InsertUseConfig { 1182 insert_use: InsertUseConfig {
1180 merge: None, 1183 granularity: ImportGranularity::Item,
1181 prefix_kind: PrefixKind::Plain, 1184 prefix_kind: PrefixKind::Plain,
1185 enforce_granularity: true,
1182 group: true, 1186 group: true,
1183 }, 1187 },
1184 }, 1188 },
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index 340fcacfa..18d5fadb9 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -140,6 +140,34 @@ impl JodChild {
140 } 140 }
141} 141}
142 142
143// feature: iter_order_by
144// Iterator::eq_by
145pub fn iter_eq_by<I, I2, F>(this: I2, other: I, mut eq: F) -> bool
146where
147 I: IntoIterator,
148 I2: IntoIterator,
149 F: FnMut(I2::Item, I::Item) -> bool,
150{
151 let mut other = other.into_iter();
152 let mut this = this.into_iter();
153
154 loop {
155 let x = match this.next() {
156 None => return other.next().is_none(),
157 Some(val) => val,
158 };
159
160 let y = match other.next() {
161 None => return false,
162 Some(val) => val,
163 };
164
165 if !eq(x, y) {
166 return false;
167 }
168 }
169}
170
143#[cfg(test)] 171#[cfg(test)]
144mod tests { 172mod tests {
145 use super::*; 173 use super::*;
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index bef49238f..df8f98b5b 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -608,6 +608,29 @@ impl ast::Visibility {
608 None => VisibilityKind::Pub, 608 None => VisibilityKind::Pub,
609 } 609 }
610 } 610 }
611
612 pub fn is_eq_to(&self, other: &Self) -> bool {
613 match (self.kind(), other.kind()) {
614 (VisibilityKind::In(this), VisibilityKind::In(other)) => {
615 stdx::iter_eq_by(this.segments(), other.segments(), |lhs, rhs| {
616 lhs.kind().zip(rhs.kind()).map_or(false, |it| match it {
617 (PathSegmentKind::CrateKw, PathSegmentKind::CrateKw)
618 | (PathSegmentKind::SelfKw, PathSegmentKind::SelfKw)
619 | (PathSegmentKind::SuperKw, PathSegmentKind::SuperKw) => true,
620 (PathSegmentKind::Name(lhs), PathSegmentKind::Name(rhs)) => {
621 lhs.text() == rhs.text()
622 }
623 _ => false,
624 })
625 })
626 }
627 (VisibilityKind::PubSelf, VisibilityKind::PubSelf)
628 | (VisibilityKind::PubSuper, VisibilityKind::PubSuper)
629 | (VisibilityKind::PubCrate, VisibilityKind::PubCrate)
630 | (VisibilityKind::Pub, VisibilityKind::Pub) => true,
631 _ => false,
632 }
633 }
611} 634}
612 635
613impl ast::LifetimeParam { 636impl ast::LifetimeParam {
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 3c4eacfeb..fbe2ce1c9 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
1<!--- 1<!---
2lsp_ext.rs hash: 10a8988e6893e6b2 2lsp_ext.rs hash: 49f253e4a9307d4f
3 3
4If you need to change the above hash to make the test pass, please check if you 4If you need to change the above hash to make the test pass, please check if you
5need to adjust this doc as well and ping this issue: 5need to adjust this doc as well and ping this issue:
@@ -464,7 +464,7 @@ Clients are discouraged from but are allowed to use the `health` status to decid
464**Request:** 464**Request:**
465 465
466```typescript 466```typescript
467interface SyntaxTeeParams { 467interface SyntaxTreeParams {
468 textDocument: TextDocumentIdentifier, 468 textDocument: TextDocumentIdentifier,
469 range?: Range, 469 range?: Range,
470} 470}
@@ -486,6 +486,22 @@ Primarily for debugging, but very useful for all people working on rust-analyzer
486Returns a textual representation of the HIR of the function containing the cursor. 486Returns a textual representation of the HIR of the function containing the cursor.
487For debugging or when working on rust-analyzer itself. 487For debugging or when working on rust-analyzer itself.
488 488
489## View ItemTree
490
491**Method:** `rust-analyzer/viewItemTree`
492
493**Request:**
494
495```typescript
496interface ViewItemTreeParams {
497 textDocument: TextDocumentIdentifier,
498}
499```
500
501**Response:** `string`
502
503Returns a textual representation of the `ItemTree` of the currently open file, for debugging.
504
489## View Crate Graph 505## View Crate Graph
490 506
491**Method:** `rust-analyzer/viewCrateGraph` 507**Method:** `rust-analyzer/viewCrateGraph`
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index b32411887..c02bab7cc 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -1,7 +1,12 @@
1[[rust-analyzer.assist.importMergeBehavior]]rust-analyzer.assist.importMergeBehavior (default: `"crate"`):: 1[[rust-analyzer.assist.importGranularity]]rust-analyzer.assist.importGranularity (default: `"crate"`)::
2+ 2+
3-- 3--
4The strategy to use when inserting new imports or merging imports. 4How imports should be grouped into use statements.
5--
6[[rust-analyzer.assist.importEnforceGranularity]]rust-analyzer.assist.importEnforceGranularity (default: `false`)::
7+
8--
9Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.
5-- 10--
6[[rust-analyzer.assist.importPrefix]]rust-analyzer.assist.importPrefix (default: `"plain"`):: 11[[rust-analyzer.assist.importPrefix]]rust-analyzer.assist.importPrefix (default: `"plain"`)::
7+ 12+
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index f96c09a79..1d8a1930a 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -276,7 +276,7 @@ nvim_lsp.rust_analyzer.setup({
276 settings = { 276 settings = {
277 ["rust-analyzer"] = { 277 ["rust-analyzer"] = {
278 assist = { 278 assist = {
279 importMergeBehavior = "last", 279 importGranularity = "module",
280 importPrefix = "by_self", 280 importPrefix = "by_self",
281 }, 281 },
282 cargo = { 282 cargo = {
diff --git a/editors/code/package.json b/editors/code/package.json
index 99223c4e8..17d9281ff 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -110,6 +110,11 @@
110 "category": "Rust Analyzer" 110 "category": "Rust Analyzer"
111 }, 111 },
112 { 112 {
113 "command": "rust-analyzer.viewItemTree",
114 "title": "Debug ItemTree",
115 "category": "Rust Analyzer"
116 },
117 {
113 "command": "rust-analyzer.viewCrateGraph", 118 "command": "rust-analyzer.viewCrateGraph",
114 "title": "View Crate Graph", 119 "title": "View Crate Graph",
115 "category": "Rust Analyzer" 120 "category": "Rust Analyzer"
@@ -385,21 +390,28 @@
385 "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" 390 "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
386 }, 391 },
387 "$generated-start": false, 392 "$generated-start": false,
388 "rust-analyzer.assist.importMergeBehavior": { 393 "rust-analyzer.assist.importGranularity": {
389 "markdownDescription": "The strategy to use when inserting new imports or merging imports.", 394 "markdownDescription": "How imports should be grouped into use statements.",
390 "default": "crate", 395 "default": "crate",
391 "type": "string", 396 "type": "string",
392 "enum": [ 397 "enum": [
393 "none", 398 "preserve",
394 "crate", 399 "crate",
395 "module" 400 "module",
401 "item"
396 ], 402 ],
397 "enumDescriptions": [ 403 "enumDescriptions": [
398 "Do not merge imports at all.", 404 "Do not change the granularity of any imports and preserve the original structure written by the developer.",
399 "Merge imports from the same crate into a single `use` statement.", 405 "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.",
400 "Merge imports from the same module into a single `use` statement." 406 "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.",
407 "Flatten imports so that each has its own use statement."
401 ] 408 ]
402 }, 409 },
410 "rust-analyzer.assist.importEnforceGranularity": {
411 "markdownDescription": "Whether to enforce the import granularity setting for all files. If set to false rust-analyzer will try to keep import styles consistent per file.",
412 "default": false,
413 "type": "boolean"
414 },
403 "rust-analyzer.assist.importPrefix": { 415 "rust-analyzer.assist.importPrefix": {
404 "markdownDescription": "The path structure for newly inserted paths to use.", 416 "markdownDescription": "The path structure for newly inserted paths to use.",
405 "default": "plain", 417 "default": "plain",
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 8ab259af2..0fdb9fe05 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -429,6 +429,56 @@ export function viewHir(ctx: Ctx): Cmd {
429 }; 429 };
430} 430}
431 431
432export function viewItemTree(ctx: Ctx): Cmd {
433 const tdcp = new class implements vscode.TextDocumentContentProvider {
434 readonly uri = vscode.Uri.parse('rust-analyzer://viewItemTree/itemtree.rs');
435 readonly eventEmitter = new vscode.EventEmitter<vscode.Uri>();
436 constructor() {
437 vscode.workspace.onDidChangeTextDocument(this.onDidChangeTextDocument, this, ctx.subscriptions);
438 vscode.window.onDidChangeActiveTextEditor(this.onDidChangeActiveTextEditor, this, ctx.subscriptions);
439 }
440
441 private onDidChangeTextDocument(event: vscode.TextDocumentChangeEvent) {
442 if (isRustDocument(event.document)) {
443 // We need to order this after language server updates, but there's no API for that.
444 // Hence, good old sleep().
445 void sleep(10).then(() => this.eventEmitter.fire(this.uri));
446 }
447 }
448 private onDidChangeActiveTextEditor(editor: vscode.TextEditor | undefined) {
449 if (editor && isRustEditor(editor)) {
450 this.eventEmitter.fire(this.uri);
451 }
452 }
453
454 provideTextDocumentContent(_uri: vscode.Uri, ct: vscode.CancellationToken): vscode.ProviderResult<string> {
455 const rustEditor = ctx.activeRustEditor;
456 const client = ctx.client;
457 if (!rustEditor || !client) return '';
458
459 const params = {
460 textDocument: client.code2ProtocolConverter.asTextDocumentIdentifier(rustEditor.document),
461 };
462 return client.sendRequest(ra.viewItemTree, params, ct);
463 }
464
465 get onDidChange(): vscode.Event<vscode.Uri> {
466 return this.eventEmitter.event;
467 }
468 };
469
470 ctx.pushCleanup(vscode.workspace.registerTextDocumentContentProvider('rust-analyzer', tdcp));
471
472 return async () => {
473 const document = await vscode.workspace.openTextDocument(tdcp.uri);
474 tdcp.eventEmitter.fire(tdcp.uri);
475 void await vscode.window.showTextDocument(document, {
476 viewColumn: vscode.ViewColumn.Two,
477 preserveFocus: true
478 });
479 };
480}
481
432export function viewCrateGraph(ctx: Ctx): Cmd { 482export function viewCrateGraph(ctx: Ctx): Cmd {
433 return async () => { 483 return async () => {
434 const panel = vscode.window.createWebviewPanel("rust-analyzer.crate-graph", "rust-analyzer crate graph", vscode.ViewColumn.Two); 484 const panel = vscode.window.createWebviewPanel("rust-analyzer.crate-graph", "rust-analyzer crate graph", vscode.ViewColumn.Two);
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index aa745a65c..6d5c2ea72 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -27,6 +27,12 @@ export const syntaxTree = new lc.RequestType<SyntaxTreeParams, string, void>("ru
27 27
28export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir"); 28export const viewHir = new lc.RequestType<lc.TextDocumentPositionParams, string, void>("rust-analyzer/viewHir");
29 29
30export interface ViewItemTreeParams {
31 textDocument: lc.TextDocumentIdentifier;
32}
33
34export const viewItemTree = new lc.RequestType<ViewItemTreeParams, string, void>("rust-analyzer/viewItemTree");
35
30export const viewCrateGraph = new lc.RequestType0<string, void>("rust-analyzer/viewCrateGraph"); 36export const viewCrateGraph = new lc.RequestType0<string, void>("rust-analyzer/viewCrateGraph");
31 37
32export interface ExpandMacroParams { 38export interface ExpandMacroParams {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 516322d03..92c797d47 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -106,6 +106,7 @@ async function tryActivate(context: vscode.ExtensionContext) {
106 ctx.registerCommand('parentModule', commands.parentModule); 106 ctx.registerCommand('parentModule', commands.parentModule);
107 ctx.registerCommand('syntaxTree', commands.syntaxTree); 107 ctx.registerCommand('syntaxTree', commands.syntaxTree);
108 ctx.registerCommand('viewHir', commands.viewHir); 108 ctx.registerCommand('viewHir', commands.viewHir);
109 ctx.registerCommand('viewItemTree', commands.viewItemTree);
109 ctx.registerCommand('viewCrateGraph', commands.viewCrateGraph); 110 ctx.registerCommand('viewCrateGraph', commands.viewCrateGraph);
110 ctx.registerCommand('expandMacro', commands.expandMacro); 111 ctx.registerCommand('expandMacro', commands.expandMacro);
111 ctx.registerCommand('run', commands.run); 112 ctx.registerCommand('run', commands.run);