aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/hir/src/lib.rs36
-rw-r--r--crates/hir_def/src/attr.rs41
-rw-r--r--crates/hir_def/src/child_by_source.rs4
-rw-r--r--crates/hir_def/src/lib.rs13
-rw-r--r--crates/hir_def/src/nameres.rs28
-rw-r--r--crates/hir_def/src/nameres/collector.rs25
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs51
-rw-r--r--crates/hir_expand/src/builtin_derive.rs10
-rw-r--r--crates/hir_expand/src/builtin_macro.rs7
-rw-r--r--crates/hir_expand/src/db.rs7
-rw-r--r--crates/hir_expand/src/eager.rs5
-rw-r--r--crates/hir_expand/src/input.rs95
-rw-r--r--crates/hir_expand/src/lib.rs22
-rw-r--r--crates/hir_expand/src/proc_macro.rs102
-rw-r--r--crates/hir_ty/src/autoderef.rs44
-rw-r--r--crates/hir_ty/src/builder.rs12
-rw-r--r--crates/hir_ty/src/chalk_cast.rs73
-rw-r--r--crates/hir_ty/src/chalk_db.rs (renamed from crates/hir_ty/src/traits/chalk.rs)223
-rw-r--r--crates/hir_ty/src/chalk_ext.rs2
-rw-r--r--crates/hir_ty/src/db.rs52
-rw-r--r--crates/hir_ty/src/diagnostics.rs2
-rw-r--r--crates/hir_ty/src/display.rs52
-rw-r--r--crates/hir_ty/src/infer.rs26
-rw-r--r--crates/hir_ty/src/infer/coerce.rs10
-rw-r--r--crates/hir_ty/src/infer/expr.rs12
-rw-r--r--crates/hir_ty/src/infer/pat.rs4
-rw-r--r--crates/hir_ty/src/infer/path.rs2
-rw-r--r--crates/hir_ty/src/infer/unify.rs166
-rw-r--r--crates/hir_ty/src/interner.rs (renamed from crates/hir_ty/src/traits/chalk/interner.rs)127
-rw-r--r--crates/hir_ty/src/lib.rs216
-rw-r--r--crates/hir_ty/src/lower.rs48
-rw-r--r--crates/hir_ty/src/mapping.rs154
-rw-r--r--crates/hir_ty/src/method_resolution.rs103
-rw-r--r--crates/hir_ty/src/primitive.rs5
-rw-r--r--crates/hir_ty/src/tests/regression.rs38
-rw-r--r--crates/hir_ty/src/tests/traits.rs30
-rw-r--r--crates/hir_ty/src/tls.rs (renamed from crates/hir_ty/src/traits/chalk/tls.rs)14
-rw-r--r--crates/hir_ty/src/traits.rs44
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs546
-rw-r--r--crates/hir_ty/src/types.rs549
-rw-r--r--crates/hir_ty/src/utils.rs18
-rw-r--r--crates/hir_ty/src/walk.rs287
-rw-r--r--crates/ide/src/diagnostics.rs16
-rw-r--r--crates/ide/src/expand_macro.rs43
-rw-r--r--crates/ide/src/folding_ranges.rs17
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs14
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs96
-rw-r--r--crates/ide/src/typing/on_enter.rs20
-rw-r--r--crates/ide_assists/src/handlers/remove_dbg.rs105
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/src/to_proto.rs3
-rw-r--r--crates/test_utils/src/bench_fixture.rs3
52 files changed, 1447 insertions, 2177 deletions
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 0afc06906..eba46a056 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1580,11 +1580,24 @@ impl Impl {
1580 ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty)) 1580 ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
1581 }; 1581 };
1582 1582
1583 let fp = TyFingerprint::for_inherent_impl(&ty);
1584 let fp = if let Some(fp) = fp {
1585 fp
1586 } else {
1587 return Vec::new();
1588 };
1589
1583 let mut all = Vec::new(); 1590 let mut all = Vec::new();
1584 def_crates.iter().for_each(|&id| { 1591 def_crates.iter().for_each(|&id| {
1585 all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter)) 1592 all.extend(
1593 db.inherent_impls_in_crate(id)
1594 .for_self_ty(&ty)
1595 .into_iter()
1596 .cloned()
1597 .map(Self::from)
1598 .filter(filter),
1599 )
1586 }); 1600 });
1587 let fp = TyFingerprint::for_impl(&ty);
1588 for id in def_crates 1601 for id in def_crates
1589 .iter() 1602 .iter()
1590 .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db)) 1603 .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
@@ -1592,13 +1605,12 @@ impl Impl {
1592 .chain(def_crates.iter().copied()) 1605 .chain(def_crates.iter().copied())
1593 .unique() 1606 .unique()
1594 { 1607 {
1595 match fp { 1608 all.extend(
1596 Some(fp) => all.extend( 1609 db.trait_impls_in_crate(id)
1597 db.trait_impls_in_crate(id).for_self_ty(fp).map(Self::from).filter(filter), 1610 .for_self_ty_without_blanket_impls(fp)
1598 ), 1611 .map(Self::from)
1599 None => all 1612 .filter(filter),
1600 .extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter)), 1613 );
1601 }
1602 } 1614 }
1603 all 1615 all
1604 } 1616 }
@@ -1825,7 +1837,7 @@ impl Type {
1825 Solution::Unique(s) => s 1837 Solution::Unique(s) => s
1826 .value 1838 .value
1827 .subst 1839 .subst
1828 .interned() 1840 .as_slice(&Interner)
1829 .first() 1841 .first()
1830 .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())), 1842 .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
1831 Solution::Ambig(_) => None, 1843 Solution::Ambig(_) => None,
@@ -1903,7 +1915,9 @@ impl Type {
1903 | TyKind::Dyn(_) 1915 | TyKind::Dyn(_)
1904 | TyKind::Function(_) 1916 | TyKind::Function(_)
1905 | TyKind::Alias(_) 1917 | TyKind::Alias(_)
1906 | TyKind::Foreign(_) => false, 1918 | TyKind::Foreign(_)
1919 | TyKind::Generator(..)
1920 | TyKind::GeneratorWitness(..) => false,
1907 } 1921 }
1908 } 1922 }
1909 } 1923 }
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index d9df7564d..786fad6e1 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -9,7 +9,7 @@ use std::{
9use base_db::CrateId; 9use base_db::CrateId;
10use cfg::{CfgExpr, CfgOptions}; 10use cfg::{CfgExpr, CfgOptions};
11use either::Either; 11use either::Either;
12use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; 12use hir_expand::{hygiene::Hygiene, name::AsName, AstId, AttrId, InFile};
13use itertools::Itertools; 13use itertools::Itertools;
14use la_arena::ArenaMap; 14use la_arena::ArenaMap;
15use mbe::ast_to_token_tree; 15use mbe::ast_to_token_tree;
@@ -98,13 +98,16 @@ impl RawAttrs {
98 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self { 98 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self {
99 let entries = collect_attrs(owner) 99 let entries = collect_attrs(owner)
100 .enumerate() 100 .enumerate()
101 .flat_map(|(i, attr)| match attr { 101 .flat_map(|(i, attr)| {
102 Either::Left(attr) => Attr::from_src(attr, hygiene, i as u32), 102 let index = AttrId(i as u32);
103 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 103 match attr {
104 index: i as u32, 104 Either::Left(attr) => Attr::from_src(attr, hygiene, index),
105 input: Some(AttrInput::Literal(SmolStr::new(doc))), 105 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
106 path: Interned::new(ModPath::from(hir_expand::name!(doc))), 106 id: index,
107 }), 107 input: Some(AttrInput::Literal(SmolStr::new(doc))),
108 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
109 }),
110 }
108 }) 111 })
109 .collect::<Arc<_>>(); 112 .collect::<Arc<_>>();
110 113
@@ -161,7 +164,7 @@ impl RawAttrs {
161 let cfg = parts.next().unwrap(); 164 let cfg = parts.next().unwrap();
162 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; 165 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
163 let cfg = CfgExpr::parse(&cfg); 166 let cfg = CfgExpr::parse(&cfg);
164 let index = attr.index; 167 let index = attr.id;
165 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { 168 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
166 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; 169 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
167 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; 170 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
@@ -468,7 +471,7 @@ impl AttrsWithOwner {
468 ) -> Option<(Documentation, DocsRangeMap)> { 471 ) -> Option<(Documentation, DocsRangeMap)> {
469 // FIXME: code duplication in `docs` above 472 // FIXME: code duplication in `docs` above
470 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { 473 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? {
471 AttrInput::Literal(s) => Some((s, attr.index)), 474 AttrInput::Literal(s) => Some((s, attr.id)),
472 AttrInput::TokenTree(_) => None, 475 AttrInput::TokenTree(_) => None,
473 }); 476 });
474 let indent = docs 477 let indent = docs
@@ -560,8 +563,8 @@ impl AttrSourceMap {
560 /// the attribute represented by `Attr`. 563 /// the attribute represented by `Attr`.
561 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> { 564 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> {
562 self.attrs 565 self.attrs
563 .get(attr.index as usize) 566 .get(attr.id.0 as usize)
564 .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index)) 567 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", attr.id))
565 .as_ref() 568 .as_ref()
566 } 569 }
567} 570}
@@ -572,7 +575,7 @@ pub struct DocsRangeMap {
572 // (docstring-line-range, attr_index, attr-string-range) 575 // (docstring-line-range, attr_index, attr-string-range)
573 // a mapping from the text range of a line of the [`Documentation`] to the attribute index and 576 // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
574 // the original (untrimmed) syntax doc line 577 // the original (untrimmed) syntax doc line
575 mapping: Vec<(TextRange, u32, TextRange)>, 578 mapping: Vec<(TextRange, AttrId, TextRange)>,
576} 579}
577 580
578impl DocsRangeMap { 581impl DocsRangeMap {
@@ -585,7 +588,7 @@ impl DocsRangeMap {
585 588
586 let relative_range = range - line_docs_range.start(); 589 let relative_range = range - line_docs_range.start();
587 590
588 let &InFile { file_id, value: ref source } = &self.source[idx as usize]; 591 let &InFile { file_id, value: ref source } = &self.source[idx.0 as usize];
589 match source { 592 match source {
590 Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here 593 Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here
591 // as well as for whats done in syntax highlight doc injection 594 // as well as for whats done in syntax highlight doc injection
@@ -606,7 +609,7 @@ impl DocsRangeMap {
606 609
607#[derive(Debug, Clone, PartialEq, Eq)] 610#[derive(Debug, Clone, PartialEq, Eq)]
608pub struct Attr { 611pub struct Attr {
609 index: u32, 612 pub(crate) id: AttrId,
610 pub(crate) path: Interned<ModPath>, 613 pub(crate) path: Interned<ModPath>,
611 pub(crate) input: Option<AttrInput>, 614 pub(crate) input: Option<AttrInput>,
612} 615}
@@ -620,7 +623,7 @@ pub enum AttrInput {
620} 623}
621 624
622impl Attr { 625impl Attr {
623 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { 626 fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> {
624 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); 627 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
625 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { 628 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
626 let value = match lit.kind() { 629 let value = match lit.kind() {
@@ -633,7 +636,7 @@ impl Attr {
633 } else { 636 } else {
634 None 637 None
635 }; 638 };
636 Some(Attr { index, path, input }) 639 Some(Attr { id, path, input })
637 } 640 }
638 641
639 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths 642 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
@@ -748,9 +751,7 @@ fn collect_attrs(
748 .chain(inner_docs.into_iter().flatten()) 751 .chain(inner_docs.into_iter().flatten())
749 .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text))); 752 .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text)));
750 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved 753 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
751 let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); 754 docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).map(|(_, attr)| attr)
752
753 attrs.into_iter().map(|(_, attr)| attr)
754} 755}
755 756
756pub(crate) fn variants_attrs_source_map( 757pub(crate) fn variants_attrs_source_map(
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index f40a7f80d..f2e809ca9 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -80,6 +80,10 @@ impl ChildBySource for ModuleId {
80impl ChildBySource for ItemScope { 80impl ChildBySource for ItemScope {
81 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) { 81 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
82 self.declarations().for_each(|item| add_module_def(db, res, item)); 82 self.declarations().for_each(|item| add_module_def(db, res, item));
83 self.unnamed_consts().for_each(|konst| {
84 let src = konst.lookup(db).source(db);
85 res[keys::CONST].insert(src, konst);
86 });
83 self.impls().for_each(|imp| add_impl(db, res, imp)); 87 self.impls().for_each(|imp| add_impl(db, res, imp));
84 88
85 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { 89 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index e2af0e514..d69116d51 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -62,7 +62,7 @@ use hir_expand::{
62 ast_id_map::FileAstId, 62 ast_id_map::FileAstId,
63 eager::{expand_eager_macro, ErrorEmitted, ErrorSink}, 63 eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
64 hygiene::Hygiene, 64 hygiene::Hygiene,
65 AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 65 AstId, AttrId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
66}; 66};
67use la_arena::Idx; 67use la_arena::Idx;
68use nameres::DefMap; 68use nameres::DefMap;
@@ -690,13 +690,16 @@ fn macro_call_as_call_id(
690 ) 690 )
691 .map(MacroCallId::from) 691 .map(MacroCallId::from)
692 } else { 692 } else {
693 Ok(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(call.ast_id)).into()) 693 Ok(def
694 .as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike { ast_id: call.ast_id })
695 .into())
694 }; 696 };
695 Ok(res) 697 Ok(res)
696} 698}
697 699
698fn derive_macro_as_call_id( 700fn derive_macro_as_call_id(
699 item_attr: &AstIdWithPath<ast::Item>, 701 item_attr: &AstIdWithPath<ast::Item>,
702 derive_attr: AttrId,
700 db: &dyn db::DefDatabase, 703 db: &dyn db::DefDatabase,
701 krate: CrateId, 704 krate: CrateId,
702 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 705 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
@@ -707,7 +710,11 @@ fn derive_macro_as_call_id(
707 .as_lazy_macro( 710 .as_lazy_macro(
708 db.upcast(), 711 db.upcast(),
709 krate, 712 krate,
710 MacroCallKind::Derive(item_attr.ast_id, last_segment.to_string()), 713 MacroCallKind::Derive {
714 ast_id: item_attr.ast_id,
715 derive_name: last_segment.to_string(),
716 derive_attr,
717 },
711 ) 718 )
712 .into(); 719 .into();
713 Ok(res) 720 Ok(res)
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 7dd68219f..9e181751c 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -613,12 +613,12 @@ mod diagnostics {
613 DiagnosticKind::UnresolvedProcMacro { ast } => { 613 DiagnosticKind::UnresolvedProcMacro { ast } => {
614 let mut precise_location = None; 614 let mut precise_location = None;
615 let (file, ast, name) = match ast { 615 let (file, ast, name) = match ast {
616 MacroCallKind::FnLike(ast) => { 616 MacroCallKind::FnLike { ast_id } => {
617 let node = ast.to_node(db.upcast()); 617 let node = ast_id.to_node(db.upcast());
618 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) 618 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
619 } 619 }
620 MacroCallKind::Derive(ast, name) => { 620 MacroCallKind::Derive { ast_id, derive_name, .. } => {
621 let node = ast.to_node(db.upcast()); 621 let node = ast_id.to_node(db.upcast());
622 622
623 // Compute the precise location of the macro name's token in the derive 623 // Compute the precise location of the macro name's token in the derive
624 // list. 624 // list.
@@ -639,7 +639,7 @@ mod diagnostics {
639 }); 639 });
640 for token in tokens { 640 for token in tokens {
641 if token.kind() == SyntaxKind::IDENT 641 if token.kind() == SyntaxKind::IDENT
642 && token.text() == name.as_str() 642 && token.text() == derive_name.as_str()
643 { 643 {
644 precise_location = Some(token.text_range()); 644 precise_location = Some(token.text_range());
645 break 'outer; 645 break 'outer;
@@ -648,9 +648,9 @@ mod diagnostics {
648 } 648 }
649 649
650 ( 650 (
651 ast.file_id, 651 ast_id.file_id,
652 SyntaxNodePtr::from(AstPtr::new(&node)), 652 SyntaxNodePtr::from(AstPtr::new(&node)),
653 Some(name.clone()), 653 Some(derive_name.clone()),
654 ) 654 )
655 } 655 }
656 }; 656 };
@@ -669,13 +669,13 @@ mod diagnostics {
669 669
670 DiagnosticKind::MacroError { ast, message } => { 670 DiagnosticKind::MacroError { ast, message } => {
671 let (file, ast) = match ast { 671 let (file, ast) = match ast {
672 MacroCallKind::FnLike(ast) => { 672 MacroCallKind::FnLike { ast_id, .. } => {
673 let node = ast.to_node(db.upcast()); 673 let node = ast_id.to_node(db.upcast());
674 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 674 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
675 } 675 }
676 MacroCallKind::Derive(ast, _) => { 676 MacroCallKind::Derive { ast_id, .. } => {
677 let node = ast.to_node(db.upcast()); 677 let node = ast_id.to_node(db.upcast());
678 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 678 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
679 } 679 }
680 }; 680 };
681 sink.push(MacroError { file, node: ast, message: message.clone() }); 681 sink.push(MacroError { file, node: ast, message: message.clone() });
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 492d8c71f..fb4ddff5e 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,7 +13,7 @@ use hir_expand::{
13 builtin_macro::find_builtin_macro, 13 builtin_macro::find_builtin_macro,
14 name::{AsName, Name}, 14 name::{AsName, Name},
15 proc_macro::ProcMacroExpander, 15 proc_macro::ProcMacroExpander,
16 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 16 AttrId, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
@@ -216,7 +216,7 @@ struct MacroDirective {
216#[derive(Clone, Debug, Eq, PartialEq)] 216#[derive(Clone, Debug, Eq, PartialEq)]
217enum MacroDirectiveKind { 217enum MacroDirectiveKind {
218 FnLike { ast_id: AstIdWithPath<ast::MacroCall> }, 218 FnLike { ast_id: AstIdWithPath<ast::MacroCall> },
219 Derive { ast_id: AstIdWithPath<ast::Item> }, 219 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
220} 220}
221 221
222struct DefData<'a> { 222struct DefData<'a> {
@@ -478,7 +478,7 @@ impl DefCollector<'_> {
478 self.def_map.edition, 478 self.def_map.edition,
479 ); 479 );
480 480
481 let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name); 481 let res = self.def_map.resolve_name_in_extern_prelude(self.db, &extern_crate.name);
482 482
483 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { 483 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
484 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); 484 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
@@ -534,6 +534,7 @@ impl DefCollector<'_> {
534 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 534 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
535 if import.is_extern_crate { 535 if import.is_extern_crate {
536 let res = self.def_map.resolve_name_in_extern_prelude( 536 let res = self.def_map.resolve_name_in_extern_prelude(
537 self.db,
537 &import 538 &import
538 .path 539 .path
539 .as_ident() 540 .as_ident()
@@ -831,12 +832,16 @@ impl DefCollector<'_> {
831 Err(UnresolvedMacro) | Ok(Err(_)) => {} 832 Err(UnresolvedMacro) | Ok(Err(_)) => {}
832 } 833 }
833 } 834 }
834 MacroDirectiveKind::Derive { ast_id } => { 835 MacroDirectiveKind::Derive { ast_id, derive_attr } => {
835 match derive_macro_as_call_id(ast_id, self.db, self.def_map.krate, |path| { 836 match derive_macro_as_call_id(
836 self.resolve_derive_macro(directive.module_id, &path) 837 ast_id,
837 }) { 838 *derive_attr,
839 self.db,
840 self.def_map.krate,
841 |path| self.resolve_derive_macro(directive.module_id, &path),
842 ) {
838 Ok(call_id) => { 843 Ok(call_id) => {
839 resolved.push((directive.module_id, call_id, 0)); 844 resolved.push((directive.module_id, call_id, directive.depth));
840 res = ReachedFixedPoint::No; 845 res = ReachedFixedPoint::No;
841 return false; 846 return false;
842 } 847 }
@@ -1368,7 +1373,7 @@ impl ModCollector<'_, '_> {
1368 self.def_collector.unexpanded_macros.push(MacroDirective { 1373 self.def_collector.unexpanded_macros.push(MacroDirective {
1369 module_id: self.module_id, 1374 module_id: self.module_id,
1370 depth: self.macro_depth + 1, 1375 depth: self.macro_depth + 1,
1371 kind: MacroDirectiveKind::Derive { ast_id }, 1376 kind: MacroDirectiveKind::Derive { ast_id, derive_attr: derive.id },
1372 }); 1377 });
1373 } 1378 }
1374 } 1379 }
@@ -1520,7 +1525,7 @@ impl ModCollector<'_, '_> {
1520 // Built-in macro failed eager expansion. 1525 // Built-in macro failed eager expansion.
1521 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( 1526 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
1522 self.module_id, 1527 self.module_id,
1523 MacroCallKind::FnLike(ast_id.ast_id), 1528 MacroCallKind::FnLike { ast_id: ast_id.ast_id },
1524 error.unwrap().to_string(), 1529 error.unwrap().to_string(),
1525 )); 1530 ));
1526 return; 1531 return;
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 60471937c..ccc9f22eb 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -60,12 +60,26 @@ impl ResolvePathResult {
60} 60}
61 61
62impl DefMap { 62impl DefMap {
63 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 63 pub(super) fn resolve_name_in_extern_prelude(
64 &self,
65 db: &dyn DefDatabase,
66 name: &Name,
67 ) -> PerNs {
64 if name == &name!(self) { 68 if name == &name!(self) {
65 cov_mark::hit!(extern_crate_self_as); 69 cov_mark::hit!(extern_crate_self_as);
66 return PerNs::types(self.module_id(self.root).into(), Visibility::Public); 70 return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
67 } 71 }
68 self.extern_prelude 72
73 let arc;
74 let root = match self.block {
75 Some(_) => {
76 arc = self.crate_root(db).def_map(db);
77 &*arc
78 }
79 None => self,
80 };
81
82 root.extern_prelude
69 .get(name) 83 .get(name)
70 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) 84 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
71 } 85 }
@@ -191,7 +205,7 @@ impl DefMap {
191 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 205 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
192 }; 206 };
193 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 207 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
194 self.resolve_name_in_crate_root_or_extern_prelude(&segment) 208 self.resolve_name_in_crate_root_or_extern_prelude(db, &segment)
195 } 209 }
196 PathKind::Plain => { 210 PathKind::Plain => {
197 let (_, segment) = match segments.next() { 211 let (_, segment) = match segments.next() {
@@ -384,24 +398,31 @@ impl DefMap {
384 } 398 }
385 } 399 }
386 }; 400 };
387 // Give precedence to names in outer `DefMap`s over the extern prelude; only check prelude 401 let from_extern_prelude = self
388 // from the crate DefMap. 402 .extern_prelude
389 let from_extern_prelude = match self.block { 403 .get(name)
390 Some(_) => PerNs::none(), 404 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));
391 None => self
392 .extern_prelude
393 .get(name)
394 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)),
395 };
396 405
397 let from_prelude = self.resolve_in_prelude(db, name); 406 let from_prelude = self.resolve_in_prelude(db, name);
398 407
399 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) 408 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
400 } 409 }
401 410
402 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { 411 fn resolve_name_in_crate_root_or_extern_prelude(
403 let from_crate_root = self[self.root].scope.get(name); 412 &self,
404 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 413 db: &dyn DefDatabase,
414 name: &Name,
415 ) -> PerNs {
416 let arc;
417 let crate_def_map = match self.block {
418 Some(_) => {
419 arc = self.crate_root(db).def_map(db);
420 &arc
421 }
422 None => self,
423 };
424 let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name);
425 let from_extern_prelude = self.resolve_name_in_extern_prelude(db, name);
405 426
406 from_crate_root.or(from_extern_prelude) 427 from_crate_root.or(from_extern_prelude)
407 } 428 }
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index 6ece4b289..537c03028 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -269,7 +269,7 @@ mod tests {
269 use expect_test::{expect, Expect}; 269 use expect_test::{expect, Expect};
270 use name::AsName; 270 use name::AsName;
271 271
272 use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; 272 use crate::{test_db::TestDB, AstId, AttrId, MacroCallId, MacroCallKind, MacroCallLoc};
273 273
274 use super::*; 274 use super::*;
275 275
@@ -308,7 +308,7 @@ $0
308 308
309 let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); 309 let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap();
310 310
311 let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); 311 let ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
312 312
313 let loc = MacroCallLoc { 313 let loc = MacroCallLoc {
314 def: MacroDefId { 314 def: MacroDefId {
@@ -317,7 +317,11 @@ $0
317 local_inner: false, 317 local_inner: false,
318 }, 318 },
319 krate: CrateId(0), 319 krate: CrateId(0),
320 kind: MacroCallKind::Derive(attr_id, name.to_string()), 320 kind: MacroCallKind::Derive {
321 ast_id,
322 derive_name: name.to_string(),
323 derive_attr: AttrId(0),
324 },
321 }; 325 };
322 326
323 let id: MacroCallId = db.intern_macro(loc).into(); 327 let id: MacroCallId = db.intern_macro(loc).into();
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index a7d0f5b1f..80365fc16 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -566,10 +566,9 @@ mod tests {
566 let loc = MacroCallLoc { 566 let loc = MacroCallLoc {
567 def, 567 def,
568 krate, 568 krate,
569 kind: MacroCallKind::FnLike(AstId::new( 569 kind: MacroCallKind::FnLike {
570 file_id.into(), 570 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)),
571 ast_id_map.ast_id(&macro_call), 571 },
572 )),
573 }; 572 };
574 573
575 let id: MacroCallId = db.intern_macro(loc).into(); 574 let id: MacroCallId = db.intern_macro(loc).into();
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 10fe60821..95dc12744 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -14,9 +14,9 @@ use syntax::{
14}; 14};
15 15
16use crate::{ 16use crate::{
17 ast_id_map::AstIdMap, hygiene::HygieneFrame, BuiltinDeriveExpander, BuiltinFnLikeExpander, 17 ast_id_map::AstIdMap, hygiene::HygieneFrame, input::process_macro_input, BuiltinDeriveExpander,
18 EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId, MacroCallId, MacroCallLoc, 18 BuiltinFnLikeExpander, EagerCallLoc, EagerMacroId, HirFileId, HirFileIdRepr, LazyMacroId,
19 MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander, 19 MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, ProcMacroExpander,
20}; 20};
21 21
22/// Total limit on the number of tokens produced by any macro invocation. 22/// Total limit on the number of tokens produced by any macro invocation.
@@ -191,6 +191,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
191 }; 191 };
192 let loc = db.lookup_intern_macro(id); 192 let loc = db.lookup_intern_macro(id);
193 let arg = loc.kind.arg(db)?; 193 let arg = loc.kind.arg(db)?;
194 let arg = process_macro_input(db, arg, id);
194 Some(arg.green()) 195 Some(arg.green())
195} 196}
196 197
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 9705526fa..ef126e4ad 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -174,8 +174,9 @@ fn lazy_expand(
174) -> ExpandResult<Option<InFile<SyntaxNode>>> { 174) -> ExpandResult<Option<InFile<SyntaxNode>>> {
175 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value); 175 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
176 176
177 let id: MacroCallId = 177 let id: MacroCallId = def
178 def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); 178 .as_lazy_macro(db, krate, MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id) })
179 .into();
179 180
180 let err = db.macro_expand_error(id); 181 let err = db.macro_expand_error(id);
181 let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)); 182 let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));
diff --git a/crates/hir_expand/src/input.rs b/crates/hir_expand/src/input.rs
new file mode 100644
index 000000000..d1f22aba4
--- /dev/null
+++ b/crates/hir_expand/src/input.rs
@@ -0,0 +1,95 @@
1//! Macro input conditioning.
2
3use syntax::{
4 ast::{self, AttrsOwner},
5 AstNode, SyntaxNode,
6};
7
8use crate::{
9 db::AstDatabase,
10 name::{name, AsName},
11 AttrId, LazyMacroId, MacroCallKind, MacroCallLoc,
12};
13
14pub(crate) fn process_macro_input(
15 db: &dyn AstDatabase,
16 node: SyntaxNode,
17 id: LazyMacroId,
18) -> SyntaxNode {
19 let loc: MacroCallLoc = db.lookup_intern_macro(id);
20
21 match loc.kind {
22 MacroCallKind::FnLike { .. } => node,
23 MacroCallKind::Derive { derive_attr, .. } => {
24 let item = match ast::Item::cast(node.clone()) {
25 Some(item) => item,
26 None => return node,
27 };
28
29 remove_derives_up_to(item, derive_attr).syntax().clone()
30 }
31 }
32}
33
34/// Removes `#[derive]` attributes from `item`, up to `attr`.
35fn remove_derives_up_to(item: ast::Item, attr: AttrId) -> ast::Item {
36 let item = item.clone_for_update();
37 let idx = attr.0 as usize;
38 for attr in item.attrs().take(idx + 1) {
39 if let Some(name) =
40 attr.path().and_then(|path| path.as_single_segment()).and_then(|seg| seg.name_ref())
41 {
42 if name.as_name() == name![derive] {
43 attr.syntax().detach();
44 }
45 }
46 }
47 item
48}
49
50#[cfg(test)]
51mod tests {
52 use base_db::fixture::WithFixture;
53 use base_db::SourceDatabase;
54 use expect_test::{expect, Expect};
55
56 use crate::test_db::TestDB;
57
58 use super::*;
59
60 fn test_remove_derives_up_to(attr: AttrId, ra_fixture: &str, expect: Expect) {
61 let (db, file_id) = TestDB::with_single_file(&ra_fixture);
62 let parsed = db.parse(file_id);
63
64 let mut items: Vec<_> =
65 parsed.syntax_node().descendants().filter_map(ast::Item::cast).collect();
66 assert_eq!(items.len(), 1);
67
68 let item = remove_derives_up_to(items.pop().unwrap(), attr);
69 expect.assert_eq(&item.to_string());
70 }
71
72 #[test]
73 fn remove_derive() {
74 test_remove_derives_up_to(
75 AttrId(2),
76 r#"
77#[allow(unused)]
78#[derive(Copy)]
79#[derive(Hello)]
80#[derive(Clone)]
81struct A {
82 bar: u32
83}
84 "#,
85 expect![[r#"
86#[allow(unused)]
87
88
89#[derive(Clone)]
90struct A {
91 bar: u32
92}"#]],
93 );
94 }
95}
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 3e332ee47..7349fdfe4 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -14,6 +14,7 @@ pub mod builtin_macro;
14pub mod proc_macro; 14pub mod proc_macro;
15pub mod quote; 15pub mod quote;
16pub mod eager; 16pub mod eager;
17mod input;
17 18
18use either::Either; 19use either::Either;
19pub use mbe::{ExpandError, ExpandResult}; 20pub use mbe::{ExpandError, ExpandResult};
@@ -290,22 +291,27 @@ pub struct MacroCallLoc {
290 291
291#[derive(Debug, Clone, PartialEq, Eq, Hash)] 292#[derive(Debug, Clone, PartialEq, Eq, Hash)]
292pub enum MacroCallKind { 293pub enum MacroCallKind {
293 FnLike(AstId<ast::MacroCall>), 294 FnLike { ast_id: AstId<ast::MacroCall> },
294 Derive(AstId<ast::Item>, String), 295 Derive { ast_id: AstId<ast::Item>, derive_name: String, derive_attr: AttrId },
295} 296}
296 297
298#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
299pub struct AttrId(pub u32);
300
297impl MacroCallKind { 301impl MacroCallKind {
298 fn file_id(&self) -> HirFileId { 302 fn file_id(&self) -> HirFileId {
299 match self { 303 match self {
300 MacroCallKind::FnLike(ast_id) => ast_id.file_id, 304 MacroCallKind::FnLike { ast_id, .. } => ast_id.file_id,
301 MacroCallKind::Derive(ast_id, _) => ast_id.file_id, 305 MacroCallKind::Derive { ast_id, .. } => ast_id.file_id,
302 } 306 }
303 } 307 }
304 308
305 fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { 309 fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
306 match self { 310 match self {
307 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), 311 MacroCallKind::FnLike { ast_id, .. } => {
308 MacroCallKind::Derive(ast_id, _) => { 312 ast_id.with_value(ast_id.to_node(db).syntax().clone())
313 }
314 MacroCallKind::Derive { ast_id, .. } => {
309 ast_id.with_value(ast_id.to_node(db).syntax().clone()) 315 ast_id.with_value(ast_id.to_node(db).syntax().clone())
310 } 316 }
311 } 317 }
@@ -313,10 +319,10 @@ impl MacroCallKind {
313 319
314 fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { 320 fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
315 match self { 321 match self {
316 MacroCallKind::FnLike(ast_id) => { 322 MacroCallKind::FnLike { ast_id, .. } => {
317 Some(ast_id.to_node(db).token_tree()?.syntax().clone()) 323 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
318 } 324 }
319 MacroCallKind::Derive(ast_id, _) => Some(ast_id.to_node(db).syntax().clone()), 325 MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
320 } 326 }
321 } 327 }
322} 328}
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs
index 75e950816..d5643393a 100644
--- a/crates/hir_expand/src/proc_macro.rs
+++ b/crates/hir_expand/src/proc_macro.rs
@@ -2,7 +2,6 @@
2 2
3use crate::db::AstDatabase; 3use crate::db::AstDatabase;
4use base_db::{CrateId, ProcMacroId}; 4use base_db::{CrateId, ProcMacroId};
5use tt::buffer::{Cursor, TokenBuffer};
6 5
7#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] 6#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
8pub struct ProcMacroExpander { 7pub struct ProcMacroExpander {
@@ -44,9 +43,6 @@ impl ProcMacroExpander {
44 .clone() 43 .clone()
45 .ok_or_else(|| err!("No derive macro found."))?; 44 .ok_or_else(|| err!("No derive macro found."))?;
46 45
47 let tt = remove_derive_attrs(tt)
48 .ok_or_else(|| err!("Fail to remove derive for custom derive"))?;
49
50 // Proc macros have access to the environment variables of the invoking crate. 46 // Proc macros have access to the environment variables of the invoking crate.
51 let env = &krate_graph[calling_crate].env; 47 let env = &krate_graph[calling_crate].env;
52 48
@@ -56,101 +52,3 @@ impl ProcMacroExpander {
56 } 52 }
57 } 53 }
58} 54}
59
60fn eat_punct(cursor: &mut Cursor, c: char) -> bool {
61 if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = cursor.token_tree() {
62 if punct.char == c {
63 *cursor = cursor.bump();
64 return true;
65 }
66 }
67 false
68}
69
70fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool {
71 if let Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) = cursor.token_tree() {
72 if Some(kind) == subtree.delimiter_kind() {
73 *cursor = cursor.bump_subtree();
74 return true;
75 }
76 }
77 false
78}
79
80fn eat_ident(cursor: &mut Cursor, t: &str) -> bool {
81 if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = cursor.token_tree() {
82 if t == ident.text.as_str() {
83 *cursor = cursor.bump();
84 return true;
85 }
86 }
87 false
88}
89
90fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> {
91 let buffer = TokenBuffer::from_tokens(&tt.token_trees);
92 let mut p = buffer.begin();
93 let mut result = tt::Subtree::default();
94
95 while !p.eof() {
96 let curr = p;
97
98 if eat_punct(&mut p, '#') {
99 eat_punct(&mut p, '!');
100 let parent = p;
101 if eat_subtree(&mut p, tt::DelimiterKind::Bracket) {
102 if eat_ident(&mut p, "derive") {
103 p = parent.bump();
104 continue;
105 }
106 }
107 }
108
109 result.token_trees.push(curr.token_tree()?.cloned());
110 p = curr.bump();
111 }
112
113 Some(result)
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119 use test_utils::assert_eq_text;
120
121 #[test]
122 fn test_remove_derive_attrs() {
123 let tt = mbe::parse_to_token_tree(
124 r#"
125 #[allow(unused)]
126 #[derive(Copy)]
127 #[derive(Hello)]
128 struct A {
129 bar: u32
130 }
131"#,
132 )
133 .unwrap()
134 .0;
135 let result = format!("{:#?}", remove_derive_attrs(&tt).unwrap());
136
137 assert_eq_text!(
138 r#"
139SUBTREE $
140 PUNCH # [alone] 0
141 SUBTREE [] 1
142 IDENT allow 2
143 SUBTREE () 3
144 IDENT unused 4
145 IDENT struct 15
146 IDENT A 16
147 SUBTREE {} 17
148 IDENT bar 18
149 PUNCH : [alone] 19
150 IDENT u32 20
151"#
152 .trim(),
153 &result
154 );
155 }
156}
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index f8e9db9ae..71bc436e6 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -6,14 +6,15 @@
6use std::iter::successors; 6use std::iter::successors;
7 7
8use base_db::CrateId; 8use base_db::CrateId;
9use chalk_ir::cast::Cast; 9use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
10use hir_def::lang_item::LangItemTarget; 10use hir_def::lang_item::LangItemTarget;
11use hir_expand::name::name; 11use hir_expand::name::name;
12use log::{info, warn}; 12use log::{info, warn};
13 13
14use crate::{ 14use crate::{
15 db::HirDatabase, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, 15 db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
16 InEnvironment, Interner, ProjectionTyExt, Solution, Ty, TyBuilder, TyKind, 16 DebruijnIndex, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution, Ty, TyBuilder,
17 TyKind,
17}; 18};
18 19
19const AUTODEREF_RECURSION_LIMIT: usize = 10; 20const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -103,7 +104,7 @@ fn deref_by_trait(
103 binders: CanonicalVarKinds::from_iter( 104 binders: CanonicalVarKinds::from_iter(
104 &Interner, 105 &Interner,
105 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new( 106 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new(
106 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), 107 VariableKind::Ty(chalk_ir::TyVariableKind::General),
107 chalk_ir::UniverseIndex::ROOT, 108 chalk_ir::UniverseIndex::ROOT,
108 ))), 109 ))),
109 ), 110 ),
@@ -136,7 +137,9 @@ fn deref_by_trait(
136 return None; 137 return None;
137 } 138 }
138 } 139 }
139 Some(Canonical { 140 // FIXME: we remove lifetime variables here since they can confuse
141 // the method resolution code later
142 Some(fixup_lifetime_variables(Canonical {
140 value: vars 143 value: vars
141 .value 144 .value
142 .subst 145 .subst
@@ -144,7 +147,7 @@ fn deref_by_trait(
144 .assert_ty_ref(&Interner) 147 .assert_ty_ref(&Interner)
145 .clone(), 148 .clone(),
146 binders: vars.binders.clone(), 149 binders: vars.binders.clone(),
147 }) 150 }))
148 } 151 }
149 Solution::Ambig(_) => { 152 Solution::Ambig(_) => {
150 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution); 153 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
@@ -152,3 +155,32 @@ fn deref_by_trait(
152 } 155 }
153 } 156 }
154} 157}
158
159fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
160 c: Canonical<T>,
161) -> Canonical<T> {
162 // Removes lifetime variables from the Canonical, replacing them by static lifetimes.
163 let mut i = 0;
164 let subst = Substitution::from_iter(
165 &Interner,
166 c.binders.iter(&Interner).map(|vk| match vk.kind {
167 VariableKind::Ty(_) => {
168 let index = i;
169 i += 1;
170 BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner)
171 }
172 VariableKind::Lifetime => static_lifetime().cast(&Interner),
173 VariableKind::Const(_) => unimplemented!(),
174 }),
175 );
176 let binders = CanonicalVarKinds::from_iter(
177 &Interner,
178 c.binders.iter(&Interner).filter(|vk| match vk.kind {
179 VariableKind::Ty(_) => true,
180 VariableKind::Lifetime => false,
181 VariableKind::Const(_) => true,
182 }),
183 );
184 let value = subst.apply(c.value, &Interner);
185 Canonical { binders, value }
186}
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index 09512d1ce..e25ef866d 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -4,6 +4,7 @@ use std::iter;
4 4
5use chalk_ir::{ 5use chalk_ir::{
6 cast::{Cast, CastTo, Caster}, 6 cast::{Cast, CastTo, Caster},
7 fold::Fold,
7 interner::HasInterner, 8 interner::HasInterner,
8 AdtId, BoundVar, DebruijnIndex, Safety, Scalar, 9 AdtId, BoundVar, DebruijnIndex, Safety, Scalar,
9}; 10};
@@ -13,7 +14,7 @@ use smallvec::SmallVec;
13use crate::{ 14use crate::{
14 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,
15 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution, 16 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution,
16 TraitRef, Ty, TyDefId, TyExt, TyKind, TypeWalk, ValueTyDefId, 17 TraitRef, Ty, TyDefId, TyExt, TyKind, ValueTyDefId,
17}; 18};
18 19
19/// 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`.
@@ -32,8 +33,7 @@ impl<D> TyBuilder<D> {
32 33
33 fn build_internal(self) -> (D, Substitution) { 34 fn build_internal(self) -> (D, Substitution) {
34 assert_eq!(self.vec.len(), self.param_count); 35 assert_eq!(self.vec.len(), self.param_count);
35 // FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form 36 let subst = Substitution::from_iter(&Interner, self.vec);
36 let subst = Substitution::intern(self.vec);
37 (self.data, subst) 37 (self.data, subst)
38 } 38 }
39 39
@@ -141,7 +141,7 @@ impl TyBuilder<hir_def::AdtId> {
141 self.vec.push(fallback().cast(&Interner)); 141 self.vec.push(fallback().cast(&Interner));
142 } else { 142 } else {
143 // each default can depend on the previous parameters 143 // each default can depend on the previous parameters
144 let subst_so_far = Substitution::intern(self.vec.clone()); 144 let subst_so_far = Substitution::from_iter(&Interner, self.vec.clone());
145 self.vec 145 self.vec
146 .push(default_ty.clone().substitute(&Interner, &subst_so_far).cast(&Interner)); 146 .push(default_ty.clone().substitute(&Interner, &subst_so_far).cast(&Interner));
147 } 147 }
@@ -196,13 +196,13 @@ impl TyBuilder<TypeAliasId> {
196 } 196 }
197} 197}
198 198
199impl<T: TypeWalk + HasInterner<Interner = Interner>> TyBuilder<Binders<T>> { 199impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
200 fn subst_binders(b: Binders<T>) -> Self { 200 fn subst_binders(b: Binders<T>) -> Self {
201 let param_count = b.binders.len(&Interner); 201 let param_count = b.binders.len(&Interner);
202 TyBuilder::new(b, param_count) 202 TyBuilder::new(b, param_count)
203 } 203 }
204 204
205 pub fn build(self) -> T { 205 pub fn build(self) -> <T as Fold<Interner>>::Result {
206 let (b, subst) = self.build_internal(); 206 let (b, subst) = self.build_internal();
207 b.substitute(&Interner, &subst) 207 b.substitute(&Interner, &subst)
208 } 208 }
diff --git a/crates/hir_ty/src/chalk_cast.rs b/crates/hir_ty/src/chalk_cast.rs
deleted file mode 100644
index df6492113..000000000
--- a/crates/hir_ty/src/chalk_cast.rs
+++ /dev/null
@@ -1,73 +0,0 @@
1//! Implementations of the Chalk `Cast` trait for our types.
2
3use chalk_ir::{
4 cast::{Cast, CastTo},
5 interner::HasInterner,
6};
7
8use crate::{AliasEq, DomainGoal, GenericArg, GenericArgData, Interner, TraitRef, Ty, WhereClause};
9
10macro_rules! has_interner {
11 ($t:ty) => {
12 impl HasInterner for $t {
13 type Interner = crate::Interner;
14 }
15 };
16}
17
18has_interner!(WhereClause);
19has_interner!(DomainGoal);
20has_interner!(GenericArg);
21has_interner!(Ty);
22
23impl CastTo<WhereClause> for TraitRef {
24 fn cast_to(self, _interner: &Interner) -> WhereClause {
25 WhereClause::Implemented(self)
26 }
27}
28
29impl CastTo<WhereClause> for AliasEq {
30 fn cast_to(self, _interner: &Interner) -> WhereClause {
31 WhereClause::AliasEq(self)
32 }
33}
34
35impl CastTo<DomainGoal> for WhereClause {
36 fn cast_to(self, _interner: &Interner) -> DomainGoal {
37 DomainGoal::Holds(self)
38 }
39}
40
41impl CastTo<GenericArg> for Ty {
42 fn cast_to(self, interner: &Interner) -> GenericArg {
43 GenericArg::new(interner, GenericArgData::Ty(self))
44 }
45}
46
47macro_rules! transitive_impl {
48 ($a:ty, $b:ty, $c:ty) => {
49 impl CastTo<$c> for $a {
50 fn cast_to(self, interner: &Interner) -> $c {
51 self.cast::<$b>(interner).cast(interner)
52 }
53 }
54 };
55}
56
57// In Chalk, these can be done as blanket impls, but that doesn't work here
58// because of coherence
59
60transitive_impl!(TraitRef, WhereClause, DomainGoal);
61transitive_impl!(AliasEq, WhereClause, DomainGoal);
62
63macro_rules! reflexive_impl {
64 ($a:ty) => {
65 impl CastTo<$a> for $a {
66 fn cast_to(self, _interner: &Interner) -> $a {
67 self
68 }
69 }
70 };
71}
72
73reflexive_impl!(GenericArg);
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/chalk_db.rs
index 090f6492b..8f054d06b 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -1,52 +1,47 @@
1//! Conversion code from/to Chalk. 1//! The implementation of `RustIrDatabase` for Chalk, which provides information
2//! about the code that Chalk needs.
2use std::sync::Arc; 3use std::sync::Arc;
3 4
4use log::debug; 5use log::debug;
5 6
6use chalk_ir::{fold::shift::Shift, CanonicalVarKinds}; 7use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
7use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; 8use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
8 9
9use base_db::{salsa::InternKey, CrateId}; 10use base_db::CrateId;
10use hir_def::{ 11use hir_def::{
11 lang_item::{lang_attr, LangItemTarget}, 12 lang_item::{lang_attr, LangItemTarget},
12 AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, 13 AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId,
13}; 14};
14use hir_expand::name::name; 15use hir_expand::name::name;
15 16
16use super::ChalkContext;
17use crate::{ 17use crate::{
18 db::HirDatabase, 18 db::HirDatabase,
19 display::HirDisplay, 19 display::HirDisplay,
20 from_assoc_type_id, 20 from_assoc_type_id, from_chalk_trait_id, make_only_type_binders,
21 mapping::{from_chalk, ToChalk, TypeAliasAsValue},
21 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, 22 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
22 to_assoc_type_id, to_chalk_trait_id, 23 to_assoc_type_id, to_chalk_trait_id,
24 traits::ChalkContext,
23 utils::generics, 25 utils::generics,
24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution, 26 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy,
25 TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, 27 ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
28 TyExt, TyKind, WhereClause,
26}; 29};
27use mapping::{
28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
29};
30
31pub use self::interner::Interner;
32pub(crate) use self::interner::*;
33
34pub(super) mod tls;
35mod interner;
36mod mapping;
37
38pub(crate) trait ToChalk {
39 type Chalk;
40 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk;
41 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self;
42}
43 30
44pub(crate) fn from_chalk<T, ChalkT>(db: &dyn HirDatabase, chalk: ChalkT) -> T 31pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
45where 32pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>;
46 T: ToChalk<Chalk = ChalkT>, 33pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>;
47{ 34pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>;
48 T::from_chalk(db, chalk) 35pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
49} 36
37pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
38pub(crate) type TraitId = chalk_ir::TraitId<Interner>;
39pub(crate) type AdtId = chalk_ir::AdtId<Interner>;
40pub(crate) type ImplId = chalk_ir::ImplId<Interner>;
41pub(crate) type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>;
42pub(crate) type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>;
43pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
44pub(crate) type Variances = chalk_ir::Variances<Interner>;
50 45
51impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { 46impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
52 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { 47 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> {
@@ -84,9 +79,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
84 binders: &CanonicalVarKinds<Interner>, 79 binders: &CanonicalVarKinds<Interner>,
85 ) -> Vec<ImplId> { 80 ) -> Vec<ImplId> {
86 debug!("impls_for_trait {:?}", trait_id); 81 debug!("impls_for_trait {:?}", trait_id);
87 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 82 let trait_: hir_def::TraitId = from_chalk_trait_id(trait_id);
88 83
89 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone()); 84 let ty: Ty = parameters[0].assert_ty_ref(&Interner).clone();
90 85
91 fn binder_kind( 86 fn binder_kind(
92 ty: &Ty, 87 ty: &Ty,
@@ -103,7 +98,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
103 None 98 None
104 } 99 }
105 100
106 let self_ty_fp = TyFingerprint::for_impl(&ty); 101 let self_ty_fp = TyFingerprint::for_trait_impl(&ty);
107 let fps: &[TyFingerprint] = match binder_kind(&ty, binders) { 102 let fps: &[TyFingerprint] = match binder_kind(&ty, binders) {
108 Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS, 103 Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS,
109 Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS, 104 Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS,
@@ -166,7 +161,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
166 Some(LangItemTarget::TraitId(trait_)) => trait_, 161 Some(LangItemTarget::TraitId(trait_)) => trait_,
167 _ => return None, 162 _ => return None,
168 }; 163 };
169 Some(trait_.to_chalk(self.db)) 164 Some(to_chalk_trait_id(trait_))
170 } 165 }
171 166
172 fn program_clauses_for_env( 167 fn program_clauses_for_env(
@@ -187,16 +182,11 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
187 let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders(); 182 let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
188 let data = &datas.impl_traits[idx as usize]; 183 let data = &datas.impl_traits[idx as usize];
189 let bound = OpaqueTyDatumBound { 184 let bound = OpaqueTyDatumBound {
190 bounds: make_binders( 185 bounds: make_only_type_binders(
191 data.bounds
192 .skip_binders()
193 .iter()
194 .cloned()
195 .map(|b| b.to_chalk(self.db))
196 .collect(),
197 1, 186 1,
187 data.bounds.skip_binders().iter().cloned().collect(),
198 ), 188 ),
199 where_clauses: make_binders(vec![], 0), 189 where_clauses: make_only_type_binders(0, vec![]),
200 }; 190 };
201 chalk_ir::Binders::new(binders, bound) 191 chalk_ir::Binders::new(binders, bound)
202 } 192 }
@@ -244,25 +234,25 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
244 .intern(&Interner), 234 .intern(&Interner),
245 }); 235 });
246 let bound = OpaqueTyDatumBound { 236 let bound = OpaqueTyDatumBound {
247 bounds: make_binders( 237 bounds: make_only_type_binders(
238 1,
248 vec![ 239 vec![
249 crate::wrap_empty_binders(impl_bound).to_chalk(self.db), 240 crate::wrap_empty_binders(impl_bound),
250 crate::wrap_empty_binders(proj_bound).to_chalk(self.db), 241 crate::wrap_empty_binders(proj_bound),
251 ], 242 ],
252 1,
253 ), 243 ),
254 where_clauses: make_binders(vec![], 0), 244 where_clauses: make_only_type_binders(0, vec![]),
255 }; 245 };
256 // The opaque type has 1 parameter. 246 // The opaque type has 1 parameter.
257 make_binders(bound, 1) 247 make_only_type_binders(1, bound)
258 } else { 248 } else {
259 // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback. 249 // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
260 let bound = OpaqueTyDatumBound { 250 let bound = OpaqueTyDatumBound {
261 bounds: make_binders(vec![], 0), 251 bounds: make_only_type_binders(0, vec![]),
262 where_clauses: make_binders(vec![], 0), 252 where_clauses: make_only_type_binders(0, vec![]),
263 }; 253 };
264 // The opaque type has 1 parameter. 254 // The opaque type has 1 parameter.
265 make_binders(bound, 1) 255 make_only_type_binders(1, bound)
266 } 256 }
267 } 257 }
268 }; 258 };
@@ -272,7 +262,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
272 262
273 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { 263 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
274 // FIXME: actually provide the hidden type; it is relevant for auto traits 264 // FIXME: actually provide the hidden type; it is relevant for auto traits
275 TyKind::Error.intern(&Interner).to_chalk(self.db) 265 TyKind::Error.intern(&Interner)
276 } 266 }
277 267
278 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool { 268 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
@@ -293,33 +283,32 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
293 _closure_id: chalk_ir::ClosureId<Interner>, 283 _closure_id: chalk_ir::ClosureId<Interner>,
294 substs: &chalk_ir::Substitution<Interner>, 284 substs: &chalk_ir::Substitution<Interner>,
295 ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> { 285 ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> {
296 let sig_ty: Ty = 286 let sig_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone();
297 from_chalk(self.db, substs.at(&Interner, 0).assert_ty_ref(&Interner).clone());
298 let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr"); 287 let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr");
299 let io = rust_ir::FnDefInputsAndOutputDatum { 288 let io = rust_ir::FnDefInputsAndOutputDatum {
300 argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(self.db)).collect(), 289 argument_types: sig.params().iter().cloned().collect(),
301 return_type: sig.ret().clone().to_chalk(self.db), 290 return_type: sig.ret().clone(),
302 }; 291 };
303 make_binders(io.shifted_in(&Interner), 0) 292 make_only_type_binders(0, io.shifted_in(&Interner))
304 } 293 }
305 fn closure_upvars( 294 fn closure_upvars(
306 &self, 295 &self,
307 _closure_id: chalk_ir::ClosureId<Interner>, 296 _closure_id: chalk_ir::ClosureId<Interner>,
308 _substs: &chalk_ir::Substitution<Interner>, 297 _substs: &chalk_ir::Substitution<Interner>,
309 ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { 298 ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
310 let ty = TyBuilder::unit().to_chalk(self.db); 299 let ty = TyBuilder::unit();
311 make_binders(ty, 0) 300 make_only_type_binders(0, ty)
312 } 301 }
313 fn closure_fn_substitution( 302 fn closure_fn_substitution(
314 &self, 303 &self,
315 _closure_id: chalk_ir::ClosureId<Interner>, 304 _closure_id: chalk_ir::ClosureId<Interner>,
316 _substs: &chalk_ir::Substitution<Interner>, 305 _substs: &chalk_ir::Substitution<Interner>,
317 ) -> chalk_ir::Substitution<Interner> { 306 ) -> chalk_ir::Substitution<Interner> {
318 Substitution::empty(&Interner).to_chalk(self.db) 307 Substitution::empty(&Interner)
319 } 308 }
320 309
321 fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String { 310 fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
322 let id = from_chalk(self.db, trait_id); 311 let id = from_chalk_trait_id(trait_id);
323 self.db.trait_data(id).name.to_string() 312 self.db.trait_data(id).name.to_string()
324 } 313 }
325 fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String { 314 fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String {
@@ -410,10 +399,10 @@ pub(crate) fn associated_ty_data_query(
410 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); 399 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
411 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; 400 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses };
412 let datum = AssociatedTyDatum { 401 let datum = AssociatedTyDatum {
413 trait_id: trait_.to_chalk(db), 402 trait_id: to_chalk_trait_id(trait_),
414 id, 403 id,
415 name: type_alias, 404 name: type_alias,
416 binders: make_binders(bound_data, generic_params.len()), 405 binders: make_only_type_binders(generic_params.len(), bound_data),
417 }; 406 };
418 Arc::new(datum) 407 Arc::new(datum)
419} 408}
@@ -424,7 +413,7 @@ pub(crate) fn trait_datum_query(
424 trait_id: TraitId, 413 trait_id: TraitId,
425) -> Arc<TraitDatum> { 414) -> Arc<TraitDatum> {
426 debug!("trait_datum {:?}", trait_id); 415 debug!("trait_datum {:?}", trait_id);
427 let trait_: hir_def::TraitId = from_chalk(db, trait_id); 416 let trait_ = from_chalk_trait_id(trait_id);
428 let trait_data = db.trait_data(trait_); 417 let trait_data = db.trait_data(trait_);
429 debug!("trait {:?} = {:?}", trait_id, trait_data.name); 418 debug!("trait {:?} = {:?}", trait_id, trait_data.name);
430 let generic_params = generics(db.upcast(), trait_.into()); 419 let generic_params = generics(db.upcast(), trait_.into());
@@ -446,7 +435,7 @@ pub(crate) fn trait_datum_query(
446 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); 435 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
447 let trait_datum = TraitDatum { 436 let trait_datum = TraitDatum {
448 id: trait_id, 437 id: trait_id,
449 binders: make_binders(trait_datum_bound, bound_vars.len(&Interner)), 438 binders: make_only_type_binders(bound_vars.len(&Interner), trait_datum_bound),
450 flags, 439 flags,
451 associated_ty_ids, 440 associated_ty_ids,
452 well_known, 441 well_known,
@@ -515,7 +504,7 @@ pub(crate) fn struct_datum_query(
515 // FIXME set ADT kind 504 // FIXME set ADT kind
516 kind: rust_ir::AdtKind::Struct, 505 kind: rust_ir::AdtKind::Struct,
517 id: struct_id, 506 id: struct_id,
518 binders: make_binders(struct_datum_bound, num_params), 507 binders: make_only_type_binders(num_params, struct_datum_bound),
519 flags, 508 flags,
520 }; 509 };
521 Arc::new(struct_datum) 510 Arc::new(struct_datum)
@@ -563,7 +552,6 @@ fn impl_def_datum(
563 trait_ref.display(db), 552 trait_ref.display(db),
564 where_clauses 553 where_clauses
565 ); 554 );
566 let trait_ref = trait_ref.to_chalk(db);
567 555
568 let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; 556 let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
569 557
@@ -585,7 +573,7 @@ fn impl_def_datum(
585 .collect(); 573 .collect();
586 debug!("impl_datum: {:?}", impl_datum_bound); 574 debug!("impl_datum: {:?}", impl_datum_bound);
587 let impl_datum = ImplDatum { 575 let impl_datum = ImplDatum {
588 binders: make_binders(impl_datum_bound, bound_vars.len(&Interner)), 576 binders: make_only_type_binders(bound_vars.len(&Interner), impl_datum_bound),
589 impl_type, 577 impl_type,
590 polarity, 578 polarity,
591 associated_ty_value_ids, 579 associated_ty_value_ids,
@@ -624,7 +612,7 @@ fn type_alias_associated_ty_value(
624 .associated_type_by_name(&type_alias_data.name) 612 .associated_type_by_name(&type_alias_data.name)
625 .expect("assoc ty value should not exist"); // validated when building the impl data as well 613 .expect("assoc ty value should not exist"); // validated when building the impl data as well
626 let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders(); 614 let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders();
627 let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; 615 let value_bound = rust_ir::AssociatedTyValueBound { ty };
628 let value = rust_ir::AssociatedTyValue { 616 let value = rust_ir::AssociatedTyValue {
629 impl_id: impl_id.to_chalk(db), 617 impl_id: impl_id.to_chalk(db),
630 associated_ty_id: to_assoc_type_id(assoc_ty), 618 associated_ty_id: to_assoc_type_id(assoc_ty),
@@ -645,13 +633,13 @@ pub(crate) fn fn_def_datum_query(
645 let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); 633 let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
646 let bound = rust_ir::FnDefDatumBound { 634 let bound = rust_ir::FnDefDatumBound {
647 // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway 635 // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
648 inputs_and_output: make_binders( 636 inputs_and_output: make_only_type_binders(
637 0,
649 rust_ir::FnDefInputsAndOutputDatum { 638 rust_ir::FnDefInputsAndOutputDatum {
650 argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(), 639 argument_types: sig.params().iter().cloned().collect(),
651 return_type: sig.ret().clone().to_chalk(db), 640 return_type: sig.ret().clone(),
652 } 641 }
653 .shifted_in(&Interner), 642 .shifted_in(&Interner),
654 0,
655 ), 643 ),
656 where_clauses, 644 where_clauses,
657 }; 645 };
@@ -688,38 +676,65 @@ pub(crate) fn adt_variance_query(
688 ) 676 )
689} 677}
690 678
691impl From<FnDefId> for crate::db::InternedCallableDefId { 679pub(super) fn convert_where_clauses(
692 fn from(fn_def_id: FnDefId) -> Self { 680 db: &dyn HirDatabase,
693 InternKey::from_intern_id(fn_def_id.0) 681 def: GenericDefId,
694 } 682 substs: &Substitution,
695} 683) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> {
696 684 let generic_predicates = db.generic_predicates(def);
697impl From<crate::db::InternedCallableDefId> for FnDefId { 685 let mut result = Vec::with_capacity(generic_predicates.len());
698 fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self { 686 for pred in generic_predicates.iter() {
699 chalk_ir::FnDefId(callable_def_id.as_intern_id()) 687 result.push(pred.clone().substitute(&Interner, substs));
700 } 688 }
701} 689 result
702
703impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
704 fn from(id: OpaqueTyId) -> Self {
705 InternKey::from_intern_id(id.0)
706 }
707}
708
709impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
710 fn from(id: crate::db::InternedOpaqueTyId) -> Self {
711 chalk_ir::OpaqueTyId(id.as_intern_id())
712 }
713}
714
715impl From<chalk_ir::ClosureId<Interner>> for crate::db::InternedClosureId {
716 fn from(id: chalk_ir::ClosureId<Interner>) -> Self {
717 Self::from_intern_id(id.0)
718 }
719} 690}
720 691
721impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> { 692pub(super) fn generic_predicate_to_inline_bound(
722 fn from(id: crate::db::InternedClosureId) -> Self { 693 db: &dyn HirDatabase,
723 chalk_ir::ClosureId(id.as_intern_id()) 694 pred: &QuantifiedWhereClause,
695 self_ty: &Ty,
696) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
697 // An InlineBound is like a GenericPredicate, except the self type is left out.
698 // We don't have a special type for this, but Chalk does.
699 let self_ty_shifted_in = self_ty.clone().shifted_in_from(&Interner, DebruijnIndex::ONE);
700 let (pred, binders) = pred.as_ref().into_value_and_skipped_binders();
701 match pred {
702 WhereClause::Implemented(trait_ref) => {
703 if trait_ref.self_type_parameter(&Interner) != self_ty_shifted_in {
704 // we can only convert predicates back to type bounds if they
705 // have the expected self type
706 return None;
707 }
708 let args_no_self = trait_ref.substitution.as_slice(&Interner)[1..]
709 .iter()
710 .map(|ty| ty.clone().cast(&Interner))
711 .collect();
712 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
713 Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
714 }
715 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
716 if projection_ty.self_type_parameter(&Interner) != self_ty_shifted_in {
717 return None;
718 }
719 let trait_ = projection_ty.trait_(db);
720 let args_no_self = projection_ty.substitution.as_slice(&Interner)[1..]
721 .iter()
722 .map(|ty| ty.clone().cast(&Interner))
723 .collect();
724 let alias_eq_bound = rust_ir::AliasEqBound {
725 value: ty.clone(),
726 trait_bound: rust_ir::TraitBound {
727 trait_id: to_chalk_trait_id(trait_),
728 args_no_self,
729 },
730 associated_ty_id: projection_ty.associated_ty_id,
731 parameters: Vec::new(), // FIXME we don't support generic associated types yet
732 };
733 Some(chalk_ir::Binders::new(
734 binders,
735 rust_ir::InlineBound::AliasEqBound(alias_eq_bound),
736 ))
737 }
738 _ => None,
724 } 739 }
725} 740}
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index 28ed3aac6..8c4542956 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -75,7 +75,7 @@ impl TyExt for Ty {
75 } 75 }
76 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> { 76 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
77 match self.kind(&Interner) { 77 match self.kind(&Interner) {
78 TyKind::Ref(mutability, lifetime, ty) => Some((ty, *lifetime, *mutability)), 78 TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)),
79 _ => None, 79 _ => None,
80 } 80 }
81 } 81 }
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 326c20240..1690926ad 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -1,4 +1,5 @@
1//! FIXME: write short doc here 1//! The home of `HirDatabase`, which is the Salsa database containing all the
2//! type inference-related queries.
2 3
3use std::sync::Arc; 4use std::sync::Arc;
4 5
@@ -10,9 +11,9 @@ use hir_def::{
10use la_arena::ArenaMap; 11use la_arena::ArenaMap;
11 12
12use crate::{ 13use crate::{
14 chalk_db,
13 method_resolution::{InherentImpls, TraitImpls}, 15 method_resolution::{InherentImpls, TraitImpls},
14 traits::chalk, 16 Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, Interner, PolyFnSig,
15 Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, PolyFnSig,
16 QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId, 17 QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
17}; 18};
18use hir_expand::name::Name; 19use hir_expand::name::Name;
@@ -94,33 +95,38 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
94 #[salsa::interned] 95 #[salsa::interned]
95 fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId; 96 fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
96 97
97 #[salsa::invoke(chalk::associated_ty_data_query)] 98 #[salsa::invoke(chalk_db::associated_ty_data_query)]
98 fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>; 99 fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
99 100
100 #[salsa::invoke(chalk::trait_datum_query)] 101 #[salsa::invoke(chalk_db::trait_datum_query)]
101 fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; 102 fn trait_datum(&self, krate: CrateId, trait_id: chalk_db::TraitId)
103 -> Arc<chalk_db::TraitDatum>;
102 104
103 #[salsa::invoke(chalk::struct_datum_query)] 105 #[salsa::invoke(chalk_db::struct_datum_query)]
104 fn struct_datum(&self, krate: CrateId, struct_id: chalk::AdtId) -> Arc<chalk::StructDatum>; 106 fn struct_datum(
107 &self,
108 krate: CrateId,
109 struct_id: chalk_db::AdtId,
110 ) -> Arc<chalk_db::StructDatum>;
105 111
106 #[salsa::invoke(crate::traits::chalk::impl_datum_query)] 112 #[salsa::invoke(chalk_db::impl_datum_query)]
107 fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; 113 fn impl_datum(&self, krate: CrateId, impl_id: chalk_db::ImplId) -> Arc<chalk_db::ImplDatum>;
108 114
109 #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)] 115 #[salsa::invoke(chalk_db::fn_def_datum_query)]
110 fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc<chalk::FnDefDatum>; 116 fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc<chalk_db::FnDefDatum>;
111 117
112 #[salsa::invoke(crate::traits::chalk::fn_def_variance_query)] 118 #[salsa::invoke(chalk_db::fn_def_variance_query)]
113 fn fn_def_variance(&self, krate: CrateId, fn_def_id: FnDefId) -> chalk::Variances; 119 fn fn_def_variance(&self, krate: CrateId, fn_def_id: FnDefId) -> chalk_db::Variances;
114 120
115 #[salsa::invoke(crate::traits::chalk::adt_variance_query)] 121 #[salsa::invoke(chalk_db::adt_variance_query)]
116 fn adt_variance(&self, krate: CrateId, adt_id: chalk::AdtId) -> chalk::Variances; 122 fn adt_variance(&self, krate: CrateId, adt_id: chalk_db::AdtId) -> chalk_db::Variances;
117 123
118 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] 124 #[salsa::invoke(chalk_db::associated_ty_value_query)]
119 fn associated_ty_value( 125 fn associated_ty_value(
120 &self, 126 &self,
121 krate: CrateId, 127 krate: CrateId,
122 id: chalk::AssociatedTyValueId, 128 id: chalk_db::AssociatedTyValueId,
123 ) -> Arc<chalk::AssociatedTyValue>; 129 ) -> Arc<chalk_db::AssociatedTyValue>;
124 130
125 #[salsa::invoke(crate::traits::trait_solve_query)] 131 #[salsa::invoke(crate::traits::trait_solve_query)]
126 fn trait_solve( 132 fn trait_solve(
@@ -129,12 +135,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
129 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, 135 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
130 ) -> Option<crate::Solution>; 136 ) -> Option<crate::Solution>;
131 137
132 #[salsa::invoke(crate::traits::chalk::program_clauses_for_chalk_env_query)] 138 #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)]
133 fn program_clauses_for_chalk_env( 139 fn program_clauses_for_chalk_env(
134 &self, 140 &self,
135 krate: CrateId, 141 krate: CrateId,
136 env: chalk_ir::Environment<chalk::Interner>, 142 env: chalk_ir::Environment<Interner>,
137 ) -> chalk_ir::ProgramClauses<chalk::Interner>; 143 ) -> chalk_ir::ProgramClauses<Interner>;
138} 144}
139 145
140fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { 146fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index 86f937e1d..84fc8ce14 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Type inference-based diagnostics.
2mod expr; 2mod expr;
3mod match_check; 3mod match_check;
4mod unsafe_check; 4mod unsafe_check;
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index e0ca96c6d..e7c9dabc2 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -1,4 +1,6 @@
1//! FIXME: write short doc here 1//! The `HirDisplay` trait, which serves two purposes: Turning various bits from
2//! HIR back into source code, and just displaying them for debugging/testing
3//! purposes.
2 4
3use std::{ 5use std::{
4 array, 6 array,
@@ -20,11 +22,11 @@ use hir_expand::name::Name;
20 22
21use crate::{ 23use crate::{
22 const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id, 24 const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id,
23 from_placeholder_idx, lt_from_placeholder_idx, primitive, subst_prefix, to_assoc_type_id, 25 from_placeholder_idx, lt_from_placeholder_idx, mapping::from_chalk, primitive, subst_prefix,
24 traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId, 26 to_assoc_type_id, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId, CallableSig, Const,
25 CallableSig, Const, ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, 27 ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
26 LifetimeData, LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, 28 LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause,
27 QuantifiedWhereClause, Scalar, TraitRef, TraitRefExt, Ty, TyExt, TyKind, WhereClause, 29 Scalar, TraitRef, TraitRefExt, Ty, TyExt, TyKind, WhereClause,
28}; 30};
29 31
30pub struct HirFormatter<'a> { 32pub struct HirFormatter<'a> {
@@ -265,7 +267,7 @@ impl HirDisplay for ProjectionTy {
265 write!(f, " as {}", trait_.name)?; 267 write!(f, " as {}", trait_.name)?;
266 if self.substitution.len(&Interner) > 1 { 268 if self.substitution.len(&Interner) > 1 {
267 write!(f, "<")?; 269 write!(f, "<")?;
268 f.write_joined(&self.substitution.interned()[1..], ", ")?; 270 f.write_joined(&self.substitution.as_slice(&Interner)[1..], ", ")?;
269 write!(f, ">")?; 271 write!(f, ">")?;
270 } 272 }
271 write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?; 273 write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
@@ -287,6 +289,8 @@ impl HirDisplay for GenericArg {
287 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 289 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
288 match self.interned() { 290 match self.interned() {
289 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f), 291 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
292 crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
293 crate::GenericArgData::Const(c) => c.hir_fmt(f),
290 } 294 }
291 } 295 }
292} 296}
@@ -414,7 +418,7 @@ impl HirDisplay for Ty {
414 write!(f, ",)")?; 418 write!(f, ",)")?;
415 } else { 419 } else {
416 write!(f, "(")?; 420 write!(f, "(")?;
417 f.write_joined(&*substs.interned(), ", ")?; 421 f.write_joined(&*substs.as_slice(&Interner), ", ")?;
418 write!(f, ")")?; 422 write!(f, ")")?;
419 } 423 }
420 } 424 }
@@ -442,7 +446,7 @@ impl HirDisplay for Ty {
442 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? 446 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
443 if total_len > 0 { 447 if total_len > 0 {
444 write!(f, "<")?; 448 write!(f, "<")?;
445 f.write_joined(&parameters.interned()[..total_len], ", ")?; 449 f.write_joined(&parameters.as_slice(&Interner)[..total_len], ", ")?;
446 write!(f, ">")?; 450 write!(f, ">")?;
447 } 451 }
448 } 452 }
@@ -489,7 +493,7 @@ impl HirDisplay for Ty {
489 .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) 493 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
490 .filter(|defaults| !defaults.is_empty()) 494 .filter(|defaults| !defaults.is_empty())
491 { 495 {
492 None => parameters.interned().as_ref(), 496 None => parameters.as_slice(&Interner),
493 Some(default_parameters) => { 497 Some(default_parameters) => {
494 let mut default_from = 0; 498 let mut default_from = 0;
495 for (i, parameter) in parameters.iter(&Interner).enumerate() { 499 for (i, parameter) in parameters.iter(&Interner).enumerate() {
@@ -513,11 +517,11 @@ impl HirDisplay for Ty {
513 } 517 }
514 } 518 }
515 } 519 }
516 &parameters.interned()[0..default_from] 520 &parameters.as_slice(&Interner)[0..default_from]
517 } 521 }
518 } 522 }
519 } else { 523 } else {
520 parameters.interned().as_ref() 524 parameters.as_slice(&Interner)
521 }; 525 };
522 if !parameters_to_write.is_empty() { 526 if !parameters_to_write.is_empty() {
523 write!(f, "<")?; 527 write!(f, "<")?;
@@ -540,7 +544,7 @@ impl HirDisplay for Ty {
540 write!(f, "{}::{}", trait_.name, type_alias_data.name)?; 544 write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
541 if parameters.len(&Interner) > 0 { 545 if parameters.len(&Interner) > 0 {
542 write!(f, "<")?; 546 write!(f, "<")?;
543 f.write_joined(&*parameters.interned(), ", ")?; 547 f.write_joined(&*parameters.as_slice(&Interner), ", ")?;
544 write!(f, ">")?; 548 write!(f, ">")?;
545 } 549 }
546 } else { 550 } else {
@@ -664,6 +668,8 @@ impl HirDisplay for Ty {
664 write!(f, "{{unknown}}")?; 668 write!(f, "{{unknown}}")?;
665 } 669 }
666 TyKind::InferenceVar(..) => write!(f, "_")?, 670 TyKind::InferenceVar(..) => write!(f, "_")?,
671 TyKind::Generator(..) => write!(f, "{{generator}}")?,
672 TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
667 } 673 }
668 Ok(()) 674 Ok(())
669 } 675 }
@@ -741,17 +747,17 @@ fn write_bounds_like_dyn_trait(
741 if !first { 747 if !first {
742 write!(f, " + ")?; 748 write!(f, " + ")?;
743 } 749 }
744 // We assume that the self type is $0 (i.e. the 750 // We assume that the self type is ^0.0 (i.e. the
745 // existential) here, which is the only thing that's 751 // existential) here, which is the only thing that's
746 // possible in actual Rust, and hence don't print it 752 // possible in actual Rust, and hence don't print it
747 write!(f, "{}", f.db.trait_data(trait_).name)?; 753 write!(f, "{}", f.db.trait_data(trait_).name)?;
748 if let [_, params @ ..] = &*trait_ref.substitution.interned().as_slice() { 754 if let [_, params @ ..] = &*trait_ref.substitution.as_slice(&Interner) {
749 if is_fn_trait { 755 if is_fn_trait {
750 if let Some(args) = 756 if let Some(args) =
751 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple()) 757 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
752 { 758 {
753 write!(f, "(")?; 759 write!(f, "(")?;
754 f.write_joined(&*args.interned(), ", ")?; 760 f.write_joined(args.as_slice(&Interner), ", ")?;
755 write!(f, ")")?; 761 write!(f, ")")?;
756 } 762 }
757 } else if !params.is_empty() { 763 } else if !params.is_empty() {
@@ -783,6 +789,10 @@ fn write_bounds_like_dyn_trait(
783 } 789 }
784 ty.hir_fmt(f)?; 790 ty.hir_fmt(f)?;
785 } 791 }
792
793 // FIXME implement these
794 WhereClause::LifetimeOutlives(_) => {}
795 WhereClause::TypeOutlives(_) => {}
786 } 796 }
787 first = false; 797 first = false;
788 } 798 }
@@ -806,7 +816,7 @@ fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<()
806 write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?; 816 write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
807 if tr.substitution.len(&Interner) > 1 { 817 if tr.substitution.len(&Interner) > 1 {
808 write!(f, "<")?; 818 write!(f, "<")?;
809 f.write_joined(&tr.substitution.interned()[1..], ", ")?; 819 f.write_joined(&tr.substitution.as_slice(&Interner)[1..], ", ")?;
810 write!(f, ">")?; 820 write!(f, ">")?;
811 } 821 }
812 Ok(()) 822 Ok(())
@@ -837,6 +847,10 @@ impl HirDisplay for WhereClause {
837 ty.hir_fmt(f)?; 847 ty.hir_fmt(f)?;
838 } 848 }
839 WhereClause::AliasEq(_) => write!(f, "{{error}}")?, 849 WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
850
851 // FIXME implement these
852 WhereClause::TypeOutlives(..) => {}
853 WhereClause::LifetimeOutlives(..) => {}
840 } 854 }
841 Ok(()) 855 Ok(())
842 } 856 }
@@ -881,9 +895,11 @@ impl HirDisplay for DomainGoal {
881 DomainGoal::Holds(wc) => { 895 DomainGoal::Holds(wc) => {
882 write!(f, "Holds(")?; 896 write!(f, "Holds(")?;
883 wc.hir_fmt(f)?; 897 wc.hir_fmt(f)?;
884 write!(f, ")") 898 write!(f, ")")?;
885 } 899 }
900 _ => write!(f, "?")?,
886 } 901 }
902 Ok(())
887 } 903 }
888} 904}
889 905
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 531159e54..bf2da2d4a 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -18,7 +18,7 @@ use std::mem;
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
21use chalk_ir::{cast::Cast, Mutability}; 21use chalk_ir::{cast::Cast, DebruijnIndex, Mutability};
22use hir_def::{ 22use hir_def::{
23 body::Body, 23 body::Body,
24 data::{ConstData, FunctionData, StaticData}, 24 data::{ConstData, FunctionData, StaticData},
@@ -38,11 +38,11 @@ use syntax::SmolStr;
38 38
39use super::{ 39use super::{
40 DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty, 40 DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty,
41 TypeWalk,
42}; 41};
43use crate::{ 42use crate::{
44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, 43 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
45 to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner, TyBuilder, TyExt, TyKind, 44 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner,
45 TyBuilder, TyExt, TyKind,
46}; 46};
47 47
48// This lint has a false positive here. See the link below for details. 48// This lint has a false positive here. See the link below for details.
@@ -323,7 +323,7 @@ impl<'a> InferenceContext<'a> {
323 } 323 }
324 324
325 fn insert_type_vars(&mut self, ty: Ty) -> Ty { 325 fn insert_type_vars(&mut self, ty: Ty) -> Ty {
326 ty.fold(&mut |ty| self.insert_type_vars_shallow(ty)) 326 fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), DebruijnIndex::INNERMOST)
327 } 327 }
328 328
329 fn resolve_obligations_as_possible(&mut self) { 329 fn resolve_obligations_as_possible(&mut self) {
@@ -434,12 +434,16 @@ impl<'a> InferenceContext<'a> {
434 /// to do it as well. 434 /// to do it as well.
435 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 435 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
436 let ty = self.resolve_ty_as_possible(ty); 436 let ty = self.resolve_ty_as_possible(ty);
437 ty.fold(&mut |ty| match ty.kind(&Interner) { 437 fold_tys(
438 TyKind::Alias(AliasTy::Projection(proj_ty)) => { 438 ty,
439 self.normalize_projection_ty(proj_ty.clone()) 439 |ty, _| match ty.kind(&Interner) {
440 } 440 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
441 _ => ty, 441 self.normalize_projection_ty(proj_ty.clone())
442 }) 442 }
443 _ => ty,
444 },
445 DebruijnIndex::INNERMOST,
446 )
443 } 447 }
444 448
445 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { 449 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index fd679f444..1f463a425 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -71,12 +71,14 @@ impl<'a> InferenceContext<'a> {
71 } 71 }
72 72
73 // Pointer weakening and function to pointer 73 // Pointer weakening and function to pointer
74 match (from_ty.interned_mut(), to_ty.kind(&Interner)) { 74 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
75 // `*mut T` -> `*const T` 75 // `*mut T` -> `*const T`
76 (TyKind::Raw(_, inner), TyKind::Raw(m2 @ Mutability::Not, ..)) => {
77 from_ty = TyKind::Raw(*m2, inner.clone()).intern(&Interner);
78 }
76 // `&mut T` -> `&T` 79 // `&mut T` -> `&T`
77 (TyKind::Raw(m1, ..), TyKind::Raw(m2 @ Mutability::Not, ..)) 80 (TyKind::Ref(_, lt, inner), TyKind::Ref(m2 @ Mutability::Not, ..)) => {
78 | (TyKind::Ref(m1, ..), TyKind::Ref(m2 @ Mutability::Not, ..)) => { 81 from_ty = TyKind::Ref(*m2, lt.clone(), inner.clone()).intern(&Interner);
79 *m1 = *m2;
80 } 82 }
81 // `&T` -> `*const T` 83 // `&T` -> `*const T`
82 // `&mut T` -> `*mut T`/`*const T` 84 // `&mut T` -> `*mut T`/`*const T`
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 9841988c5..50497eecb 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -3,7 +3,7 @@
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::{mem, sync::Arc}; 4use std::{mem, sync::Arc};
5 5
6use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 6use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
7use hir_def::{ 7use hir_def::{
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
@@ -17,14 +17,14 @@ use syntax::ast::RangeOp;
17use crate::{ 17use crate::{
18 autoderef, dummy_usize_const, 18 autoderef, dummy_usize_const,
19 lower::lower_to_chalk_mutability, 19 lower::lower_to_chalk_mutability,
20 mapping::from_chalk,
20 method_resolution, op, 21 method_resolution, op,
21 primitive::{self, UintTy}, 22 primitive::{self, UintTy},
22 static_lifetime, to_chalk_trait_id, 23 static_lifetime, to_chalk_trait_id,
23 traits::{chalk::from_chalk, FnTrait}, 24 traits::FnTrait,
24 utils::{generics, Generics}, 25 utils::{generics, Generics},
25 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner, 26 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
26 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind, 27 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
27 TypeWalk,
28}; 28};
29 29
30use super::{ 30use super::{
@@ -463,7 +463,11 @@ impl<'a> InferenceContext<'a> {
463 }; 463 };
464 match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) { 464 match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) {
465 TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| { 465 TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
466 substs.interned().get(idx).map(|a| a.assert_ty_ref(&Interner)).cloned() 466 substs
467 .as_slice(&Interner)
468 .get(idx)
469 .map(|a| a.assert_ty_ref(&Interner))
470 .cloned()
467 }), 471 }),
468 TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => { 472 TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
469 let local_id = self.db.struct_data(*s).variant_data.field(name)?; 473 let local_id = self.db.struct_data(*s).variant_data.field(name)?;
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index a41e8e116..aea354cde 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -122,7 +122,7 @@ impl<'a> InferenceContext<'a> {
122 let ty = match &body[pat] { 122 let ty = match &body[pat] {
123 &Pat::Tuple { ref args, ellipsis } => { 123 &Pat::Tuple { ref args, ellipsis } => {
124 let expectations = match expected.as_tuple() { 124 let expectations = match expected.as_tuple() {
125 Some(parameters) => &*parameters.interned().as_slice(), 125 Some(parameters) => &*parameters.as_slice(&Interner),
126 _ => &[], 126 _ => &[],
127 }; 127 };
128 128
@@ -242,7 +242,7 @@ impl<'a> InferenceContext<'a> {
242 let (inner_ty, alloc_ty) = match expected.as_adt() { 242 let (inner_ty, alloc_ty) = match expected.as_adt() {
243 Some((adt, subst)) if adt == box_adt => ( 243 Some((adt, subst)) if adt == box_adt => (
244 subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(), 244 subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(),
245 subst.interned().get(1).and_then(|a| a.ty(&Interner).cloned()), 245 subst.as_slice(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()),
246 ), 246 ),
247 _ => (self.result.standard_types.unknown.clone(), None), 247 _ => (self.result.standard_types.unknown.clone(), None),
248 }; 248 };
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index f8955aa32..495282eba 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -101,7 +101,7 @@ impl<'a> InferenceContext<'a> {
101 let substs = ctx.substs_from_path(path, typable, true); 101 let substs = ctx.substs_from_path(path, typable, true);
102 let ty = TyBuilder::value_ty(self.db, typable) 102 let ty = TyBuilder::value_ty(self.db, typable)
103 .use_parent_substs(&parent_substs) 103 .use_parent_substs(&parent_substs)
104 .fill(substs.interned()[parent_substs.len(&Interner)..].iter().cloned()) 104 .fill(substs.as_slice(&Interner)[parent_substs.len(&Interner)..].iter().cloned())
105 .build(); 105 .build();
106 Some(ty) 106 Some(ty)
107 } 107 }
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 2ea9dd920..a887e20b0 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -2,14 +2,17 @@
2 2
3use std::borrow::Cow; 3use std::borrow::Cow;
4 4
5use chalk_ir::{FloatTy, IntTy, TyVariableKind, UniverseIndex, VariableKind}; 5use chalk_ir::{
6 cast::Cast, fold::Fold, interner::HasInterner, FloatTy, IntTy, TyVariableKind, UniverseIndex,
7 VariableKind,
8};
6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 9use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
7 10
8use super::{DomainGoal, InferenceContext}; 11use super::{DomainGoal, InferenceContext};
9use crate::{ 12use crate::{
10 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSubst, 13 fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
11 InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyExt, TyKind, TypeWalk, 14 DebruijnIndex, FnPointer, FnSubst, InEnvironment, InferenceVar, Interner, Scalar, Substitution,
12 WhereClause, 15 Ty, TyExt, TyKind, WhereClause,
13}; 16};
14 17
15impl<'a> InferenceContext<'a> { 18impl<'a> InferenceContext<'a> {
@@ -34,7 +37,10 @@ where
34} 37}
35 38
36#[derive(Debug)] 39#[derive(Debug)]
37pub(super) struct Canonicalized<T> { 40pub(super) struct Canonicalized<T>
41where
42 T: HasInterner<Interner = Interner>,
43{
38 pub(super) value: Canonical<T>, 44 pub(super) value: Canonical<T>,
39 free_vars: Vec<(InferenceVar, TyVariableKind)>, 45 free_vars: Vec<(InferenceVar, TyVariableKind)>,
40} 46}
@@ -48,9 +54,14 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
48 }) 54 })
49 } 55 }
50 56
51 fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: DebruijnIndex) -> T { 57 fn do_canonicalize<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
52 t.fold_binders( 58 &mut self,
53 &mut |ty, binders| match ty.kind(&Interner) { 59 t: T,
60 binders: DebruijnIndex,
61 ) -> T {
62 fold_tys(
63 t,
64 |ty, binders| match ty.kind(&Interner) {
54 &TyKind::InferenceVar(var, kind) => { 65 &TyKind::InferenceVar(var, kind) => {
55 let inner = from_inference_var(var); 66 let inner = from_inference_var(var);
56 if self.var_stack.contains(&inner) { 67 if self.var_stack.contains(&inner) {
@@ -76,7 +87,10 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
76 ) 87 )
77 } 88 }
78 89
79 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 90 fn into_canonicalized<T: HasInterner<Interner = Interner>>(
91 self,
92 result: T,
93 ) -> Canonicalized<T> {
80 let kinds = self 94 let kinds = self
81 .free_vars 95 .free_vars
82 .iter() 96 .iter()
@@ -103,28 +117,18 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
103 DomainGoal::Holds(wc) => { 117 DomainGoal::Holds(wc) => {
104 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST)) 118 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST))
105 } 119 }
120 _ => unimplemented!(),
106 }; 121 };
107 self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment }) 122 self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment })
108 } 123 }
109} 124}
110 125
111impl<T> Canonicalized<T> { 126impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
112 pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty { 127 pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty {
113 ty.fold_binders( 128 crate::fold_free_vars(ty, |bound, _binders| {
114 &mut |ty, binders| { 129 let (v, k) = self.free_vars[bound.index];
115 if let TyKind::BoundVar(bound) = ty.kind(&Interner) { 130 TyKind::InferenceVar(v, k).intern(&Interner)
116 if bound.debruijn >= binders { 131 })
117 let (v, k) = self.free_vars[bound.index];
118 TyKind::InferenceVar(v, k).intern(&Interner)
119 } else {
120 ty
121 }
122 } else {
123 ty
124 }
125 },
126 DebruijnIndex::INNERMOST,
127 )
128 } 132 }
129 133
130 pub(super) fn apply_solution( 134 pub(super) fn apply_solution(
@@ -136,15 +140,17 @@ impl<T> Canonicalized<T> {
136 let new_vars = Substitution::from_iter( 140 let new_vars = Substitution::from_iter(
137 &Interner, 141 &Interner,
138 solution.binders.iter(&Interner).map(|k| match k.kind { 142 solution.binders.iter(&Interner).map(|k| match k.kind {
139 VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(), 143 VariableKind::Ty(TyVariableKind::General) => {
140 VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(), 144 ctx.table.new_type_var().cast(&Interner)
141 VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(), 145 }
142 // HACK: Chalk can sometimes return new lifetime variables. We 146 VariableKind::Ty(TyVariableKind::Integer) => {
143 // want to just skip them, but to not mess up the indices of 147 ctx.table.new_integer_var().cast(&Interner)
144 // other variables, we'll just create a new type variable in 148 }
145 // their place instead. This should not matter (we never see the 149 VariableKind::Ty(TyVariableKind::Float) => {
146 // actual *uses* of the lifetime variable). 150 ctx.table.new_float_var().cast(&Interner)
147 VariableKind::Lifetime => ctx.table.new_type_var(), 151 }
152 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
153 VariableKind::Lifetime => static_lifetime().cast(&Interner),
148 _ => panic!("const variable in solution"), 154 _ => panic!("const variable in solution"),
149 }), 155 }),
150 ); 156 );
@@ -488,55 +494,63 @@ impl InferenceTable {
488 /// be resolved as far as possible, i.e. contain no type variables with 494 /// be resolved as far as possible, i.e. contain no type variables with
489 /// known type. 495 /// known type.
490 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 496 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
491 ty.fold(&mut |ty| match ty.kind(&Interner) { 497 fold_tys(
492 &TyKind::InferenceVar(tv, kind) => { 498 ty,
493 let inner = from_inference_var(tv); 499 |ty, _| match ty.kind(&Interner) {
494 if tv_stack.contains(&inner) { 500 &TyKind::InferenceVar(tv, kind) => {
495 cov_mark::hit!(type_var_cycles_resolve_as_possible); 501 let inner = from_inference_var(tv);
496 // recursive type 502 if tv_stack.contains(&inner) {
497 return self.type_variable_table.fallback_value(tv, kind); 503 cov_mark::hit!(type_var_cycles_resolve_as_possible);
498 } 504 // recursive type
499 if let Some(known_ty) = 505 return self.type_variable_table.fallback_value(tv, kind);
500 self.var_unification_table.inlined_probe_value(inner).known() 506 }
501 { 507 if let Some(known_ty) =
502 // known_ty may contain other variables that are known by now 508 self.var_unification_table.inlined_probe_value(inner).known()
503 tv_stack.push(inner); 509 {
504 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone()); 510 // known_ty may contain other variables that are known by now
505 tv_stack.pop(); 511 tv_stack.push(inner);
506 result 512 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
507 } else { 513 tv_stack.pop();
508 ty 514 result
515 } else {
516 ty
517 }
509 } 518 }
510 } 519 _ => ty,
511 _ => ty, 520 },
512 }) 521 DebruijnIndex::INNERMOST,
522 )
513 } 523 }
514 524
515 /// Resolves the type completely; type variables without known type are 525 /// Resolves the type completely; type variables without known type are
516 /// replaced by TyKind::Unknown. 526 /// replaced by TyKind::Unknown.
517 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 527 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
518 ty.fold(&mut |ty| match ty.kind(&Interner) { 528 fold_tys(
519 &TyKind::InferenceVar(tv, kind) => { 529 ty,
520 let inner = from_inference_var(tv); 530 |ty, _| match ty.kind(&Interner) {
521 if tv_stack.contains(&inner) { 531 &TyKind::InferenceVar(tv, kind) => {
522 cov_mark::hit!(type_var_cycles_resolve_completely); 532 let inner = from_inference_var(tv);
523 // recursive type 533 if tv_stack.contains(&inner) {
524 return self.type_variable_table.fallback_value(tv, kind); 534 cov_mark::hit!(type_var_cycles_resolve_completely);
525 } 535 // recursive type
526 if let Some(known_ty) = 536 return self.type_variable_table.fallback_value(tv, kind);
527 self.var_unification_table.inlined_probe_value(inner).known() 537 }
528 { 538 if let Some(known_ty) =
529 // known_ty may contain other variables that are known by now 539 self.var_unification_table.inlined_probe_value(inner).known()
530 tv_stack.push(inner); 540 {
531 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone()); 541 // known_ty may contain other variables that are known by now
532 tv_stack.pop(); 542 tv_stack.push(inner);
533 result 543 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
534 } else { 544 tv_stack.pop();
535 self.type_variable_table.fallback_value(tv, kind) 545 result
546 } else {
547 self.type_variable_table.fallback_value(tv, kind)
548 }
536 } 549 }
537 } 550 _ => ty,
538 _ => ty, 551 },
539 }) 552 DebruijnIndex::INNERMOST,
553 )
540 } 554 }
541} 555}
542 556
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/interner.rs
index bd9395b7e..a1656115d 100644
--- a/crates/hir_ty/src/traits/chalk/interner.rs
+++ b/crates/hir_ty/src/interner.rs
@@ -1,61 +1,83 @@
1//! Implementation of the Chalk `Interner` trait, which allows customizing the 1//! Implementation of the Chalk `Interner` trait, which allows customizing the
2//! representation of the various objects Chalk deals with (types, goals etc.). 2//! representation of the various objects Chalk deals with (types, goals etc.).
3 3
4use super::tls; 4use crate::{chalk_db, tls, GenericArg};
5use base_db::salsa::InternId; 5use base_db::salsa::InternId;
6use chalk_ir::{GenericArg, Goal, GoalData}; 6use chalk_ir::{Goal, GoalData};
7use hir_def::TypeAliasId; 7use hir_def::{
8 intern::{impl_internable, InternStorage, Internable, Interned},
9 TypeAliasId,
10};
8use smallvec::SmallVec; 11use smallvec::SmallVec;
9use std::{fmt, sync::Arc}; 12use std::{fmt, sync::Arc};
10 13
11#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] 14#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
12pub struct Interner; 15pub struct Interner;
13 16
14pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>; 17#[derive(PartialEq, Eq, Hash, Debug)]
15pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>; 18pub struct InternedWrapper<T>(T);
16pub(crate) type TraitId = chalk_ir::TraitId<Interner>; 19
17pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>; 20impl<T> std::ops::Deref for InternedWrapper<T> {
18pub(crate) type AdtId = chalk_ir::AdtId<Interner>; 21 type Target = T;
19pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>; 22
20pub(crate) type ImplId = chalk_ir::ImplId<Interner>; 23 fn deref(&self) -> &Self::Target {
21pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>; 24 &self.0
22pub(crate) type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>; 25 }
23pub(crate) type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>; 26}
24pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; 27
25pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; 28impl_internable!(
26pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>; 29 InternedWrapper<Vec<chalk_ir::VariableKind<Interner>>>,
27pub(crate) type Variances = chalk_ir::Variances<Interner>; 30 InternedWrapper<SmallVec<[GenericArg; 2]>>,
31 InternedWrapper<chalk_ir::TyData<Interner>>,
32 InternedWrapper<chalk_ir::LifetimeData<Interner>>,
33 InternedWrapper<chalk_ir::ConstData<Interner>>,
34 InternedWrapper<Vec<chalk_ir::CanonicalVarKind<Interner>>>,
35 InternedWrapper<Vec<chalk_ir::ProgramClause<Interner>>>,
36 InternedWrapper<Vec<chalk_ir::QuantifiedWhereClause<Interner>>>,
37 InternedWrapper<Vec<chalk_ir::Variance>>,
38);
28 39
29impl chalk_ir::interner::Interner for Interner { 40impl chalk_ir::interner::Interner for Interner {
30 type InternedType = Arc<chalk_ir::TyData<Self>>; 41 type InternedType = Interned<InternedWrapper<chalk_ir::TyData<Interner>>>;
31 type InternedLifetime = chalk_ir::LifetimeData<Self>; 42 type InternedLifetime = Interned<InternedWrapper<chalk_ir::LifetimeData<Self>>>;
32 type InternedConst = Arc<chalk_ir::ConstData<Self>>; 43 type InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>;
33 type InternedConcreteConst = (); 44 type InternedConcreteConst = ();
34 type InternedGenericArg = chalk_ir::GenericArgData<Self>; 45 type InternedGenericArg = chalk_ir::GenericArgData<Self>;
35 type InternedGoal = Arc<GoalData<Self>>; 46 type InternedGoal = Arc<GoalData<Self>>;
36 type InternedGoals = Vec<Goal<Self>>; 47 type InternedGoals = Vec<Goal<Self>>;
37 type InternedSubstitution = SmallVec<[GenericArg<Self>; 2]>; 48 type InternedSubstitution = Interned<InternedWrapper<SmallVec<[GenericArg; 2]>>>;
38 type InternedProgramClause = Arc<chalk_ir::ProgramClauseData<Self>>; 49 type InternedProgramClause = chalk_ir::ProgramClauseData<Self>;
39 type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; 50 type InternedProgramClauses = Interned<InternedWrapper<Vec<chalk_ir::ProgramClause<Self>>>>;
40 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; 51 type InternedQuantifiedWhereClauses =
41 type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; 52 Interned<InternedWrapper<Vec<chalk_ir::QuantifiedWhereClause<Self>>>>;
42 type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; 53 type InternedVariableKinds = Interned<InternedWrapper<Vec<chalk_ir::VariableKind<Interner>>>>;
54 type InternedCanonicalVarKinds =
55 Interned<InternedWrapper<Vec<chalk_ir::CanonicalVarKind<Self>>>>;
43 type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>; 56 type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
44 type InternedVariances = Arc<[chalk_ir::Variance]>; 57 type InternedVariances = Interned<InternedWrapper<Vec<chalk_ir::Variance>>>;
45 type DefId = InternId; 58 type DefId = InternId;
46 type InternedAdtId = hir_def::AdtId; 59 type InternedAdtId = hir_def::AdtId;
47 type Identifier = TypeAliasId; 60 type Identifier = TypeAliasId;
48 type FnAbi = (); 61 type FnAbi = ();
49 62
50 fn debug_adt_id(type_kind_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 63 fn debug_adt_id(
64 type_kind_id: chalk_db::AdtId,
65 fmt: &mut fmt::Formatter<'_>,
66 ) -> Option<fmt::Result> {
51 tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) 67 tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
52 } 68 }
53 69
54 fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 70 fn debug_trait_id(
71 type_kind_id: chalk_db::TraitId,
72 fmt: &mut fmt::Formatter<'_>,
73 ) -> Option<fmt::Result> {
55 tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) 74 tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
56 } 75 }
57 76
58 fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 77 fn debug_assoc_type_id(
78 id: chalk_db::AssocTypeId,
79 fmt: &mut fmt::Formatter<'_>,
80 ) -> Option<fmt::Result> {
59 tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) 81 tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
60 } 82 }
61 83
@@ -99,7 +121,7 @@ impl chalk_ir::interner::Interner for Interner {
99 } 121 }
100 122
101 fn debug_generic_arg( 123 fn debug_generic_arg(
102 parameter: &GenericArg<Interner>, 124 parameter: &GenericArg,
103 fmt: &mut fmt::Formatter<'_>, 125 fmt: &mut fmt::Formatter<'_>,
104 ) -> Option<fmt::Result> { 126 ) -> Option<fmt::Result> {
105 tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) 127 tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt)))
@@ -194,30 +216,30 @@ impl chalk_ir::interner::Interner for Interner {
194 216
195 fn intern_ty(&self, kind: chalk_ir::TyKind<Self>) -> Self::InternedType { 217 fn intern_ty(&self, kind: chalk_ir::TyKind<Self>) -> Self::InternedType {
196 let flags = kind.compute_flags(self); 218 let flags = kind.compute_flags(self);
197 Arc::new(chalk_ir::TyData { kind, flags }) 219 Interned::new(InternedWrapper(chalk_ir::TyData { kind, flags }))
198 } 220 }
199 221
200 fn ty_data<'a>(&self, ty: &'a Self::InternedType) -> &'a chalk_ir::TyData<Self> { 222 fn ty_data<'a>(&self, ty: &'a Self::InternedType) -> &'a chalk_ir::TyData<Self> {
201 ty 223 &ty.0
202 } 224 }
203 225
204 fn intern_lifetime(&self, lifetime: chalk_ir::LifetimeData<Self>) -> Self::InternedLifetime { 226 fn intern_lifetime(&self, lifetime: chalk_ir::LifetimeData<Self>) -> Self::InternedLifetime {
205 lifetime 227 Interned::new(InternedWrapper(lifetime))
206 } 228 }
207 229
208 fn lifetime_data<'a>( 230 fn lifetime_data<'a>(
209 &self, 231 &self,
210 lifetime: &'a Self::InternedLifetime, 232 lifetime: &'a Self::InternedLifetime,
211 ) -> &'a chalk_ir::LifetimeData<Self> { 233 ) -> &'a chalk_ir::LifetimeData<Self> {
212 lifetime 234 &lifetime.0
213 } 235 }
214 236
215 fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Self::InternedConst { 237 fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Self::InternedConst {
216 Arc::new(constant) 238 Interned::new(InternedWrapper(constant))
217 } 239 }
218 240
219 fn const_data<'a>(&self, constant: &'a Self::InternedConst) -> &'a chalk_ir::ConstData<Self> { 241 fn const_data<'a>(&self, constant: &'a Self::InternedConst) -> &'a chalk_ir::ConstData<Self> {
220 constant 242 &constant.0
221 } 243 }
222 244
223 fn const_eq( 245 fn const_eq(
@@ -264,23 +286,23 @@ impl chalk_ir::interner::Interner for Interner {
264 286
265 fn intern_substitution<E>( 287 fn intern_substitution<E>(
266 &self, 288 &self,
267 data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>, 289 data: impl IntoIterator<Item = Result<GenericArg, E>>,
268 ) -> Result<Self::InternedSubstitution, E> { 290 ) -> Result<Self::InternedSubstitution, E> {
269 data.into_iter().collect() 291 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
270 } 292 }
271 293
272 fn substitution_data<'a>( 294 fn substitution_data<'a>(
273 &self, 295 &self,
274 substitution: &'a Self::InternedSubstitution, 296 substitution: &'a Self::InternedSubstitution,
275 ) -> &'a [GenericArg<Self>] { 297 ) -> &'a [GenericArg] {
276 substitution 298 &substitution.as_ref().0
277 } 299 }
278 300
279 fn intern_program_clause( 301 fn intern_program_clause(
280 &self, 302 &self,
281 data: chalk_ir::ProgramClauseData<Self>, 303 data: chalk_ir::ProgramClauseData<Self>,
282 ) -> Self::InternedProgramClause { 304 ) -> Self::InternedProgramClause {
283 Arc::new(data) 305 data
284 } 306 }
285 307
286 fn program_clause_data<'a>( 308 fn program_clause_data<'a>(
@@ -294,7 +316,7 @@ impl chalk_ir::interner::Interner for Interner {
294 &self, 316 &self,
295 data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, 317 data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>,
296 ) -> Result<Self::InternedProgramClauses, E> { 318 ) -> Result<Self::InternedProgramClauses, E> {
297 data.into_iter().collect() 319 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
298 } 320 }
299 321
300 fn program_clauses_data<'a>( 322 fn program_clauses_data<'a>(
@@ -308,7 +330,7 @@ impl chalk_ir::interner::Interner for Interner {
308 &self, 330 &self,
309 data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, 331 data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>,
310 ) -> Result<Self::InternedQuantifiedWhereClauses, E> { 332 ) -> Result<Self::InternedQuantifiedWhereClauses, E> {
311 data.into_iter().collect() 333 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
312 } 334 }
313 335
314 fn quantified_where_clauses_data<'a>( 336 fn quantified_where_clauses_data<'a>(
@@ -322,21 +344,21 @@ impl chalk_ir::interner::Interner for Interner {
322 &self, 344 &self,
323 data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>, 345 data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>,
324 ) -> Result<Self::InternedVariableKinds, E> { 346 ) -> Result<Self::InternedVariableKinds, E> {
325 data.into_iter().collect() 347 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
326 } 348 }
327 349
328 fn variable_kinds_data<'a>( 350 fn variable_kinds_data<'a>(
329 &self, 351 &self,
330 parameter_kinds: &'a Self::InternedVariableKinds, 352 parameter_kinds: &'a Self::InternedVariableKinds,
331 ) -> &'a [chalk_ir::VariableKind<Self>] { 353 ) -> &'a [chalk_ir::VariableKind<Self>] {
332 &parameter_kinds 354 &parameter_kinds.as_ref().0
333 } 355 }
334 356
335 fn intern_canonical_var_kinds<E>( 357 fn intern_canonical_var_kinds<E>(
336 &self, 358 &self,
337 data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>, 359 data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>,
338 ) -> Result<Self::InternedCanonicalVarKinds, E> { 360 ) -> Result<Self::InternedCanonicalVarKinds, E> {
339 data.into_iter().collect() 361 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
340 } 362 }
341 363
342 fn canonical_var_kinds_data<'a>( 364 fn canonical_var_kinds_data<'a>(
@@ -376,7 +398,7 @@ impl chalk_ir::interner::Interner for Interner {
376 &self, 398 &self,
377 data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>, 399 data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>,
378 ) -> Result<Self::InternedVariances, E> { 400 ) -> Result<Self::InternedVariances, E> {
379 data.into_iter().collect() 401 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
380 } 402 }
381 403
382 fn variances_data<'a>( 404 fn variances_data<'a>(
@@ -390,3 +412,12 @@ impl chalk_ir::interner::Interner for Interner {
390impl chalk_ir::interner::HasInterner for Interner { 412impl chalk_ir::interner::HasInterner for Interner {
391 type Interner = Self; 413 type Interner = Self;
392} 414}
415
416#[macro_export]
417macro_rules! has_interner {
418 ($t:ty) => {
419 impl HasInterner for $t {
420 type Interner = crate::Interner;
421 }
422 };
423}
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index 87f10e9d5..113234fa4 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -1,27 +1,29 @@
1//! The type system. We currently use this to infer types for completion, hover 1//! The type system. We currently use this to infer types for completion, hover
2//! information and various assists. 2//! information and various assists.
3
3#[allow(unused)] 4#[allow(unused)]
4macro_rules! eprintln { 5macro_rules! eprintln {
5 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; 6 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
6} 7}
7 8
8mod autoderef; 9mod autoderef;
9pub mod primitive;
10pub mod traits;
11pub mod method_resolution;
12mod op;
13mod lower;
14pub(crate) mod infer;
15pub(crate) mod utils;
16mod chalk_cast;
17mod chalk_ext;
18mod builder; 10mod builder;
11mod chalk_db;
12mod chalk_ext;
13mod infer;
14mod interner;
15mod lower;
16mod mapping;
17mod op;
18mod tls;
19mod utils;
19mod walk; 20mod walk;
20mod types;
21
22pub mod display;
23pub mod db; 21pub mod db;
24pub mod diagnostics; 22pub mod diagnostics;
23pub mod display;
24pub mod method_resolution;
25pub mod primitive;
26pub mod traits;
25 27
26#[cfg(test)] 28#[cfg(test)]
27mod tests; 29mod tests;
@@ -30,12 +32,12 @@ mod test_db;
30 32
31use std::sync::Arc; 33use std::sync::Arc;
32 34
33use base_db::salsa; 35use chalk_ir::{
34use chalk_ir::UintTy; 36 fold::{Fold, Shift},
35use hir_def::{ 37 interner::HasInterner,
36 expr::ExprId, type_ref::Rawness, ConstParamId, LifetimeParamId, TraitId, TypeAliasId, 38 UintTy,
37 TypeParamId,
38}; 39};
40use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId};
39 41
40use crate::{db::HirDatabase, display::HirDisplay, utils::generics}; 42use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
41 43
@@ -43,12 +45,17 @@ pub use autoderef::autoderef;
43pub use builder::TyBuilder; 45pub use builder::TyBuilder;
44pub use chalk_ext::*; 46pub use chalk_ext::*;
45pub use infer::{could_unify, InferenceResult}; 47pub use infer::{could_unify, InferenceResult};
48pub use interner::Interner;
46pub use lower::{ 49pub use lower::{
47 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 50 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
48 TyDefId, TyLoweringContext, ValueTyDefId, 51 TyDefId, TyLoweringContext, ValueTyDefId,
49}; 52};
50pub use traits::{chalk::Interner, TraitEnvironment}; 53pub use mapping::{
51pub use types::*; 54 const_from_placeholder_idx, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
55 from_placeholder_idx, lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
56 to_foreign_def_id, to_placeholder_idx,
57};
58pub use traits::TraitEnvironment;
52pub use walk::TypeWalk; 59pub use walk::TypeWalk;
53 60
54pub use chalk_ir::{ 61pub use chalk_ir::{
@@ -65,6 +72,21 @@ pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
65pub type VariableKind = chalk_ir::VariableKind<Interner>; 72pub type VariableKind = chalk_ir::VariableKind<Interner>;
66pub type VariableKinds = chalk_ir::VariableKinds<Interner>; 73pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
67pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>; 74pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
75pub type Binders<T> = chalk_ir::Binders<T>;
76pub type Substitution = chalk_ir::Substitution<Interner>;
77pub type GenericArg = chalk_ir::GenericArg<Interner>;
78pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
79
80pub type Ty = chalk_ir::Ty<Interner>;
81pub type TyKind = chalk_ir::TyKind<Interner>;
82pub type DynTy = chalk_ir::DynTy<Interner>;
83pub type FnPointer = chalk_ir::FnPointer<Interner>;
84// pub type FnSubst = chalk_ir::FnSubst<Interner>;
85pub use chalk_ir::FnSubst;
86pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
87pub type AliasTy = chalk_ir::AliasTy<Interner>;
88pub type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
89pub type InferenceVar = chalk_ir::InferenceVar;
68 90
69pub type Lifetime = chalk_ir::Lifetime<Interner>; 91pub type Lifetime = chalk_ir::Lifetime<Interner>;
70pub type LifetimeData = chalk_ir::LifetimeData<Interner>; 92pub type LifetimeData = chalk_ir::LifetimeData<Interner>;
@@ -76,12 +98,27 @@ pub type ConstValue = chalk_ir::ConstValue<Interner>;
76pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>; 98pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
77 99
78pub type ChalkTraitId = chalk_ir::TraitId<Interner>; 100pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
101pub type TraitRef = chalk_ir::TraitRef<Interner>;
102pub type QuantifiedWhereClause = Binders<WhereClause>;
103pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
104pub type Canonical<T> = chalk_ir::Canonical<T>;
79 105
80pub type FnSig = chalk_ir::FnSig<Interner>; 106pub type FnSig = chalk_ir::FnSig<Interner>;
81 107
108pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
109pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
110pub type AliasEq = chalk_ir::AliasEq<Interner>;
111pub type Solution = chalk_solve::Solution<Interner>;
112pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
113pub type Guidance = chalk_solve::Guidance<Interner>;
114pub type WhereClause = chalk_ir::WhereClause<Interner>;
115
82// FIXME: get rid of this 116// FIXME: get rid of this
83pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution { 117pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
84 Substitution::intern(s.interned()[..std::cmp::min(s.len(&Interner), n)].into()) 118 Substitution::from_iter(
119 &Interner,
120 s.as_slice(&Interner)[..std::cmp::min(s.len(&Interner), n)].iter().cloned(),
121 )
85} 122}
86 123
87/// Return an index of a parameter in the generic type parameter list by it's id. 124/// Return an index of a parameter in the generic type parameter list by it's id.
@@ -89,14 +126,17 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
89 generics(db.upcast(), id.parent).param_idx(id) 126 generics(db.upcast(), id.parent).param_idx(id)
90} 127}
91 128
92pub fn wrap_empty_binders<T>(value: T) -> Binders<T> 129pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
93where 130where
94 T: TypeWalk, 131 T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>,
95{ 132{
96 Binders::empty(&Interner, value.shifted_in_from(DebruijnIndex::ONE)) 133 Binders::empty(&Interner, value.shifted_in_from(&Interner, DebruijnIndex::ONE))
97} 134}
98 135
99pub fn make_only_type_binders<T>(num_vars: usize, value: T) -> Binders<T> { 136pub(crate) fn make_only_type_binders<T: HasInterner<Interner = Interner>>(
137 num_vars: usize,
138 value: T,
139) -> Binders<T> {
100 Binders::new( 140 Binders::new(
101 VariableKinds::from_iter( 141 VariableKinds::from_iter(
102 &Interner, 142 &Interner,
@@ -108,7 +148,7 @@ pub fn make_only_type_binders<T>(num_vars: usize, value: T) -> Binders<T> {
108} 148}
109 149
110// FIXME: get rid of this 150// FIXME: get rid of this
111pub fn make_canonical<T>( 151pub fn make_canonical<T: HasInterner<Interner = Interner>>(
112 value: T, 152 value: T,
113 kinds: impl IntoIterator<Item = TyVariableKind>, 153 kinds: impl IntoIterator<Item = TyVariableKind>,
114) -> Canonical<T> { 154) -> Canonical<T> {
@@ -129,6 +169,8 @@ pub struct CallableSig {
129 is_varargs: bool, 169 is_varargs: bool,
130} 170}
131 171
172has_interner!(CallableSig);
173
132/// A polymorphic function signature. 174/// A polymorphic function signature.
133pub type PolyFnSig = Binders<CallableSig>; 175pub type PolyFnSig = Binders<CallableSig>;
134 176
@@ -144,10 +186,10 @@ impl CallableSig {
144 params_and_return: fn_ptr 186 params_and_return: fn_ptr
145 .substitution 187 .substitution
146 .clone() 188 .clone()
147 .shifted_out_to(DebruijnIndex::ONE) 189 .shifted_out_to(&Interner, DebruijnIndex::ONE)
148 .expect("unexpected lifetime vars in fn ptr") 190 .expect("unexpected lifetime vars in fn ptr")
149 .0 191 .0
150 .interned() 192 .as_slice(&Interner)
151 .iter() 193 .iter()
152 .map(|arg| arg.assert_ty_ref(&Interner).clone()) 194 .map(|arg| arg.assert_ty_ref(&Interner).clone())
153 .collect(), 195 .collect(),
@@ -164,7 +206,22 @@ impl CallableSig {
164 } 206 }
165} 207}
166 208
167impl Ty {} 209impl Fold<Interner> for CallableSig {
210 type Result = CallableSig;
211
212 fn fold_with<'i>(
213 self,
214 folder: &mut dyn chalk_ir::fold::Folder<'i, Interner>,
215 outer_binder: DebruijnIndex,
216 ) -> chalk_ir::Fallible<Self::Result>
217 where
218 Interner: 'i,
219 {
220 let vec = self.params_and_return.to_vec();
221 let folded = vec.fold_with(folder, outer_binder)?;
222 Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
223 }
224}
168 225
169#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 226#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
170pub enum ImplTraitId { 227pub enum ImplTraitId {
@@ -177,70 +234,75 @@ pub struct ReturnTypeImplTraits {
177 pub(crate) impl_traits: Vec<ReturnTypeImplTrait>, 234 pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
178} 235}
179 236
237has_interner!(ReturnTypeImplTraits);
238
180#[derive(Clone, PartialEq, Eq, Debug, Hash)] 239#[derive(Clone, PartialEq, Eq, Debug, Hash)]
181pub(crate) struct ReturnTypeImplTrait { 240pub(crate) struct ReturnTypeImplTrait {
182 pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>, 241 pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
183} 242}
184 243
185pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId { 244pub fn static_lifetime() -> Lifetime {
186 chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id)) 245 LifetimeData::Static.intern(&Interner)
187}
188
189pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId {
190 salsa::InternKey::from_intern_id(id.0)
191}
192
193pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId {
194 chalk_ir::AssocTypeId(salsa::InternKey::as_intern_id(&id))
195}
196
197pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId {
198 salsa::InternKey::from_intern_id(id.0)
199}
200
201pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeParamId {
202 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
203 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
204 db.lookup_intern_type_param_id(interned_id)
205} 246}
206 247
207pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderIndex { 248pub fn dummy_usize_const() -> Const {
208 let interned_id = db.intern_type_param_id(id); 249 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner);
209 PlaceholderIndex { 250 chalk_ir::ConstData {
210 ui: chalk_ir::UniverseIndex::ROOT, 251 ty: usize_ty,
211 idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(), 252 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
212 } 253 }
254 .intern(&Interner)
213} 255}
214 256
215pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> LifetimeParamId { 257pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
216 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); 258 t: T,
217 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx)); 259 f: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
218 db.lookup_intern_lifetime_param_id(interned_id) 260) -> T::Result {
219} 261 use chalk_ir::{fold::Folder, Fallible};
262 struct FreeVarFolder<F>(F);
263 impl<'i, F: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for FreeVarFolder<F> {
264 fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
265 self
266 }
220 267
221pub fn const_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> ConstParamId { 268 fn interner(&self) -> &'i Interner {
222 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); 269 &Interner
223 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx)); 270 }
224 db.lookup_intern_const_param_id(interned_id)
225}
226 271
227pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId { 272 fn fold_free_var_ty(
228 chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id)) 273 &mut self,
274 bound_var: BoundVar,
275 outer_binder: DebruijnIndex,
276 ) -> Fallible<Ty> {
277 Ok(self.0(bound_var, outer_binder))
278 }
279 }
280 t.fold_with(&mut FreeVarFolder(f), DebruijnIndex::INNERMOST).expect("fold failed unexpectedly")
229} 281}
230 282
231pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId { 283pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
232 salsa::InternKey::from_intern_id(id.0) 284 t: T,
233} 285 f: impl FnMut(Ty, DebruijnIndex) -> Ty,
286 binders: DebruijnIndex,
287) -> T::Result {
288 use chalk_ir::{
289 fold::{Folder, SuperFold},
290 Fallible,
291 };
292 struct TyFolder<F>(F);
293 impl<'i, F: FnMut(Ty, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for TyFolder<F> {
294 fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
295 self
296 }
234 297
235pub fn static_lifetime() -> Lifetime { 298 fn interner(&self) -> &'i Interner {
236 LifetimeData::Static.intern(&Interner) 299 &Interner
237} 300 }
238 301
239pub fn dummy_usize_const() -> Const { 302 fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
240 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner); 303 let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
241 chalk_ir::ConstData { 304 Ok(self.0(ty, outer_binder))
242 ty: usize_ty, 305 }
243 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
244 } 306 }
245 .intern(&Interner) 307 t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
246} 308}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index e6903e189..a035686bc 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -8,7 +8,7 @@
8use std::{iter, sync::Arc}; 8use std::{iter, sync::Arc};
9 9
10use base_db::CrateId; 10use base_db::CrateId;
11use chalk_ir::{cast::Cast, Mutability, Safety}; 11use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
12use hir_def::{ 12use hir_def::{
13 adt::StructKind, 13 adt::StructKind,
14 builtin_type::BuiltinType, 14 builtin_type::BuiltinType,
@@ -27,15 +27,16 @@ use stdx::impl_from;
27 27
28use crate::{ 28use crate::{
29 db::HirDatabase, 29 db::HirDatabase,
30 dummy_usize_const, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, 30 dummy_usize_const,
31 traits::chalk::{Interner, ToChalk}, 31 mapping::ToChalk,
32 static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
32 utils::{ 33 utils::{
33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics, 34 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
34 }, 35 },
35 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, 36 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
36 FnSubst, ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, 37 FnSubst, ImplTraitId, Interner, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
37 QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, 38 QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
38 TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, TypeWalk, WhereClause, 39 TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
39}; 40};
40 41
41#[derive(Debug)] 42#[derive(Debug)]
@@ -488,7 +489,7 @@ impl<'a> TyLoweringContext<'a> {
488 }; 489 };
489 // We need to shift in the bound vars, since 490 // We need to shift in the bound vars, since
490 // associated_type_shorthand_candidates does not do that 491 // associated_type_shorthand_candidates does not do that
491 let substs = substs.shifted_in_from(self.in_binders); 492 let substs = substs.shifted_in_from(&Interner, self.in_binders);
492 // FIXME handle type parameters on the segment 493 // FIXME handle type parameters on the segment
493 return Some( 494 return Some(
494 TyKind::Alias(AliasTy::Projection(ProjectionTy { 495 TyKind::Alias(AliasTy::Projection(ProjectionTy {
@@ -847,7 +848,7 @@ pub fn associated_type_shorthand_candidates<R>(
847 // FIXME: how to correctly handle higher-ranked bounds here? 848 // FIXME: how to correctly handle higher-ranked bounds here?
848 WhereClause::Implemented(tr) => search( 849 WhereClause::Implemented(tr) => search(
849 tr.clone() 850 tr.clone()
850 .shifted_out_to(DebruijnIndex::ONE) 851 .shifted_out_to(&Interner, DebruijnIndex::ONE)
851 .expect("FIXME unexpected higher-ranked trait bound"), 852 .expect("FIXME unexpected higher-ranked trait bound"),
852 ), 853 ),
853 _ => None, 854 _ => None,
@@ -950,8 +951,7 @@ pub(crate) fn trait_environment_query(
950 traits_in_scope 951 traits_in_scope
951 .push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id())); 952 .push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
952 } 953 }
953 let program_clause: chalk_ir::ProgramClause<Interner> = 954 let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
954 pred.clone().to_chalk(db).cast(&Interner);
955 clauses.push(program_clause.into_from_env_clause(&Interner)); 955 clauses.push(program_clause.into_from_env_clause(&Interner));
956 } 956 }
957 } 957 }
@@ -974,7 +974,7 @@ pub(crate) fn trait_environment_query(
974 let substs = TyBuilder::type_params_subst(db, trait_id); 974 let substs = TyBuilder::type_params_subst(db, trait_id);
975 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; 975 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
976 let pred = WhereClause::Implemented(trait_ref); 976 let pred = WhereClause::Implemented(trait_ref);
977 let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner); 977 let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
978 clauses.push(program_clause.into_from_env_clause(&Interner)); 978 clauses.push(program_clause.into_from_env_clause(&Interner));
979 } 979 }
980 980
@@ -1016,22 +1016,16 @@ pub(crate) fn generic_defaults_query(
1016 p.default.as_ref().map_or(TyKind::Error.intern(&Interner), |t| ctx.lower_ty(t)); 1016 p.default.as_ref().map_or(TyKind::Error.intern(&Interner), |t| ctx.lower_ty(t));
1017 1017
1018 // Each default can only refer to previous parameters. 1018 // Each default can only refer to previous parameters.
1019 ty = ty.fold_binders( 1019 ty = crate::fold_free_vars(ty, |bound, binders| {
1020 &mut |ty, binders| match ty.kind(&Interner) { 1020 if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST {
1021 TyKind::BoundVar(BoundVar { debruijn, index }) if *debruijn == binders => { 1021 // type variable default referring to parameter coming
1022 if *index >= idx { 1022 // after it. This is forbidden (FIXME: report
1023 // type variable default referring to parameter coming 1023 // diagnostic)
1024 // after it. This is forbidden (FIXME: report 1024 TyKind::Error.intern(&Interner)
1025 // diagnostic) 1025 } else {
1026 TyKind::Error.intern(&Interner) 1026 bound.shifted_in_from(binders).to_ty(&Interner)
1027 } else { 1027 }
1028 ty 1028 });
1029 }
1030 }
1031 _ => ty,
1032 },
1033 DebruijnIndex::INNERMOST,
1034 );
1035 1029
1036 crate::make_only_type_binders(idx, ty) 1030 crate::make_only_type_binders(idx, ty)
1037 }) 1031 })
@@ -1307,6 +1301,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
1307 } 1301 }
1308} 1302}
1309 1303
1310fn make_binders<T>(generics: &Generics, value: T) -> Binders<T> { 1304fn make_binders<T: HasInterner<Interner = Interner>>(generics: &Generics, value: T) -> Binders<T> {
1311 crate::make_only_type_binders(generics.len(), value) 1305 crate::make_only_type_binders(generics.len(), value)
1312} 1306}
diff --git a/crates/hir_ty/src/mapping.rs b/crates/hir_ty/src/mapping.rs
new file mode 100644
index 000000000..5e86fafe5
--- /dev/null
+++ b/crates/hir_ty/src/mapping.rs
@@ -0,0 +1,154 @@
1//! This module contains the implementations of the `ToChalk` trait, which
2//! handles conversion between our data types and their corresponding types in
3//! Chalk (in both directions); plus some helper functions for more specialized
4//! conversions.
5
6use chalk_solve::rust_ir;
7
8use base_db::salsa::{self, InternKey};
9use hir_def::{ConstParamId, LifetimeParamId, TraitId, TypeAliasId, TypeParamId};
10
11use crate::{
12 chalk_db, db::HirDatabase, AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId,
13 Interner, OpaqueTyId, PlaceholderIndex,
14};
15
16pub(crate) trait ToChalk {
17 type Chalk;
18 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk;
19 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self;
20}
21
22pub(crate) fn from_chalk<T, ChalkT>(db: &dyn HirDatabase, chalk: ChalkT) -> T
23where
24 T: ToChalk<Chalk = ChalkT>,
25{
26 T::from_chalk(db, chalk)
27}
28
29impl ToChalk for hir_def::ImplId {
30 type Chalk = chalk_db::ImplId;
31
32 fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::ImplId {
33 chalk_ir::ImplId(self.as_intern_id())
34 }
35
36 fn from_chalk(_db: &dyn HirDatabase, impl_id: chalk_db::ImplId) -> hir_def::ImplId {
37 InternKey::from_intern_id(impl_id.0)
38 }
39}
40
41impl ToChalk for CallableDefId {
42 type Chalk = FnDefId;
43
44 fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
45 db.intern_callable_def(self).into()
46 }
47
48 fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
49 db.lookup_intern_callable_def(fn_def_id.into())
50 }
51}
52
53pub(crate) struct TypeAliasAsValue(pub(crate) TypeAliasId);
54
55impl ToChalk for TypeAliasAsValue {
56 type Chalk = chalk_db::AssociatedTyValueId;
57
58 fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::AssociatedTyValueId {
59 rust_ir::AssociatedTyValueId(self.0.as_intern_id())
60 }
61
62 fn from_chalk(
63 _db: &dyn HirDatabase,
64 assoc_ty_value_id: chalk_db::AssociatedTyValueId,
65 ) -> TypeAliasAsValue {
66 TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0))
67 }
68}
69
70impl From<FnDefId> for crate::db::InternedCallableDefId {
71 fn from(fn_def_id: FnDefId) -> Self {
72 InternKey::from_intern_id(fn_def_id.0)
73 }
74}
75
76impl From<crate::db::InternedCallableDefId> for FnDefId {
77 fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self {
78 chalk_ir::FnDefId(callable_def_id.as_intern_id())
79 }
80}
81
82impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
83 fn from(id: OpaqueTyId) -> Self {
84 InternKey::from_intern_id(id.0)
85 }
86}
87
88impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
89 fn from(id: crate::db::InternedOpaqueTyId) -> Self {
90 chalk_ir::OpaqueTyId(id.as_intern_id())
91 }
92}
93
94impl From<chalk_ir::ClosureId<Interner>> for crate::db::InternedClosureId {
95 fn from(id: chalk_ir::ClosureId<Interner>) -> Self {
96 Self::from_intern_id(id.0)
97 }
98}
99
100impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
101 fn from(id: crate::db::InternedClosureId) -> Self {
102 chalk_ir::ClosureId(id.as_intern_id())
103 }
104}
105
106pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
107 chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id))
108}
109
110pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId {
111 salsa::InternKey::from_intern_id(id.0)
112}
113
114pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId {
115 chalk_ir::AssocTypeId(salsa::InternKey::as_intern_id(&id))
116}
117
118pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId {
119 salsa::InternKey::from_intern_id(id.0)
120}
121
122pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeParamId {
123 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
124 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
125 db.lookup_intern_type_param_id(interned_id)
126}
127
128pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderIndex {
129 let interned_id = db.intern_type_param_id(id);
130 PlaceholderIndex {
131 ui: chalk_ir::UniverseIndex::ROOT,
132 idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
133 }
134}
135
136pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> LifetimeParamId {
137 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
138 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
139 db.lookup_intern_lifetime_param_id(interned_id)
140}
141
142pub fn const_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> ConstParamId {
143 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
144 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
145 db.lookup_intern_const_param_id(interned_id)
146}
147
148pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
149 chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
150}
151
152pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId {
153 salsa::InternKey::from_intern_id(id.0)
154}
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 7e09a1539..ece884241 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -13,6 +13,7 @@ use hir_def::{
13}; 13};
14use hir_expand::name::Name; 14use hir_expand::name::Name;
15use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::{FxHashMap, FxHashSet};
16use stdx::always;
16 17
17use crate::{ 18use crate::{
18 autoderef, 19 autoderef,
@@ -21,32 +22,36 @@ use crate::{
21 primitive::{self, FloatTy, IntTy, UintTy}, 22 primitive::{self, FloatTy, IntTy, UintTy},
22 static_lifetime, 23 static_lifetime,
23 utils::all_super_traits, 24 utils::all_super_traits,
24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, 25 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, 26 Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
26 TyExt, TyKind, TypeWalk,
27}; 27};
28 28
29/// This is used as a key for indexing impls. 29/// This is used as a key for indexing impls.
30#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 30#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
31pub enum TyFingerprint { 31pub enum TyFingerprint {
32 // These are lang item impls:
32 Str, 33 Str,
33 Slice, 34 Slice,
34 Array, 35 Array,
35 Never, 36 Never,
36 RawPtr(Mutability), 37 RawPtr(Mutability),
37 Scalar(Scalar), 38 Scalar(Scalar),
39 // These can have user-defined impls:
38 Adt(hir_def::AdtId), 40 Adt(hir_def::AdtId),
39 Dyn(TraitId), 41 Dyn(TraitId),
40 Tuple(usize),
41 ForeignType(ForeignDefId), 42 ForeignType(ForeignDefId),
42 FnPtr(usize, FnSig), 43 // These only exist for trait impls
44 Unit,
45 Unnameable,
46 Function(u32),
43} 47}
44 48
45impl TyFingerprint { 49impl TyFingerprint {
46 /// Creates a TyFingerprint for looking up an impl. Only certain types can 50 /// Creates a TyFingerprint for looking up an inherent impl. Only certain
47 /// have impls: if we have some `struct S`, we can have an `impl S`, but not 51 /// types can have inherent impls: if we have some `struct S`, we can have
48 /// `impl &S`. Hence, this will return `None` for reference types and such. 52 /// an `impl S`, but not `impl &S`. Hence, this will return `None` for
49 pub fn for_impl(ty: &Ty) -> Option<TyFingerprint> { 53 /// reference types and such.
54 pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
50 let fp = match ty.kind(&Interner) { 55 let fp = match ty.kind(&Interner) {
51 TyKind::Str => TyFingerprint::Str, 56 TyKind::Str => TyFingerprint::Str,
52 TyKind::Never => TyFingerprint::Never, 57 TyKind::Never => TyFingerprint::Never,
@@ -54,17 +59,52 @@ impl TyFingerprint {
54 TyKind::Array(..) => TyFingerprint::Array, 59 TyKind::Array(..) => TyFingerprint::Array,
55 TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar), 60 TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
56 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt), 61 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
57 TyKind::Tuple(cardinality, _) => TyFingerprint::Tuple(*cardinality),
58 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability), 62 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
59 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id), 63 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
60 TyKind::Function(FnPointer { sig, substitution: substs, .. }) => {
61 TyFingerprint::FnPtr(substs.0.len(&Interner) - 1, *sig)
62 }
63 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?, 64 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
64 _ => return None, 65 _ => return None,
65 }; 66 };
66 Some(fp) 67 Some(fp)
67 } 68 }
69
70 /// Creates a TyFingerprint for looking up a trait impl.
71 pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
72 let fp = match ty.kind(&Interner) {
73 TyKind::Str => TyFingerprint::Str,
74 TyKind::Never => TyFingerprint::Never,
75 TyKind::Slice(..) => TyFingerprint::Slice,
76 TyKind::Array(..) => TyFingerprint::Array,
77 TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
78 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
79 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
80 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
81 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
82 TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
83 TyKind::Tuple(_, subst) => {
84 let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(&Interner));
85 if let Some(ty) = first_ty {
86 return TyFingerprint::for_trait_impl(ty);
87 } else {
88 TyFingerprint::Unit
89 }
90 }
91 TyKind::AssociatedType(_, _)
92 | TyKind::OpaqueType(_, _)
93 | TyKind::FnDef(_, _)
94 | TyKind::Closure(_, _)
95 | TyKind::Generator(..)
96 | TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable,
97 TyKind::Function(fn_ptr) => {
98 TyFingerprint::Function(fn_ptr.substitution.0.len(&Interner) as u32)
99 }
100 TyKind::Alias(_)
101 | TyKind::Placeholder(_)
102 | TyKind::BoundVar(_)
103 | TyKind::InferenceVar(_, _)
104 | TyKind::Error => return None,
105 };
106 Some(fp)
107 }
68} 108}
69 109
70pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ 110pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
@@ -112,7 +152,7 @@ impl TraitImpls {
112 None => continue, 152 None => continue,
113 }; 153 };
114 let self_ty = db.impl_self_ty(impl_id); 154 let self_ty = db.impl_self_ty(impl_id);
115 let self_ty_fp = TyFingerprint::for_impl(self_ty.skip_binders()); 155 let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
116 impls 156 impls
117 .map 157 .map
118 .entry(target_trait) 158 .entry(target_trait)
@@ -157,10 +197,13 @@ impl TraitImpls {
157 } 197 }
158 198
159 /// Queries all trait impls for the given type. 199 /// Queries all trait impls for the given type.
160 pub fn for_self_ty(&self, fp: TyFingerprint) -> impl Iterator<Item = ImplId> + '_ { 200 pub fn for_self_ty_without_blanket_impls(
201 &self,
202 fp: TyFingerprint,
203 ) -> impl Iterator<Item = ImplId> + '_ {
161 self.map 204 self.map
162 .values() 205 .values()
163 .flat_map(move |impls| impls.get(&None).into_iter().chain(impls.get(&Some(fp)))) 206 .flat_map(move |impls| impls.get(&Some(fp)).into_iter())
164 .flat_map(|it| it.iter().copied()) 207 .flat_map(|it| it.iter().copied())
165 } 208 }
166 209
@@ -215,7 +258,9 @@ impl InherentImpls {
215 } 258 }
216 259
217 let self_ty = db.impl_self_ty(impl_id); 260 let self_ty = db.impl_self_ty(impl_id);
218 if let Some(fp) = TyFingerprint::for_impl(self_ty.skip_binders()) { 261 let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
262 always!(fp.is_some());
263 if let Some(fp) = fp {
219 map.entry(fp).or_default().push(impl_id); 264 map.entry(fp).or_default().push(impl_id);
220 } 265 }
221 } 266 }
@@ -228,7 +273,7 @@ impl InherentImpls {
228 } 273 }
229 274
230 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { 275 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
231 match TyFingerprint::for_impl(self_ty) { 276 match TyFingerprint::for_inherent_impl(self_ty) {
232 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), 277 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
233 None => &[], 278 None => &[],
234 } 279 }
@@ -609,6 +654,7 @@ fn iterate_trait_method_candidates(
609 } 654 }
610 } 655 }
611 known_implemented = true; 656 known_implemented = true;
657 // FIXME: we shouldn't be ignoring the binders here
612 if callback(&self_ty.value, *item) { 658 if callback(&self_ty.value, *item) {
613 return true; 659 return true;
614 } 660 }
@@ -757,20 +803,13 @@ pub(crate) fn inherent_impl_substs(
757/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past 803/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
758/// num_vars_to_keep) by `TyKind::Unknown`. 804/// num_vars_to_keep) by `TyKind::Unknown`.
759fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution { 805fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution {
760 s.fold_binders( 806 crate::fold_free_vars(s, |bound, binders| {
761 &mut |ty, binders| { 807 if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
762 if let TyKind::BoundVar(bound) = ty.kind(&Interner) { 808 TyKind::Error.intern(&Interner)
763 if bound.index >= num_vars_to_keep && bound.debruijn >= binders { 809 } else {
764 TyKind::Error.intern(&Interner) 810 bound.shifted_in_from(binders).to_ty(&Interner)
765 } else { 811 }
766 ty 812 })
767 }
768 } else {
769 ty
770 }
771 },
772 DebruijnIndex::INNERMOST,
773 )
774} 813}
775 814
776fn transform_receiver_ty( 815fn transform_receiver_ty(
diff --git a/crates/hir_ty/src/primitive.rs b/crates/hir_ty/src/primitive.rs
index 2449addfb..d7f48c69a 100644
--- a/crates/hir_ty/src/primitive.rs
+++ b/crates/hir_ty/src/primitive.rs
@@ -1,7 +1,4 @@
1//! Defines primitive types, which have a couple of peculiarities: 1//! A few helper functions for dealing with primitives.
2//!
3//! * during type inference, they can be uncertain (ie, `let x = 92;`)
4//! * they don't belong to any particular crate.
5 2
6pub use chalk_ir::{FloatTy, IntTy, UintTy}; 3pub use chalk_ir::{FloatTy, IntTy, UintTy};
7pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}; 4pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint};
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index b69f86050..9cd9f473d 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -974,3 +974,41 @@ fn param_overrides_fn() {
974 "#, 974 "#,
975 ) 975 )
976} 976}
977
978#[test]
979fn lifetime_from_chalk_during_deref() {
980 check_types(
981 r#"
982 #[lang = "deref"]
983 pub trait Deref {
984 type Target;
985 }
986
987 struct Box<T: ?Sized> {}
988 impl<T> Deref for Box<T> {
989 type Target = T;
990
991 fn deref(&self) -> &Self::Target {
992 loop {}
993 }
994 }
995
996 trait Iterator {
997 type Item;
998 }
999
1000 pub struct Iter<'a, T: 'a> {
1001 inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
1002 }
1003
1004 trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
1005 fn clone_box(&self);
1006 }
1007
1008 fn clone_iter<T>(s: Iter<T>) {
1009 s.inner.clone_box();
1010 //^^^^^^^^^^^^^^^^^^^ ()
1011 }
1012 "#,
1013 )
1014}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 65b71fdfa..1c1aa491d 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3413,3 +3413,33 @@ fn foo() {
3413 "#]], 3413 "#]],
3414 ); 3414 );
3415} 3415}
3416
3417#[test]
3418fn renamed_extern_crate_in_block() {
3419 check_types(
3420 r#"
3421//- /lib.rs crate:lib deps:serde
3422use serde::Deserialize;
3423
3424struct Foo {}
3425
3426const _ : () = {
3427 extern crate serde as _serde;
3428 impl _serde::Deserialize for Foo {
3429 fn deserialize() -> u8 { 0 }
3430 }
3431};
3432
3433fn foo() {
3434 Foo::deserialize();
3435 //^^^^^^^^^^^^^^^^^^ u8
3436}
3437
3438//- /serde.rs crate:serde
3439
3440pub trait Deserialize {
3441 fn deserialize() -> u8;
3442}
3443 "#,
3444 );
3445}
diff --git a/crates/hir_ty/src/traits/chalk/tls.rs b/crates/hir_ty/src/tls.rs
index 8892a63a9..87c671a42 100644
--- a/crates/hir_ty/src/traits/chalk/tls.rs
+++ b/crates/hir_ty/src/tls.rs
@@ -4,8 +4,10 @@ use std::fmt;
4use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication}; 4use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication};
5use itertools::Itertools; 5use itertools::Itertools;
6 6
7use super::{from_chalk, Interner}; 7use crate::{
8use crate::{db::HirDatabase, from_assoc_type_id, CallableDefId}; 8 chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
9 CallableDefId, Interner,
10};
9use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId}; 11use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
10 12
11pub(crate) use unsafe_tls::{set_current_program, with_current_program}; 13pub(crate) use unsafe_tls::{set_current_program, with_current_program};
@@ -15,7 +17,7 @@ pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase);
15impl DebugContext<'_> { 17impl DebugContext<'_> {
16 pub(crate) fn debug_struct_id( 18 pub(crate) fn debug_struct_id(
17 &self, 19 &self,
18 id: super::AdtId, 20 id: chalk_db::AdtId,
19 f: &mut fmt::Formatter<'_>, 21 f: &mut fmt::Formatter<'_>,
20 ) -> Result<(), fmt::Error> { 22 ) -> Result<(), fmt::Error> {
21 let name = match id.0 { 23 let name = match id.0 {
@@ -28,17 +30,17 @@ impl DebugContext<'_> {
28 30
29 pub(crate) fn debug_trait_id( 31 pub(crate) fn debug_trait_id(
30 &self, 32 &self,
31 id: super::TraitId, 33 id: chalk_db::TraitId,
32 fmt: &mut fmt::Formatter<'_>, 34 fmt: &mut fmt::Formatter<'_>,
33 ) -> Result<(), fmt::Error> { 35 ) -> Result<(), fmt::Error> {
34 let trait_: hir_def::TraitId = from_chalk(self.0, id); 36 let trait_: hir_def::TraitId = from_chalk_trait_id(id);
35 let trait_data = self.0.trait_data(trait_); 37 let trait_data = self.0.trait_data(trait_);
36 write!(fmt, "{}", trait_data.name) 38 write!(fmt, "{}", trait_data.name)
37 } 39 }
38 40
39 pub(crate) fn debug_assoc_type_id( 41 pub(crate) fn debug_assoc_type_id(
40 &self, 42 &self,
41 id: super::AssocTypeId, 43 id: chalk_db::AssocTypeId,
42 fmt: &mut fmt::Formatter<'_>, 44 fmt: &mut fmt::Formatter<'_>,
43 ) -> Result<(), fmt::Error> { 45 ) -> Result<(), fmt::Error> {
44 let type_alias: TypeAliasId = from_assoc_type_id(id); 46 let type_alias: TypeAliasId = from_assoc_type_id(id);
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index 7d87741b8..9936d0803 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -1,28 +1,26 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2
2use std::env::var; 3use std::env::var;
3 4
4use base_db::CrateId;
5use chalk_ir::cast::Cast; 5use chalk_ir::cast::Cast;
6use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver}; 6use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
7
8use base_db::CrateId;
7use hir_def::{lang_item::LangItemTarget, TraitId}; 9use hir_def::{lang_item::LangItemTarget, TraitId};
8use stdx::panic_context; 10use stdx::panic_context;
9 11
10use crate::{ 12use crate::{
11 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment, 13 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment,
12 Solution, TraitRefExt, Ty, TyKind, WhereClause, 14 Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
13}; 15};
14 16
15use self::chalk::{from_chalk, Interner, ToChalk};
16
17pub(crate) mod chalk;
18
19/// This controls how much 'time' we give the Chalk solver before giving up. 17/// This controls how much 'time' we give the Chalk solver before giving up.
20const CHALK_SOLVER_FUEL: i32 = 100; 18const CHALK_SOLVER_FUEL: i32 = 100;
21 19
22#[derive(Debug, Copy, Clone)] 20#[derive(Debug, Copy, Clone)]
23struct ChalkContext<'a> { 21pub(crate) struct ChalkContext<'a> {
24 db: &'a dyn HirDatabase, 22 pub(crate) db: &'a dyn HirDatabase,
25 krate: CrateId, 23 pub(crate) krate: CrateId,
26} 24}
27 25
28fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> { 26fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
@@ -81,6 +79,7 @@ pub(crate) fn trait_solve_query(
81 db.trait_data(it.hir_trait_id()).name.to_string() 79 db.trait_data(it.hir_trait_id()).name.to_string()
82 } 80 }
83 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(), 81 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(),
82 _ => "??".to_string(),
84 }); 83 });
85 log::info!("trait_solve_query({})", goal.value.goal.display(db)); 84 log::info!("trait_solve_query({})", goal.value.goal.display(db));
86 85
@@ -95,13 +94,12 @@ pub(crate) fn trait_solve_query(
95 } 94 }
96 } 95 }
97 96
98 let canonical = goal.to_chalk(db).cast(&Interner); 97 let canonical = goal.cast(&Interner);
99 98
100 // We currently don't deal with universes (I think / hope they're not yet 99 // We currently don't deal with universes (I think / hope they're not yet
101 // relevant for our use cases?) 100 // relevant for our use cases?)
102 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 101 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
103 let solution = solve(db, krate, &u_canonical); 102 solve(db, krate, &u_canonical)
104 solution.map(|solution| solution_from_chalk(db, solution))
105} 103}
106 104
107fn solve( 105fn solve(
@@ -148,7 +146,7 @@ fn solve(
148 // don't set the TLS for Chalk unless Chalk debugging is active, to make 146 // don't set the TLS for Chalk unless Chalk debugging is active, to make
149 // extra sure we only use it for debugging 147 // extra sure we only use it for debugging
150 let solution = 148 let solution =
151 if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; 149 if is_chalk_debug() { crate::tls::set_current_program(db, solve) } else { solve() };
152 150
153 solution 151 solution
154} 152}
@@ -169,26 +167,6 @@ fn is_chalk_print() -> bool {
169 std::env::var("CHALK_PRINT").is_ok() 167 std::env::var("CHALK_PRINT").is_ok()
170} 168}
171 169
172fn solution_from_chalk(
173 db: &dyn HirDatabase,
174 solution: chalk_solve::Solution<Interner>,
175) -> Solution {
176 match solution {
177 chalk_solve::Solution::Unique(constr_subst) => {
178 Solution::Unique(from_chalk(db, constr_subst))
179 }
180 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => {
181 Solution::Ambig(Guidance::Definite(from_chalk(db, subst)))
182 }
183 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => {
184 Solution::Ambig(Guidance::Suggested(from_chalk(db, subst)))
185 }
186 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => {
187 Solution::Ambig(Guidance::Unknown)
188 }
189 }
190}
191
192#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 170#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
193pub enum FnTrait { 171pub enum FnTrait {
194 FnOnce, 172 FnOnce,
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
deleted file mode 100644
index 701359e6f..000000000
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ /dev/null
@@ -1,546 +0,0 @@
1//! This module contains the implementations of the `ToChalk` trait, which
2//! handles conversion between our data types and their corresponding types in
3//! Chalk (in both directions); plus some helper functions for more specialized
4//! conversions.
5
6use chalk_ir::{cast::Cast, interner::HasInterner};
7use chalk_solve::rust_ir;
8
9use base_db::salsa::InternKey;
10use hir_def::{GenericDefId, TypeAliasId};
11
12use crate::{
13 db::HirDatabase, static_lifetime, AliasTy, CallableDefId, Canonical, ConstrainedSubst,
14 DomainGoal, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy, ProjectionTyExt,
15 QuantifiedWhereClause, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
16};
17
18use super::interner::*;
19use super::*;
20
21impl ToChalk for Ty {
22 type Chalk = chalk_ir::Ty<Interner>;
23 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
24 match self.into_inner() {
25 TyKind::Ref(m, lt, ty) => {
26 chalk_ir::TyKind::Ref(m, lt, ty.to_chalk(db)).intern(&Interner)
27 }
28 TyKind::Array(ty, size) => {
29 chalk_ir::TyKind::Array(ty.to_chalk(db), size).intern(&Interner)
30 }
31 TyKind::Function(FnPointer { sig, substitution: substs, num_binders }) => {
32 let substitution = chalk_ir::FnSubst(substs.0.to_chalk(db));
33 chalk_ir::TyKind::Function(chalk_ir::FnPointer { num_binders, sig, substitution })
34 .intern(&Interner)
35 }
36 TyKind::AssociatedType(assoc_type_id, substs) => {
37 let substitution = substs.to_chalk(db);
38 chalk_ir::TyKind::AssociatedType(assoc_type_id, substitution).intern(&Interner)
39 }
40
41 TyKind::OpaqueType(id, substs) => {
42 let substitution = substs.to_chalk(db);
43 chalk_ir::TyKind::OpaqueType(id, substitution).intern(&Interner)
44 }
45
46 TyKind::Foreign(id) => chalk_ir::TyKind::Foreign(id).intern(&Interner),
47
48 TyKind::Scalar(scalar) => chalk_ir::TyKind::Scalar(scalar).intern(&Interner),
49
50 TyKind::Tuple(cardinality, substs) => {
51 let substitution = substs.to_chalk(db);
52 chalk_ir::TyKind::Tuple(cardinality, substitution).intern(&Interner)
53 }
54 TyKind::Raw(mutability, ty) => {
55 let ty = ty.to_chalk(db);
56 chalk_ir::TyKind::Raw(mutability, ty).intern(&Interner)
57 }
58 TyKind::Slice(ty) => chalk_ir::TyKind::Slice(ty.to_chalk(db)).intern(&Interner),
59 TyKind::Str => chalk_ir::TyKind::Str.intern(&Interner),
60 TyKind::FnDef(id, substs) => {
61 let substitution = substs.to_chalk(db);
62 chalk_ir::TyKind::FnDef(id, substitution).intern(&Interner)
63 }
64 TyKind::Never => chalk_ir::TyKind::Never.intern(&Interner),
65
66 TyKind::Closure(closure_id, substs) => {
67 let substitution = substs.to_chalk(db);
68 chalk_ir::TyKind::Closure(closure_id, substitution).intern(&Interner)
69 }
70
71 TyKind::Adt(adt_id, substs) => {
72 let substitution = substs.to_chalk(db);
73 chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner)
74 }
75 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
76 chalk_ir::AliasTy::Projection(proj_ty.to_chalk(db))
77 .cast(&Interner)
78 .intern(&Interner)
79 }
80 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
81 chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)).cast(&Interner).intern(&Interner)
82 }
83 TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner),
84 TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner),
85 TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"),
86 TyKind::Dyn(dyn_ty) => {
87 let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders();
88 let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter(
89 &Interner,
90 bounds.interned().iter().cloned().map(|p| p.to_chalk(db)),
91 );
92 let bounded_ty = chalk_ir::DynTy {
93 bounds: chalk_ir::Binders::new(binders, where_clauses),
94 lifetime: dyn_ty.lifetime,
95 };
96 chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner)
97 }
98 TyKind::Error => chalk_ir::TyKind::Error.intern(&Interner),
99 }
100 }
101 fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
102 match chalk.data(&Interner).kind.clone() {
103 chalk_ir::TyKind::Error => TyKind::Error,
104 chalk_ir::TyKind::Array(ty, size) => TyKind::Array(from_chalk(db, ty), size),
105 chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx),
106 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => {
107 TyKind::Alias(AliasTy::Projection(from_chalk(db, proj)))
108 }
109 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => {
110 TyKind::Alias(AliasTy::Opaque(from_chalk(db, opaque_ty)))
111 }
112 chalk_ir::TyKind::Function(chalk_ir::FnPointer {
113 num_binders,
114 sig,
115 substitution,
116 ..
117 }) => {
118 assert_eq!(num_binders, 0);
119 let substs = crate::FnSubst(from_chalk(db, substitution.0));
120 TyKind::Function(FnPointer { num_binders, sig, substitution: substs })
121 }
122 chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx),
123 chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Error,
124 chalk_ir::TyKind::Dyn(dyn_ty) => {
125 assert_eq!(dyn_ty.bounds.binders.len(&Interner), 1);
126 let (bounds, binders) = dyn_ty.bounds.into_value_and_skipped_binders();
127 let where_clauses = crate::QuantifiedWhereClauses::from_iter(
128 &Interner,
129 bounds.interned().iter().cloned().map(|p| from_chalk(db, p)),
130 );
131 TyKind::Dyn(crate::DynTy {
132 bounds: crate::Binders::new(binders, where_clauses),
133 // HACK: we sometimes get lifetime variables back in solutions
134 // from Chalk, and don't have the infrastructure to substitute
135 // them yet. So for now we just turn them into 'static right
136 // when we get them
137 lifetime: static_lifetime(),
138 })
139 }
140
141 chalk_ir::TyKind::Adt(adt_id, subst) => TyKind::Adt(adt_id, from_chalk(db, subst)),
142 chalk_ir::TyKind::AssociatedType(type_id, subst) => {
143 TyKind::AssociatedType(type_id, from_chalk(db, subst))
144 }
145
146 chalk_ir::TyKind::OpaqueType(opaque_type_id, subst) => {
147 TyKind::OpaqueType(opaque_type_id, from_chalk(db, subst))
148 }
149
150 chalk_ir::TyKind::Scalar(scalar) => TyKind::Scalar(scalar),
151 chalk_ir::TyKind::Tuple(cardinality, subst) => {
152 TyKind::Tuple(cardinality, from_chalk(db, subst))
153 }
154 chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)),
155 chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)),
156 chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => {
157 // HACK: we sometimes get lifetime variables back in solutions
158 // from Chalk, and don't have the infrastructure to substitute
159 // them yet. So for now we just turn them into 'static right
160 // when we get them
161 TyKind::Ref(mutability, static_lifetime(), from_chalk(db, ty))
162 }
163 chalk_ir::TyKind::Str => TyKind::Str,
164 chalk_ir::TyKind::Never => TyKind::Never,
165
166 chalk_ir::TyKind::FnDef(fn_def_id, subst) => {
167 TyKind::FnDef(fn_def_id, from_chalk(db, subst))
168 }
169
170 chalk_ir::TyKind::Closure(id, subst) => TyKind::Closure(id, from_chalk(db, subst)),
171
172 chalk_ir::TyKind::Foreign(foreign_def_id) => TyKind::Foreign(foreign_def_id),
173 chalk_ir::TyKind::Generator(_, _) => unimplemented!(), // FIXME
174 chalk_ir::TyKind::GeneratorWitness(_, _) => unimplemented!(), // FIXME
175 }
176 .intern(&Interner)
177 }
178}
179
180impl ToChalk for GenericArg {
181 type Chalk = chalk_ir::GenericArg<Interner>;
182
183 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
184 match self.interned() {
185 crate::GenericArgData::Ty(ty) => ty.clone().to_chalk(db).cast(&Interner),
186 }
187 }
188
189 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
190 match chalk.interned() {
191 chalk_ir::GenericArgData::Ty(ty) => Ty::from_chalk(db, ty.clone()).cast(&Interner),
192 chalk_ir::GenericArgData::Lifetime(_) => unimplemented!(),
193 chalk_ir::GenericArgData::Const(_) => unimplemented!(),
194 }
195 }
196}
197
198impl ToChalk for Substitution {
199 type Chalk = chalk_ir::Substitution<Interner>;
200
201 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
202 chalk_ir::Substitution::from_iter(
203 &Interner,
204 self.iter(&Interner).map(|ty| ty.clone().to_chalk(db)),
205 )
206 }
207
208 fn from_chalk(
209 db: &dyn HirDatabase,
210 parameters: chalk_ir::Substitution<Interner>,
211 ) -> Substitution {
212 let tys = parameters.iter(&Interner).map(|p| from_chalk(db, p.clone())).collect();
213 Substitution::intern(tys)
214 }
215}
216
217impl ToChalk for TraitRef {
218 type Chalk = chalk_ir::TraitRef<Interner>;
219
220 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
221 let trait_id = self.trait_id;
222 let substitution = self.substitution.to_chalk(db);
223 chalk_ir::TraitRef { trait_id, substitution }
224 }
225
226 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
227 let trait_id = trait_ref.trait_id;
228 let substs = from_chalk(db, trait_ref.substitution);
229 TraitRef { trait_id, substitution: substs }
230 }
231}
232
233impl ToChalk for hir_def::TraitId {
234 type Chalk = TraitId;
235
236 fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId {
237 chalk_ir::TraitId(self.as_intern_id())
238 }
239
240 fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId {
241 InternKey::from_intern_id(trait_id.0)
242 }
243}
244
245impl ToChalk for hir_def::ImplId {
246 type Chalk = ImplId;
247
248 fn to_chalk(self, _db: &dyn HirDatabase) -> ImplId {
249 chalk_ir::ImplId(self.as_intern_id())
250 }
251
252 fn from_chalk(_db: &dyn HirDatabase, impl_id: ImplId) -> hir_def::ImplId {
253 InternKey::from_intern_id(impl_id.0)
254 }
255}
256
257impl ToChalk for CallableDefId {
258 type Chalk = FnDefId;
259
260 fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
261 db.intern_callable_def(self).into()
262 }
263
264 fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
265 db.lookup_intern_callable_def(fn_def_id.into())
266 }
267}
268
269pub(crate) struct TypeAliasAsValue(pub(crate) TypeAliasId);
270
271impl ToChalk for TypeAliasAsValue {
272 type Chalk = AssociatedTyValueId;
273
274 fn to_chalk(self, _db: &dyn HirDatabase) -> AssociatedTyValueId {
275 rust_ir::AssociatedTyValueId(self.0.as_intern_id())
276 }
277
278 fn from_chalk(
279 _db: &dyn HirDatabase,
280 assoc_ty_value_id: AssociatedTyValueId,
281 ) -> TypeAliasAsValue {
282 TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0))
283 }
284}
285
286impl ToChalk for WhereClause {
287 type Chalk = chalk_ir::WhereClause<Interner>;
288
289 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::WhereClause<Interner> {
290 match self {
291 WhereClause::Implemented(trait_ref) => {
292 chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db))
293 }
294 WhereClause::AliasEq(alias_eq) => chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db)),
295 }
296 }
297
298 fn from_chalk(
299 db: &dyn HirDatabase,
300 where_clause: chalk_ir::WhereClause<Interner>,
301 ) -> WhereClause {
302 match where_clause {
303 chalk_ir::WhereClause::Implemented(tr) => WhereClause::Implemented(from_chalk(db, tr)),
304 chalk_ir::WhereClause::AliasEq(alias_eq) => {
305 WhereClause::AliasEq(from_chalk(db, alias_eq))
306 }
307
308 chalk_ir::WhereClause::LifetimeOutlives(_) => {
309 // we shouldn't get these from Chalk
310 panic!("encountered LifetimeOutlives from Chalk")
311 }
312
313 chalk_ir::WhereClause::TypeOutlives(_) => {
314 // we shouldn't get these from Chalk
315 panic!("encountered TypeOutlives from Chalk")
316 }
317 }
318 }
319}
320
321impl ToChalk for ProjectionTy {
322 type Chalk = chalk_ir::ProjectionTy<Interner>;
323
324 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> {
325 chalk_ir::ProjectionTy {
326 associated_ty_id: self.associated_ty_id,
327 substitution: self.substitution.to_chalk(db),
328 }
329 }
330
331 fn from_chalk(
332 db: &dyn HirDatabase,
333 projection_ty: chalk_ir::ProjectionTy<Interner>,
334 ) -> ProjectionTy {
335 ProjectionTy {
336 associated_ty_id: projection_ty.associated_ty_id,
337 substitution: from_chalk(db, projection_ty.substitution),
338 }
339 }
340}
341impl ToChalk for OpaqueTy {
342 type Chalk = chalk_ir::OpaqueTy<Interner>;
343
344 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
345 chalk_ir::OpaqueTy {
346 opaque_ty_id: self.opaque_ty_id,
347 substitution: self.substitution.to_chalk(db),
348 }
349 }
350
351 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
352 OpaqueTy {
353 opaque_ty_id: chalk.opaque_ty_id,
354 substitution: from_chalk(db, chalk.substitution),
355 }
356 }
357}
358
359impl ToChalk for AliasTy {
360 type Chalk = chalk_ir::AliasTy<Interner>;
361
362 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
363 match self {
364 AliasTy::Projection(projection_ty) => {
365 chalk_ir::AliasTy::Projection(projection_ty.to_chalk(db))
366 }
367 AliasTy::Opaque(opaque_ty) => chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)),
368 }
369 }
370
371 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
372 match chalk {
373 chalk_ir::AliasTy::Projection(projection_ty) => {
374 AliasTy::Projection(from_chalk(db, projection_ty))
375 }
376 chalk_ir::AliasTy::Opaque(opaque_ty) => AliasTy::Opaque(from_chalk(db, opaque_ty)),
377 }
378 }
379}
380
381impl ToChalk for AliasEq {
382 type Chalk = chalk_ir::AliasEq<Interner>;
383
384 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
385 chalk_ir::AliasEq { alias: self.alias.to_chalk(db), ty: self.ty.to_chalk(db) }
386 }
387
388 fn from_chalk(db: &dyn HirDatabase, alias_eq: chalk_ir::AliasEq<Interner>) -> Self {
389 AliasEq { alias: from_chalk(db, alias_eq.alias), ty: from_chalk(db, alias_eq.ty) }
390 }
391}
392
393impl ToChalk for DomainGoal {
394 type Chalk = chalk_ir::DomainGoal<Interner>;
395
396 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
397 match self {
398 DomainGoal::Holds(WhereClause::Implemented(tr)) => tr.to_chalk(db).cast(&Interner),
399 DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => {
400 alias_eq.to_chalk(db).cast(&Interner)
401 }
402 }
403 }
404
405 fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self {
406 unimplemented!()
407 }
408}
409
410impl<T> ToChalk for Canonical<T>
411where
412 T: ToChalk,
413 T::Chalk: HasInterner<Interner = Interner>,
414{
415 type Chalk = chalk_ir::Canonical<T::Chalk>;
416
417 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
418 let value = self.value.to_chalk(db);
419 chalk_ir::Canonical { value, binders: self.binders }
420 }
421
422 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
423 Canonical { binders: canonical.binders, value: from_chalk(db, canonical.value) }
424 }
425}
426
427impl<T: ToChalk> ToChalk for InEnvironment<T>
428where
429 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
430{
431 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
432
433 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
434 chalk_ir::InEnvironment { environment: self.environment, goal: self.goal.to_chalk(db) }
435 }
436
437 fn from_chalk(
438 _db: &dyn HirDatabase,
439 _in_env: chalk_ir::InEnvironment<T::Chalk>,
440 ) -> InEnvironment<T> {
441 unimplemented!()
442 }
443}
444
445impl<T: ToChalk> ToChalk for crate::Binders<T>
446where
447 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
448{
449 type Chalk = chalk_ir::Binders<T::Chalk>;
450
451 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Binders<T::Chalk> {
452 let (value, binders) = self.into_value_and_skipped_binders();
453 chalk_ir::Binders::new(binders, value.to_chalk(db))
454 }
455
456 fn from_chalk(db: &dyn HirDatabase, binders: chalk_ir::Binders<T::Chalk>) -> crate::Binders<T> {
457 let (v, b) = binders.into_value_and_skipped_binders();
458 crate::Binders::new(b, from_chalk(db, v))
459 }
460}
461
462impl ToChalk for crate::ConstrainedSubst {
463 type Chalk = chalk_ir::ConstrainedSubst<Interner>;
464
465 fn to_chalk(self, _db: &dyn HirDatabase) -> Self::Chalk {
466 unimplemented!()
467 }
468
469 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
470 ConstrainedSubst { subst: from_chalk(db, chalk.subst) }
471 }
472}
473
474pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
475where
476 T: HasInterner<Interner = Interner>,
477{
478 chalk_ir::Binders::new(
479 chalk_ir::VariableKinds::from_iter(
480 &Interner,
481 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
482 .take(num_vars),
483 ),
484 value,
485 )
486}
487
488pub(super) fn convert_where_clauses(
489 db: &dyn HirDatabase,
490 def: GenericDefId,
491 substs: &Substitution,
492) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> {
493 let generic_predicates = db.generic_predicates(def);
494 let mut result = Vec::with_capacity(generic_predicates.len());
495 for pred in generic_predicates.iter() {
496 result.push(pred.clone().substitute(&Interner, substs).to_chalk(db));
497 }
498 result
499}
500
501pub(super) fn generic_predicate_to_inline_bound(
502 db: &dyn HirDatabase,
503 pred: &QuantifiedWhereClause,
504 self_ty: &Ty,
505) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
506 // An InlineBound is like a GenericPredicate, except the self type is left out.
507 // We don't have a special type for this, but Chalk does.
508 let self_ty_shifted_in = self_ty.clone().shifted_in_from(DebruijnIndex::ONE);
509 let (pred, binders) = pred.as_ref().into_value_and_skipped_binders();
510 match pred {
511 WhereClause::Implemented(trait_ref) => {
512 if trait_ref.self_type_parameter(&Interner) != self_ty_shifted_in {
513 // we can only convert predicates back to type bounds if they
514 // have the expected self type
515 return None;
516 }
517 let args_no_self = trait_ref.substitution.interned()[1..]
518 .iter()
519 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
520 .collect();
521 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
522 Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
523 }
524 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
525 if projection_ty.self_type_parameter(&Interner) != self_ty_shifted_in {
526 return None;
527 }
528 let trait_ = projection_ty.trait_(db);
529 let args_no_self = projection_ty.substitution.interned()[1..]
530 .iter()
531 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
532 .collect();
533 let alias_eq_bound = rust_ir::AliasEqBound {
534 value: ty.clone().to_chalk(db),
535 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
536 associated_ty_id: projection_ty.associated_ty_id,
537 parameters: Vec::new(), // FIXME we don't support generic associated types yet
538 };
539 Some(chalk_ir::Binders::new(
540 binders,
541 rust_ir::InlineBound::AliasEqBound(alias_eq_bound),
542 ))
543 }
544 _ => None,
545 }
546}
diff --git a/crates/hir_ty/src/types.rs b/crates/hir_ty/src/types.rs
deleted file mode 100644
index 89adad108..000000000
--- a/crates/hir_ty/src/types.rs
+++ /dev/null
@@ -1,549 +0,0 @@
1//! This is the home of `Ty` etc. until they get replaced by their chalk_ir
2//! equivalents.
3
4use std::sync::Arc;
5
6use chalk_ir::{
7 cast::{Cast, CastTo, Caster},
8 BoundVar, Mutability, Scalar, TyVariableKind,
9};
10use smallvec::SmallVec;
11
12use crate::{
13 AssocTypeId, CanonicalVarKinds, ChalkTraitId, ClosureId, Const, FnDefId, FnSig, ForeignDefId,
14 Interner, Lifetime, OpaqueTyId, PlaceholderIndex, TypeWalk, VariableKind, VariableKinds,
15};
16
17#[derive(Clone, PartialEq, Eq, Debug, Hash)]
18pub struct OpaqueTy {
19 pub opaque_ty_id: OpaqueTyId,
20 pub substitution: Substitution,
21}
22
23/// A "projection" type corresponds to an (unnormalized)
24/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
25/// trait and all its parameters are fully known.
26#[derive(Clone, PartialEq, Eq, Debug, Hash)]
27pub struct ProjectionTy {
28 pub associated_ty_id: AssocTypeId,
29 pub substitution: Substitution,
30}
31
32impl ProjectionTy {
33 pub fn self_type_parameter(&self, interner: &Interner) -> Ty {
34 self.substitution.interned()[0].assert_ty_ref(interner).clone()
35 }
36}
37
38#[derive(Clone, PartialEq, Eq, Debug, Hash)]
39pub struct DynTy {
40 /// The unknown self type.
41 pub bounds: Binders<QuantifiedWhereClauses>,
42 pub lifetime: Lifetime,
43}
44
45#[derive(Clone, PartialEq, Eq, Debug, Hash)]
46pub struct FnPointer {
47 pub num_binders: usize,
48 pub sig: FnSig,
49 pub substitution: FnSubst,
50}
51/// A wrapper for the substs on a Fn.
52#[derive(Clone, PartialEq, Eq, Debug, Hash)]
53pub struct FnSubst(pub Substitution);
54
55impl FnPointer {
56 /// Represent the current `Fn` as if it was wrapped in `Binders`
57 pub fn into_binders(self, interner: &Interner) -> Binders<FnSubst> {
58 Binders::new(
59 VariableKinds::from_iter(
60 interner,
61 (0..self.num_binders).map(|_| VariableKind::Lifetime),
62 ),
63 self.substitution,
64 )
65 }
66
67 /// Represent the current `Fn` as if it was wrapped in `Binders`
68 pub fn as_binders(&self, interner: &Interner) -> Binders<&FnSubst> {
69 Binders::new(
70 VariableKinds::from_iter(
71 interner,
72 (0..self.num_binders).map(|_| VariableKind::Lifetime),
73 ),
74 &self.substitution,
75 )
76 }
77}
78
79#[derive(Clone, PartialEq, Eq, Debug, Hash)]
80pub enum AliasTy {
81 /// A "projection" type corresponds to an (unnormalized)
82 /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
83 /// trait and all its parameters are fully known.
84 Projection(ProjectionTy),
85 /// An opaque type (`impl Trait`).
86 ///
87 /// This is currently only used for return type impl trait; each instance of
88 /// `impl Trait` in a return type gets its own ID.
89 Opaque(OpaqueTy),
90}
91
92/// A type.
93///
94/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
95/// the same thing (but in a different way).
96///
97/// This should be cheap to clone.
98#[derive(Clone, PartialEq, Eq, Debug, Hash)]
99pub enum TyKind {
100 /// Structures, enumerations and unions.
101 Adt(chalk_ir::AdtId<Interner>, Substitution),
102
103 /// Represents an associated item like `Iterator::Item`. This is used
104 /// when we have tried to normalize a projection like `T::Item` but
105 /// couldn't find a better representation. In that case, we generate
106 /// an **application type** like `(Iterator::Item)<T>`.
107 AssociatedType(AssocTypeId, Substitution),
108
109 /// a scalar type like `bool` or `u32`
110 Scalar(Scalar),
111
112 /// A tuple type. For example, `(i32, bool)`.
113 Tuple(usize, Substitution),
114
115 /// An array with the given length. Written as `[T; n]`.
116 Array(Ty, Const),
117
118 /// The pointee of an array slice. Written as `[T]`.
119 Slice(Ty),
120
121 /// A raw pointer. Written as `*mut T` or `*const T`
122 Raw(Mutability, Ty),
123
124 /// A reference; a pointer with an associated lifetime. Written as
125 /// `&'a mut T` or `&'a T`.
126 Ref(Mutability, Lifetime, Ty),
127
128 /// This represents a placeholder for an opaque type in situations where we
129 /// don't know the hidden type (i.e. currently almost always). This is
130 /// analogous to the `AssociatedType` type constructor.
131 /// It is also used as the type of async block, with one type parameter
132 /// representing the Future::Output type.
133 OpaqueType(OpaqueTyId, Substitution),
134
135 /// The anonymous type of a function declaration/definition. Each
136 /// function has a unique type, which is output (for a function
137 /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
138 ///
139 /// This includes tuple struct / enum variant constructors as well.
140 ///
141 /// For example the type of `bar` here:
142 ///
143 /// ```
144 /// fn foo() -> i32 { 1 }
145 /// let bar = foo; // bar: fn() -> i32 {foo}
146 /// ```
147 FnDef(FnDefId, Substitution),
148
149 /// The pointee of a string slice. Written as `str`.
150 Str,
151
152 /// The never type `!`.
153 Never,
154
155 /// The type of a specific closure.
156 ///
157 /// The closure signature is stored in a `FnPtr` type in the first type
158 /// parameter.
159 Closure(ClosureId, Substitution),
160
161 /// Represents a foreign type declared in external blocks.
162 Foreign(ForeignDefId),
163
164 /// A pointer to a function. Written as `fn() -> i32`.
165 ///
166 /// For example the type of `bar` here:
167 ///
168 /// ```
169 /// fn foo() -> i32 { 1 }
170 /// let bar: fn() -> i32 = foo;
171 /// ```
172 Function(FnPointer),
173
174 /// An "alias" type represents some form of type alias, such as:
175 /// - An associated type projection like `<T as Iterator>::Item`
176 /// - `impl Trait` types
177 /// - Named type aliases like `type Foo<X> = Vec<X>`
178 Alias(AliasTy),
179
180 /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
181 /// {}` when we're type-checking the body of that function. In this
182 /// situation, we know this stands for *some* type, but don't know the exact
183 /// type.
184 Placeholder(PlaceholderIndex),
185
186 /// A bound type variable. This is used in various places: when representing
187 /// some polymorphic type like the type of function `fn f<T>`, the type
188 /// parameters get turned into variables; during trait resolution, inference
189 /// variables get turned into bound variables and back; and in `Dyn` the
190 /// `Self` type is represented with a bound variable as well.
191 BoundVar(BoundVar),
192
193 /// A type variable used during type checking.
194 InferenceVar(InferenceVar, TyVariableKind),
195
196 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
197 ///
198 /// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
199 /// represents the `Self` type inside the bounds. This is currently
200 /// implicit; Chalk has the `Binders` struct to make it explicit, but it
201 /// didn't seem worth the overhead yet.
202 Dyn(DynTy),
203
204 /// A placeholder for a type which could not be computed; this is propagated
205 /// to avoid useless error messages. Doubles as a placeholder where type
206 /// variables are inserted before type checking, since we want to try to
207 /// infer a better type here anyway -- for the IDE use case, we want to try
208 /// to infer as much as possible even in the presence of type errors.
209 Error,
210}
211
212#[derive(Clone, PartialEq, Eq, Debug, Hash)]
213pub struct Ty(Arc<TyKind>);
214
215impl TyKind {
216 pub fn intern(self, _interner: &Interner) -> Ty {
217 Ty(Arc::new(self))
218 }
219}
220
221impl Ty {
222 pub fn kind(&self, _interner: &Interner) -> &TyKind {
223 &self.0
224 }
225
226 pub fn interned_mut(&mut self) -> &mut TyKind {
227 Arc::make_mut(&mut self.0)
228 }
229
230 pub fn into_inner(self) -> TyKind {
231 Arc::try_unwrap(self.0).unwrap_or_else(|a| (*a).clone())
232 }
233}
234
235#[derive(Clone, PartialEq, Eq, Debug, Hash)]
236pub struct GenericArg {
237 interned: GenericArgData,
238}
239
240#[derive(Clone, PartialEq, Eq, Debug, Hash)]
241pub enum GenericArgData {
242 Ty(Ty),
243}
244
245impl GenericArg {
246 /// Constructs a generic argument using `GenericArgData`.
247 pub fn new(_interner: &Interner, data: GenericArgData) -> Self {
248 GenericArg { interned: data }
249 }
250
251 /// Gets the interned value.
252 pub fn interned(&self) -> &GenericArgData {
253 &self.interned
254 }
255
256 /// Asserts that this is a type argument.
257 pub fn assert_ty_ref(&self, interner: &Interner) -> &Ty {
258 self.ty(interner).unwrap()
259 }
260
261 /// Checks whether the generic argument is a type.
262 pub fn is_ty(&self, _interner: &Interner) -> bool {
263 match self.interned() {
264 GenericArgData::Ty(_) => true,
265 }
266 }
267
268 /// Returns the type if it is one, `None` otherwise.
269 pub fn ty(&self, _interner: &Interner) -> Option<&Ty> {
270 match self.interned() {
271 GenericArgData::Ty(t) => Some(t),
272 }
273 }
274
275 pub fn interned_mut(&mut self) -> &mut GenericArgData {
276 &mut self.interned
277 }
278}
279
280/// A list of substitutions for generic parameters.
281#[derive(Clone, PartialEq, Eq, Debug, Hash)]
282pub struct Substitution(SmallVec<[GenericArg; 2]>);
283
284impl Substitution {
285 pub fn interned(&self) -> &SmallVec<[GenericArg; 2]> {
286 &self.0
287 }
288
289 pub fn len(&self, _: &Interner) -> usize {
290 self.0.len()
291 }
292
293 pub fn is_empty(&self, _: &Interner) -> bool {
294 self.0.is_empty()
295 }
296
297 pub fn at(&self, _: &Interner, i: usize) -> &GenericArg {
298 &self.0[i]
299 }
300
301 pub fn empty(_: &Interner) -> Substitution {
302 Substitution(SmallVec::new())
303 }
304
305 pub fn iter(&self, _: &Interner) -> std::slice::Iter<'_, GenericArg> {
306 self.0.iter()
307 }
308
309 pub fn from1(_interner: &Interner, ty: Ty) -> Substitution {
310 Substitution::intern({
311 let mut v = SmallVec::new();
312 v.push(ty.cast(&Interner));
313 v
314 })
315 }
316
317 pub fn from_iter(
318 interner: &Interner,
319 elements: impl IntoIterator<Item = impl CastTo<GenericArg>>,
320 ) -> Self {
321 Substitution(elements.into_iter().casted(interner).collect())
322 }
323
324 pub fn apply<T: TypeWalk>(&self, value: T, _interner: &Interner) -> T {
325 value.subst_bound_vars(self)
326 }
327
328 // Temporary helper functions, to be removed
329 pub fn intern(interned: SmallVec<[GenericArg; 2]>) -> Substitution {
330 Substitution(interned)
331 }
332
333 pub fn interned_mut(&mut self) -> &mut SmallVec<[GenericArg; 2]> {
334 &mut self.0
335 }
336}
337
338#[derive(Clone, PartialEq, Eq, Hash)]
339pub struct Binders<T> {
340 /// The binders that quantify over the value.
341 pub binders: VariableKinds,
342 value: T,
343}
344
345impl<T> Binders<T> {
346 pub fn new(binders: VariableKinds, value: T) -> Self {
347 Self { binders, value }
348 }
349
350 pub fn empty(_interner: &Interner, value: T) -> Self {
351 crate::make_only_type_binders(0, value)
352 }
353
354 pub fn as_ref(&self) -> Binders<&T> {
355 Binders { binders: self.binders.clone(), value: &self.value }
356 }
357
358 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> {
359 Binders { binders: self.binders, value: f(self.value) }
360 }
361
362 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
363 Some(Binders { binders: self.binders, value: f(self.value)? })
364 }
365
366 pub fn skip_binders(&self) -> &T {
367 &self.value
368 }
369
370 pub fn into_value_and_skipped_binders(self) -> (T, VariableKinds) {
371 (self.value, self.binders)
372 }
373
374 /// Returns the number of binders.
375 pub fn len(&self, interner: &Interner) -> usize {
376 self.binders.len(interner)
377 }
378
379 // Temporary helper function, to be removed
380 pub fn skip_binders_mut(&mut self) -> &mut T {
381 &mut self.value
382 }
383}
384
385impl<T: Clone> Binders<&T> {
386 pub fn cloned(&self) -> Binders<T> {
387 Binders::new(self.binders.clone(), self.value.clone())
388 }
389}
390
391impl<T: TypeWalk> Binders<T> {
392 /// Substitutes all variables.
393 pub fn substitute(self, interner: &Interner, subst: &Substitution) -> T {
394 let (value, binders) = self.into_value_and_skipped_binders();
395 assert_eq!(subst.len(interner), binders.len(interner));
396 value.subst_bound_vars(subst)
397 }
398}
399
400impl<T: std::fmt::Debug> std::fmt::Debug for Binders<T> {
401 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
402 let Binders { ref binders, ref value } = *self;
403 write!(fmt, "for{:?} ", binders.inner_debug(&Interner))?;
404 std::fmt::Debug::fmt(value, fmt)
405 }
406}
407
408/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
409#[derive(Clone, PartialEq, Eq, Debug, Hash)]
410pub struct TraitRef {
411 pub trait_id: ChalkTraitId,
412 pub substitution: Substitution,
413}
414
415impl TraitRef {
416 pub fn self_type_parameter(&self, interner: &Interner) -> Ty {
417 self.substitution.at(interner, 0).assert_ty_ref(interner).clone()
418 }
419}
420
421/// Like `generics::WherePredicate`, but with resolved types: A condition on the
422/// parameters of a generic item.
423#[derive(Debug, Clone, PartialEq, Eq, Hash)]
424pub enum WhereClause {
425 /// The given trait needs to be implemented for its type parameters.
426 Implemented(TraitRef),
427 /// An associated type bindings like in `Iterator<Item = T>`.
428 AliasEq(AliasEq),
429}
430
431pub type QuantifiedWhereClause = Binders<WhereClause>;
432
433#[derive(Debug, Clone, PartialEq, Eq, Hash)]
434pub struct QuantifiedWhereClauses(Arc<[QuantifiedWhereClause]>);
435
436impl QuantifiedWhereClauses {
437 pub fn from_iter(
438 _interner: &Interner,
439 elements: impl IntoIterator<Item = QuantifiedWhereClause>,
440 ) -> Self {
441 QuantifiedWhereClauses(elements.into_iter().collect())
442 }
443
444 pub fn interned(&self) -> &Arc<[QuantifiedWhereClause]> {
445 &self.0
446 }
447
448 pub fn interned_mut(&mut self) -> &mut Arc<[QuantifiedWhereClause]> {
449 &mut self.0
450 }
451}
452
453/// Basically a claim (currently not validated / checked) that the contained
454/// type / trait ref contains no inference variables; any inference variables it
455/// contained have been replaced by bound variables, and `kinds` tells us how
456/// many there are and whether they were normal or float/int variables. This is
457/// used to erase irrelevant differences between types before using them in
458/// queries.
459#[derive(Debug, Clone, PartialEq, Eq, Hash)]
460pub struct Canonical<T> {
461 pub value: T,
462 pub binders: CanonicalVarKinds,
463}
464
465/// Something (usually a goal), along with an environment.
466#[derive(Clone, Debug, PartialEq, Eq, Hash)]
467pub struct InEnvironment<T> {
468 pub environment: chalk_ir::Environment<Interner>,
469 pub goal: T,
470}
471
472impl<T> InEnvironment<T> {
473 pub fn new(environment: &chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
474 InEnvironment { environment: environment.clone(), goal: value }
475 }
476}
477
478/// Something that needs to be proven (by Chalk) during type checking, e.g. that
479/// a certain type implements a certain trait. Proving the Obligation might
480/// result in additional information about inference variables.
481#[derive(Clone, Debug, PartialEq, Eq, Hash)]
482pub enum DomainGoal {
483 Holds(WhereClause),
484}
485
486#[derive(Clone, Debug, PartialEq, Eq, Hash)]
487pub struct AliasEq {
488 pub alias: AliasTy,
489 pub ty: Ty,
490}
491
492#[derive(Clone, Debug, PartialEq, Eq)]
493pub struct ConstrainedSubst {
494 pub subst: Substitution,
495}
496
497#[derive(Clone, Debug, PartialEq, Eq)]
498/// A (possible) solution for a proposed goal.
499pub enum Solution {
500 /// The goal indeed holds, and there is a unique value for all existential
501 /// variables.
502 Unique(Canonical<ConstrainedSubst>),
503
504 /// The goal may be provable in multiple ways, but regardless we may have some guidance
505 /// for type inference. In this case, we don't return any lifetime
506 /// constraints, since we have not "committed" to any particular solution
507 /// yet.
508 Ambig(Guidance),
509}
510
511#[derive(Clone, Debug, PartialEq, Eq)]
512/// When a goal holds ambiguously (e.g., because there are multiple possible
513/// solutions), we issue a set of *guidance* back to type inference.
514pub enum Guidance {
515 /// The existential variables *must* have the given values if the goal is
516 /// ever to hold, but that alone isn't enough to guarantee the goal will
517 /// actually hold.
518 Definite(Canonical<Substitution>),
519
520 /// There are multiple plausible values for the existentials, but the ones
521 /// here are suggested as the preferred choice heuristically. These should
522 /// be used for inference fallback only.
523 Suggested(Canonical<Substitution>),
524
525 /// There's no useful information to feed back to type inference
526 Unknown,
527}
528
529/// The kinds of placeholders we need during type inference. There's separate
530/// values for general types, and for integer and float variables. The latter
531/// two are used for inference of literal values (e.g. `100` could be one of
532/// several integer types).
533#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
534pub struct InferenceVar {
535 index: u32,
536}
537
538impl From<u32> for InferenceVar {
539 fn from(index: u32) -> InferenceVar {
540 InferenceVar { index }
541 }
542}
543
544impl InferenceVar {
545 /// Gets the underlying index value.
546 pub fn index(self) -> u32 {
547 self.index
548 }
549}
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 8d5d5cd73..5f6cb052a 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -1,8 +1,7 @@
1//! Helper functions for working with def, which don't need to be a separate 1//! Helper functions for working with def, which don't need to be a separate
2//! query, but can't be computed directly from `*Data` (ie, which need a `db`). 2//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3use std::sync::Arc;
4 3
5use chalk_ir::{BoundVar, DebruijnIndex}; 4use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
6use hir_def::{ 5use hir_def::{
7 db::DefDatabase, 6 db::DefDatabase,
8 generics::{ 7 generics::{
@@ -16,9 +15,7 @@ use hir_def::{
16}; 15};
17use hir_expand::name::{name, Name}; 16use hir_expand::name::{name, Name};
18 17
19use crate::{ 18use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, WhereClause};
20 db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, TypeWalk, WhereClause,
21};
22 19
23fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 20fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
24 let resolver = trait_.resolver(db); 21 let resolver = trait_.resolver(db);
@@ -69,7 +66,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
69 // FIXME: how to correctly handle higher-ranked bounds here? 66 // FIXME: how to correctly handle higher-ranked bounds here?
70 WhereClause::Implemented(tr) => Some( 67 WhereClause::Implemented(tr) => Some(
71 tr.clone() 68 tr.clone()
72 .shifted_out_to(DebruijnIndex::ONE) 69 .shifted_out_to(&Interner, DebruijnIndex::ONE)
73 .expect("FIXME unexpected higher-ranked trait bound"), 70 .expect("FIXME unexpected higher-ranked trait bound"),
74 ), 71 ),
75 _ => None, 72 _ => None,
@@ -137,15 +134,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
137 }) 134 })
138} 135}
139 136
140/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices).
141/// The underlying values are cloned if there are other strong references.
142pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
143 if Arc::get_mut(a).is_none() {
144 *a = a.iter().cloned().collect();
145 }
146 Arc::get_mut(a).unwrap()
147}
148
149pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { 137pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
150 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); 138 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
151 Generics { def, params: db.generic_params(def), parent_generics } 139 Generics { def, params: db.generic_params(def), parent_generics }
diff --git a/crates/hir_ty/src/walk.rs b/crates/hir_ty/src/walk.rs
index 91116dcda..6ef1d5336 100644
--- a/crates/hir_ty/src/walk.rs
+++ b/crates/hir_ty/src/walk.rs
@@ -1,138 +1,17 @@
1//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and 1//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and
2//! `Visit`). 2//! `Visit`).
3 3
4use std::mem; 4use chalk_ir::interner::HasInterner;
5
6use chalk_ir::DebruijnIndex;
7 5
8use crate::{ 6use crate::{
9 utils::make_mut_slice, AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, 7 AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, GenericArgData, Interner,
10 GenericArgData, Interner, OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, 8 OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause,
11 WhereClause,
12}; 9};
13 10
14/// This allows walking structures that contain types to do something with those 11/// This allows walking structures that contain types to do something with those
15/// types, similar to Chalk's `Fold` trait. 12/// types, similar to Chalk's `Fold` trait.
16pub trait TypeWalk { 13pub trait TypeWalk {
17 fn walk(&self, f: &mut impl FnMut(&Ty)); 14 fn walk(&self, f: &mut impl FnMut(&Ty));
18 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
19 self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST);
20 }
21 /// Walk the type, counting entered binders.
22 ///
23 /// `TyKind::Bound` variables use DeBruijn indexing, which means that 0 refers
24 /// to the innermost binder, 1 to the next, etc.. So when we want to
25 /// substitute a certain bound variable, we can't just walk the whole type
26 /// and blindly replace each instance of a certain index; when we 'enter'
27 /// things that introduce new bound variables, we have to keep track of
28 /// that. Currently, the only thing that introduces bound variables on our
29 /// side are `TyKind::Dyn` and `TyKind::Opaque`, which each introduce a bound
30 /// variable for the self type.
31 fn walk_mut_binders(
32 &mut self,
33 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
34 binders: DebruijnIndex,
35 );
36
37 fn fold_binders(
38 mut self,
39 f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty,
40 binders: DebruijnIndex,
41 ) -> Self
42 where
43 Self: Sized,
44 {
45 self.walk_mut_binders(
46 &mut |ty_mut, binders| {
47 let ty = mem::replace(ty_mut, TyKind::Error.intern(&Interner));
48 *ty_mut = f(ty, binders);
49 },
50 binders,
51 );
52 self
53 }
54
55 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
56 where
57 Self: Sized,
58 {
59 self.walk_mut(&mut |ty_mut| {
60 let ty = mem::replace(ty_mut, TyKind::Error.intern(&Interner));
61 *ty_mut = f(ty);
62 });
63 self
64 }
65
66 /// Substitutes `TyKind::Bound` vars with the given substitution.
67 fn subst_bound_vars(self, substs: &Substitution) -> Self
68 where
69 Self: Sized,
70 {
71 self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST)
72 }
73
74 /// Substitutes `TyKind::Bound` vars with the given substitution.
75 fn subst_bound_vars_at_depth(mut self, substs: &Substitution, depth: DebruijnIndex) -> Self
76 where
77 Self: Sized,
78 {
79 self.walk_mut_binders(
80 &mut |ty, binders| {
81 if let &mut TyKind::BoundVar(bound) = ty.interned_mut() {
82 if bound.debruijn >= binders {
83 *ty = substs.interned()[bound.index]
84 .assert_ty_ref(&Interner)
85 .clone()
86 .shifted_in_from(binders);
87 }
88 }
89 },
90 depth,
91 );
92 self
93 }
94
95 fn shifted_in(self, _interner: &Interner) -> Self
96 where
97 Self: Sized,
98 {
99 self.shifted_in_from(DebruijnIndex::ONE)
100 }
101
102 /// Shifts up debruijn indices of `TyKind::Bound` vars by `n`.
103 fn shifted_in_from(self, n: DebruijnIndex) -> Self
104 where
105 Self: Sized,
106 {
107 self.fold_binders(
108 &mut |ty, binders| match ty.kind(&Interner) {
109 TyKind::BoundVar(bound) if bound.debruijn >= binders => {
110 TyKind::BoundVar(bound.shifted_in_from(n)).intern(&Interner)
111 }
112 _ => ty,
113 },
114 DebruijnIndex::INNERMOST,
115 )
116 }
117
118 /// Shifts debruijn indices of `TyKind::Bound` vars out (down) by `n`.
119 fn shifted_out_to(self, n: DebruijnIndex) -> Option<Self>
120 where
121 Self: Sized + std::fmt::Debug,
122 {
123 Some(self.fold_binders(
124 &mut |ty, binders| {
125 match ty.kind(&Interner) {
126 TyKind::BoundVar(bound) if bound.debruijn >= binders => {
127 TyKind::BoundVar(bound.shifted_out_to(n).unwrap_or(bound.clone()))
128 .intern(&Interner)
129 }
130 _ => ty,
131 }
132 },
133 DebruijnIndex::INNERMOST,
134 ))
135 }
136} 15}
137 16
138impl TypeWalk for Ty { 17impl TypeWalk for Ty {
@@ -174,45 +53,6 @@ impl TypeWalk for Ty {
174 } 53 }
175 f(self); 54 f(self);
176 } 55 }
177
178 fn walk_mut_binders(
179 &mut self,
180 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
181 binders: DebruijnIndex,
182 ) {
183 match self.interned_mut() {
184 TyKind::Alias(AliasTy::Projection(p_ty)) => {
185 p_ty.substitution.walk_mut_binders(f, binders);
186 }
187 TyKind::Dyn(dyn_ty) => {
188 for p in make_mut_slice(dyn_ty.bounds.skip_binders_mut().interned_mut()) {
189 p.walk_mut_binders(f, binders.shifted_in());
190 }
191 }
192 TyKind::Alias(AliasTy::Opaque(o_ty)) => {
193 o_ty.substitution.walk_mut_binders(f, binders);
194 }
195 TyKind::Slice(ty)
196 | TyKind::Array(ty, _)
197 | TyKind::Ref(_, _, ty)
198 | TyKind::Raw(_, ty) => {
199 ty.walk_mut_binders(f, binders);
200 }
201 TyKind::Function(fn_pointer) => {
202 fn_pointer.substitution.0.walk_mut_binders(f, binders.shifted_in());
203 }
204 TyKind::Adt(_, substs)
205 | TyKind::FnDef(_, substs)
206 | TyKind::Tuple(_, substs)
207 | TyKind::OpaqueType(_, substs)
208 | TyKind::AssociatedType(_, substs)
209 | TyKind::Closure(.., substs) => {
210 substs.walk_mut_binders(f, binders);
211 }
212 _ => {}
213 }
214 f(self, binders);
215 }
216} 56}
217 57
218impl<T: TypeWalk> TypeWalk for Vec<T> { 58impl<T: TypeWalk> TypeWalk for Vec<T> {
@@ -221,43 +61,18 @@ impl<T: TypeWalk> TypeWalk for Vec<T> {
221 t.walk(f); 61 t.walk(f);
222 } 62 }
223 } 63 }
224 fn walk_mut_binders(
225 &mut self,
226 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
227 binders: DebruijnIndex,
228 ) {
229 for t in self {
230 t.walk_mut_binders(f, binders);
231 }
232 }
233} 64}
234 65
235impl TypeWalk for OpaqueTy { 66impl TypeWalk for OpaqueTy {
236 fn walk(&self, f: &mut impl FnMut(&Ty)) { 67 fn walk(&self, f: &mut impl FnMut(&Ty)) {
237 self.substitution.walk(f); 68 self.substitution.walk(f);
238 } 69 }
239
240 fn walk_mut_binders(
241 &mut self,
242 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
243 binders: DebruijnIndex,
244 ) {
245 self.substitution.walk_mut_binders(f, binders);
246 }
247} 70}
248 71
249impl TypeWalk for ProjectionTy { 72impl TypeWalk for ProjectionTy {
250 fn walk(&self, f: &mut impl FnMut(&Ty)) { 73 fn walk(&self, f: &mut impl FnMut(&Ty)) {
251 self.substitution.walk(f); 74 self.substitution.walk(f);
252 } 75 }
253
254 fn walk_mut_binders(
255 &mut self,
256 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
257 binders: DebruijnIndex,
258 ) {
259 self.substitution.walk_mut_binders(f, binders);
260 }
261} 76}
262 77
263impl TypeWalk for AliasTy { 78impl TypeWalk for AliasTy {
@@ -267,17 +82,6 @@ impl TypeWalk for AliasTy {
267 AliasTy::Opaque(it) => it.walk(f), 82 AliasTy::Opaque(it) => it.walk(f),
268 } 83 }
269 } 84 }
270
271 fn walk_mut_binders(
272 &mut self,
273 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
274 binders: DebruijnIndex,
275 ) {
276 match self {
277 AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
278 AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
279 }
280 }
281} 85}
282 86
283impl TypeWalk for GenericArg { 87impl TypeWalk for GenericArg {
@@ -286,18 +90,7 @@ impl TypeWalk for GenericArg {
286 GenericArgData::Ty(ty) => { 90 GenericArgData::Ty(ty) => {
287 ty.walk(f); 91 ty.walk(f);
288 } 92 }
289 } 93 _ => {}
290 }
291
292 fn walk_mut_binders(
293 &mut self,
294 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
295 binders: DebruijnIndex,
296 ) {
297 match self.interned_mut() {
298 GenericArgData::Ty(ty) => {
299 ty.walk_mut_binders(f, binders);
300 }
301 } 94 }
302 } 95 }
303} 96}
@@ -308,44 +101,18 @@ impl TypeWalk for Substitution {
308 t.walk(f); 101 t.walk(f);
309 } 102 }
310 } 103 }
311
312 fn walk_mut_binders(
313 &mut self,
314 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
315 binders: DebruijnIndex,
316 ) {
317 for t in self.interned_mut() {
318 t.walk_mut_binders(f, binders);
319 }
320 }
321} 104}
322 105
323impl<T: TypeWalk> TypeWalk for Binders<T> { 106impl<T: TypeWalk + HasInterner<Interner = Interner>> TypeWalk for Binders<T> {
324 fn walk(&self, f: &mut impl FnMut(&Ty)) { 107 fn walk(&self, f: &mut impl FnMut(&Ty)) {
325 self.skip_binders().walk(f); 108 self.skip_binders().walk(f);
326 } 109 }
327
328 fn walk_mut_binders(
329 &mut self,
330 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
331 binders: DebruijnIndex,
332 ) {
333 self.skip_binders_mut().walk_mut_binders(f, binders.shifted_in())
334 }
335} 110}
336 111
337impl TypeWalk for TraitRef { 112impl TypeWalk for TraitRef {
338 fn walk(&self, f: &mut impl FnMut(&Ty)) { 113 fn walk(&self, f: &mut impl FnMut(&Ty)) {
339 self.substitution.walk(f); 114 self.substitution.walk(f);
340 } 115 }
341
342 fn walk_mut_binders(
343 &mut self,
344 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
345 binders: DebruijnIndex,
346 ) {
347 self.substitution.walk_mut_binders(f, binders);
348 }
349} 116}
350 117
351impl TypeWalk for WhereClause { 118impl TypeWalk for WhereClause {
@@ -353,17 +120,7 @@ impl TypeWalk for WhereClause {
353 match self { 120 match self {
354 WhereClause::Implemented(trait_ref) => trait_ref.walk(f), 121 WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
355 WhereClause::AliasEq(alias_eq) => alias_eq.walk(f), 122 WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
356 } 123 _ => {}
357 }
358
359 fn walk_mut_binders(
360 &mut self,
361 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
362 binders: DebruijnIndex,
363 ) {
364 match self {
365 WhereClause::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
366 WhereClause::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
367 } 124 }
368 } 125 }
369} 126}
@@ -374,16 +131,6 @@ impl TypeWalk for CallableSig {
374 t.walk(f); 131 t.walk(f);
375 } 132 }
376 } 133 }
377
378 fn walk_mut_binders(
379 &mut self,
380 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
381 binders: DebruijnIndex,
382 ) {
383 for t in make_mut_slice(&mut self.params_and_return) {
384 t.walk_mut_binders(f, binders);
385 }
386 }
387} 134}
388 135
389impl TypeWalk for AliasEq { 136impl TypeWalk for AliasEq {
@@ -394,30 +141,10 @@ impl TypeWalk for AliasEq {
394 AliasTy::Opaque(opaque) => opaque.walk(f), 141 AliasTy::Opaque(opaque) => opaque.walk(f),
395 } 142 }
396 } 143 }
397
398 fn walk_mut_binders(
399 &mut self,
400 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
401 binders: DebruijnIndex,
402 ) {
403 self.ty.walk_mut_binders(f, binders);
404 match &mut self.alias {
405 AliasTy::Projection(projection_ty) => projection_ty.walk_mut_binders(f, binders),
406 AliasTy::Opaque(opaque) => opaque.walk_mut_binders(f, binders),
407 }
408 }
409} 144}
410 145
411impl TypeWalk for FnSubst { 146impl TypeWalk for FnSubst<Interner> {
412 fn walk(&self, f: &mut impl FnMut(&Ty)) { 147 fn walk(&self, f: &mut impl FnMut(&Ty)) {
413 self.0.walk(f) 148 self.0.walk(f)
414 } 149 }
415
416 fn walk_mut_binders(
417 &mut self,
418 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
419 binders: DebruijnIndex,
420 ) {
421 self.0.walk_mut_binders(f, binders)
422 }
423} 150}
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index dd42116a7..0ace80a1e 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -20,7 +20,7 @@ use itertools::Itertools;
20use rustc_hash::FxHashSet; 20use rustc_hash::FxHashSet;
21use syntax::{ 21use syntax::{
22 ast::{self, AstNode}, 22 ast::{self, AstNode},
23 SyntaxNode, SyntaxNodePtr, TextRange, 23 SyntaxNode, SyntaxNodePtr, TextRange, TextSize,
24}; 24};
25use text_edit::TextEdit; 25use text_edit::TextEdit;
26use unlinked_file::UnlinkedFile; 26use unlinked_file::UnlinkedFile;
@@ -159,14 +159,16 @@ pub(crate) fn diagnostics(
159 ); 159 );
160 }) 160 })
161 .on::<UnlinkedFile, _>(|d| { 161 .on::<UnlinkedFile, _>(|d| {
162 // Limit diagnostic to the first few characters in the file. This matches how VS Code
163 // renders it with the full span, but on other editors, and is less invasive.
164 let range = sema.diagnostics_display_range(d.display_source()).range;
165 let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range);
166
162 // Override severity and mark as unused. 167 // Override severity and mark as unused.
163 res.borrow_mut().push( 168 res.borrow_mut().push(
164 Diagnostic::hint( 169 Diagnostic::hint(range, d.message())
165 sema.diagnostics_display_range(d.display_source()).range, 170 .with_fix(d.fix(&sema))
166 d.message(), 171 .with_code(Some(d.code())),
167 )
168 .with_fix(d.fix(&sema))
169 .with_code(Some(d.code())),
170 ); 172 );
171 }) 173 })
172 .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| { 174 .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| {
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index d5628e3df..be0ee03bf 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -1,3 +1,5 @@
1use std::iter;
2
1use hir::Semantics; 3use hir::Semantics;
2use ide_db::RootDatabase; 4use ide_db::RootDatabase;
3use syntax::{ 5use syntax::{
@@ -91,27 +93,42 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
91 let is_last = 93 let is_last =
92 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) }; 94 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
93 95
94 res += &match token.kind() { 96 match token.kind() {
95 k if is_text(k) && is_next(|it| !it.is_punct(), true) => token.text().to_string() + " ", 97 k if is_text(k) && is_next(|it| !it.is_punct(), true) => {
98 res.push_str(token.text());
99 res.push(' ');
100 }
96 L_CURLY if is_next(|it| it != R_CURLY, true) => { 101 L_CURLY if is_next(|it| it != R_CURLY, true) => {
97 indent += 1; 102 indent += 1;
98 let leading_space = if is_last(is_text, false) { " " } else { "" }; 103 if is_last(is_text, false) {
99 format!("{}{{\n{}", leading_space, " ".repeat(indent)) 104 res.push(' ');
105 }
106 res.push_str("{\n");
107 res.extend(iter::repeat(" ").take(2 * indent));
100 } 108 }
101 R_CURLY if is_last(|it| it != L_CURLY, true) => { 109 R_CURLY if is_last(|it| it != L_CURLY, true) => {
102 indent = indent.saturating_sub(1); 110 indent = indent.saturating_sub(1);
103 format!("\n{}}}", " ".repeat(indent)) 111 res.push('\n');
112 res.extend(iter::repeat(" ").take(2 * indent));
113 res.push_str("}");
114 }
115 R_CURLY => {
116 res.push_str("}\n");
117 res.extend(iter::repeat(" ").take(2 * indent));
104 } 118 }
105 R_CURLY => format!("}}\n{}", " ".repeat(indent)),
106 LIFETIME_IDENT if is_next(|it| it == IDENT, true) => { 119 LIFETIME_IDENT if is_next(|it| it == IDENT, true) => {
107 format!("{} ", token.text().to_string()) 120 res.push_str(token.text());
121 res.push(' ');
108 } 122 }
109 T![;] => format!(";\n{}", " ".repeat(indent)), 123 T![;] => {
110 T![->] => " -> ".to_string(), 124 res.push_str(";\n");
111 T![=] => " = ".to_string(), 125 res.extend(iter::repeat(" ").take(2 * indent));
112 T![=>] => " => ".to_string(), 126 }
113 _ => token.text().to_string(), 127 T![->] => res.push_str(" -> "),
114 }; 128 T![=] => res.push_str(" = "),
129 T![=>] => res.push_str(" => "),
130 _ => res.push_str(token.text()),
131 }
115 132
116 last = Some(token.kind()); 133 last = Some(token.kind());
117 } 134 }
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 153726ce8..2b9ed123c 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -19,6 +19,7 @@ pub enum FoldKind {
19 Region, 19 Region,
20 Consts, 20 Consts,
21 Statics, 21 Statics,
22 Array,
22} 23}
23 24
24#[derive(Debug)] 25#[derive(Debug)]
@@ -119,6 +120,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
119 match kind { 120 match kind {
120 COMMENT => Some(FoldKind::Comment), 121 COMMENT => Some(FoldKind::Comment),
121 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), 122 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
123 ARRAY_EXPR => Some(FoldKind::Array),
122 ASSOC_ITEM_LIST 124 ASSOC_ITEM_LIST
123 | RECORD_FIELD_LIST 125 | RECORD_FIELD_LIST
124 | RECORD_PAT_FIELD_LIST 126 | RECORD_PAT_FIELD_LIST
@@ -269,6 +271,7 @@ mod tests {
269 FoldKind::Region => "region", 271 FoldKind::Region => "region",
270 FoldKind::Consts => "consts", 272 FoldKind::Consts => "consts",
271 FoldKind::Statics => "statics", 273 FoldKind::Statics => "statics",
274 FoldKind::Array => "array",
272 }; 275 };
273 assert_eq!(kind, &attr.unwrap()); 276 assert_eq!(kind, &attr.unwrap());
274 } 277 }
@@ -465,6 +468,20 @@ fn foo<fold arglist>(
465 } 468 }
466 469
467 #[test] 470 #[test]
471 fn fold_multiline_array() {
472 check(
473 r#"
474const FOO: [usize; 4] = <fold array>[
475 1,
476 2,
477 3,
478 4,
479]</fold>;
480"#,
481 )
482 }
483
484 #[test]
468 fn fold_region() { 485 fn fold_region() {
469 check( 486 check(
470 r#" 487 r#"
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 5ccb84714..e921784bf 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -323,8 +323,18 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
323 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), 323 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait),
324 hir::ModuleDef::TypeAlias(type_) => { 324 hir::ModuleDef::TypeAlias(type_) => {
325 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); 325 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
326 if type_.as_assoc_item(db).is_some() { 326 if let Some(item) = type_.as_assoc_item(db) {
327 h |= HlMod::Associated 327 h |= HlMod::Associated;
328 match item.container(db) {
329 AssocItemContainer::Impl(i) => {
330 if i.trait_(db).is_some() {
331 h |= HlMod::Trait;
332 }
333 }
334 AssocItemContainer::Trait(_t) => {
335 h |= HlMod::Trait;
336 }
337 }
328 } 338 }
329 return h; 339 return h;
330 } 340 }
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 1b02857ec..de2d22ac7 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,5 +1,8 @@
1use std::time::Instant;
2
1use expect_test::{expect_file, ExpectFile}; 3use expect_test::{expect_file, ExpectFile};
2use ide_db::SymbolKind; 4use ide_db::SymbolKind;
5use stdx::format_to;
3use test_utils::{bench, bench_fixture, skip_slow_tests}; 6use test_utils::{bench, bench_fixture, skip_slow_tests};
4 7
5use crate::{fixture, FileRange, HlTag, TextRange}; 8use crate::{fixture, FileRange, HlTag, TextRange};
@@ -258,6 +261,99 @@ fn benchmark_syntax_highlighting_long_struct() {
258} 261}
259 262
260#[test] 263#[test]
264fn syntax_highlighting_not_quadratic() {
265 if skip_slow_tests() {
266 return;
267 }
268
269 let mut measures = Vec::new();
270 for i in 6..=10 {
271 let n = 1 << i;
272 let fixture = bench_fixture::big_struct_n(n);
273 let (analysis, file_id) = fixture::file(&fixture);
274
275 let time = Instant::now();
276
277 let hash = analysis
278 .highlight(file_id)
279 .unwrap()
280 .iter()
281 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
282 .count();
283 assert!(hash > n as usize);
284
285 let elapsed = time.elapsed();
286 measures.push((n as f64, elapsed.as_millis() as f64))
287 }
288
289 assert_linear(&measures)
290}
291
292/// Checks that a set of measurements looks like a liner function rather than
293/// like a quadratic function. Algorithm:
294///
295/// 1. Linearly scale input to be in [0; 1)
296/// 2. Using linear regression, compute the best linear function approximating
297/// the input.
298/// 3. Compute RMSE and maximal absolute error.
299/// 4. Check that errors are within tolerances and that the constant term is not
300/// too negative.
301///
302/// Ideally, we should use a proper "model selection" to directly compare
303/// quadratic and linear models, but that sounds rather complicated:
304///
305/// https://stats.stackexchange.com/questions/21844/selecting-best-model-based-on-linear-quadratic-and-cubic-fit-of-data
306fn assert_linear(xy: &[(f64, f64)]) {
307 let (mut xs, mut ys): (Vec<_>, Vec<_>) = xy.iter().copied().unzip();
308 normalize(&mut xs);
309 normalize(&mut ys);
310 let xy = xs.iter().copied().zip(ys.iter().copied());
311
312 // Linear regression: finding a and b to fit y = a + b*x.
313
314 let mean_x = mean(&xs);
315 let mean_y = mean(&ys);
316
317 let b = {
318 let mut num = 0.0;
319 let mut denom = 0.0;
320 for (x, y) in xy.clone() {
321 num += (x - mean_x) * (y - mean_y);
322 denom += (x - mean_x).powi(2);
323 }
324 num / denom
325 };
326
327 let a = mean_y - b * mean_x;
328
329 let mut plot = format!("y_pred = {:.3} + {:.3} * x\n\nx y y_pred\n", a, b);
330
331 let mut se = 0.0;
332 let mut max_error = 0.0f64;
333 for (x, y) in xy {
334 let y_pred = a + b * x;
335 se += (y - y_pred).powi(2);
336 max_error = max_error.max((y_pred - y).abs());
337
338 format_to!(plot, "{:.3} {:.3} {:.3}\n", x, y, y_pred);
339 }
340
341 let rmse = (se / xs.len() as f64).sqrt();
342 format_to!(plot, "\nrmse = {:.3} max error = {:.3}", rmse, max_error);
343
344 assert!(rmse < 0.05 && max_error < 0.1 && a > -0.1, "\nLooks quadratic\n{}", plot);
345
346 fn normalize(xs: &mut Vec<f64>) {
347 let max = xs.iter().copied().max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap();
348 xs.iter_mut().for_each(|it| *it /= max);
349 }
350
351 fn mean(xs: &[f64]) -> f64 {
352 xs.iter().copied().sum::<f64>() / (xs.len() as f64)
353 }
354}
355
356#[test]
261fn benchmark_syntax_highlighting_parser() { 357fn benchmark_syntax_highlighting_parser() {
262 if skip_slow_tests() { 358 if skip_slow_tests() {
263 return; 359 return;
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs
index 9144681bf..6f1ce3689 100644
--- a/crates/ide/src/typing/on_enter.rs
+++ b/crates/ide/src/typing/on_enter.rs
@@ -18,6 +18,7 @@ use text_edit::TextEdit;
18// 18//
19// - kbd:[Enter] inside triple-slash comments automatically inserts `///` 19// - kbd:[Enter] inside triple-slash comments automatically inserts `///`
20// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//` 20// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//`
21// - kbd:[Enter] inside `//!` doc comments automatically inserts `//!`
21// 22//
22// This action needs to be assigned to shortcut explicitly. 23// This action needs to be assigned to shortcut explicitly.
23// 24//
@@ -187,6 +188,25 @@ fn foo() {
187 } 188 }
188 189
189 #[test] 190 #[test]
191 fn continues_another_doc_comment() {
192 do_check(
193 r#"
194fn main() {
195 //! Documentation for$0 on enter
196 let x = 1 + 1;
197}
198"#,
199 r#"
200fn main() {
201 //! Documentation for
202 //! $0 on enter
203 let x = 1 + 1;
204}
205"#,
206 );
207 }
208
209 #[test]
190 fn continues_code_comment_in_the_middle_of_line() { 210 fn continues_code_comment_in_the_middle_of_line() {
191 do_check( 211 do_check(
192 r" 212 r"
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs
index 6114091f2..c8226550f 100644
--- a/crates/ide_assists/src/handlers/remove_dbg.rs
+++ b/crates/ide_assists/src/handlers/remove_dbg.rs
@@ -1,5 +1,5 @@
1use syntax::{ 1use syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode, AstToken},
3 match_ast, SyntaxElement, TextRange, TextSize, T, 3 match_ast, SyntaxElement, TextRange, TextSize, T,
4}; 4};
5 5
@@ -24,7 +24,39 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; 24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
25 let new_contents = adjusted_macro_contents(&macro_call)?; 25 let new_contents = adjusted_macro_contents(&macro_call)?;
26 26
27 let macro_text_range = macro_call.syntax().text_range(); 27 let parent = macro_call.syntax().parent();
28
29 let macro_text_range = if let Some(it) = parent.as_ref() {
30 if new_contents.is_empty() {
31 match_ast! {
32 match it {
33 ast::BlockExpr(_it) => {
34 macro_call.syntax()
35 .prev_sibling_or_token()
36 .and_then(whitespace_start)
37 .map(|start| TextRange::new(start, macro_call.syntax().text_range().end()))
38 .unwrap_or(macro_call.syntax().text_range())
39 },
40 ast::ExprStmt(it) => {
41 let start = it
42 .syntax()
43 .prev_sibling_or_token()
44 .and_then(whitespace_start)
45 .unwrap_or(it.syntax().text_range().start());
46 let end = it.syntax().text_range().end();
47
48 TextRange::new(start, end)
49 },
50 _ => macro_call.syntax().text_range()
51 }
52 }
53 } else {
54 macro_call.syntax().text_range()
55 }
56 } else {
57 macro_call.syntax().text_range()
58 };
59
28 let macro_end = if macro_call.semicolon_token().is_some() { 60 let macro_end = if macro_call.semicolon_token().is_some() {
29 macro_text_range.end() - TextSize::of(';') 61 macro_text_range.end() - TextSize::of(';')
30 } else { 62 } else {
@@ -36,11 +68,22 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36 "Remove dbg!()", 68 "Remove dbg!()",
37 macro_text_range, 69 macro_text_range,
38 |builder| { 70 |builder| {
39 builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents); 71 builder.replace(
72 TextRange::new(macro_text_range.start(), macro_end),
73 if new_contents.is_empty() && parent.and_then(ast::LetStmt::cast).is_some() {
74 ast::make::expr_unit().to_string()
75 } else {
76 new_contents
77 },
78 );
40 }, 79 },
41 ) 80 )
42} 81}
43 82
83fn whitespace_start(it: SyntaxElement) -> Option<TextSize> {
84 Some(it.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start())
85}
86
44fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { 87fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> {
45 let contents = get_valid_macrocall_contents(&macro_call, "dbg")?; 88 let contents = get_valid_macrocall_contents(&macro_call, "dbg")?;
46 let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); 89 let macro_text_with_brackets = macro_call.token_tree()?.syntax().text();
@@ -94,15 +137,11 @@ fn get_valid_macrocall_contents(
94 let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>(); 137 let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>();
95 let last_child = contents_between_brackets.pop()?; 138 let last_child = contents_between_brackets.pop()?;
96 139
97 if contents_between_brackets.is_empty() { 140 match (first_child.kind(), last_child.kind()) {
98 None 141 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
99 } else { 142 Some(contents_between_brackets)
100 match (first_child.kind(), last_child.kind()) {
101 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
102 Some(contents_between_brackets)
103 }
104 _ => None,
105 } 143 }
144 _ => None,
106 } 145 }
107} 146}
108 147
@@ -418,4 +457,48 @@ fn main() {
418}"#, 457}"#,
419 ); 458 );
420 } 459 }
460
461 #[test]
462 fn test_remove_empty_dbg() {
463 check_assist(remove_dbg, r#"fn foo() { $0dbg!(); }"#, r#"fn foo() { }"#);
464 check_assist(
465 remove_dbg,
466 r#"
467fn foo() {
468 $0dbg!();
469}
470"#,
471 r#"
472fn foo() {
473}
474"#,
475 );
476 check_assist(
477 remove_dbg,
478 r#"
479fn foo() {
480 let test = $0dbg!();
481}"#,
482 r#"
483fn foo() {
484 let test = ();
485}"#,
486 );
487 check_assist(
488 remove_dbg,
489 r#"
490fn foo() {
491 let t = {
492 println!("Hello, world");
493 $0dbg!()
494 };
495}"#,
496 r#"
497fn foo() {
498 let t = {
499 println!("Hello, world");
500 };
501}"#,
502 );
503 }
421} 504}
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 3130785cc..0571a912c 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -22,7 +22,7 @@ env_logger = { version = "0.8.1", default-features = false }
22itertools = "0.10.0" 22itertools = "0.10.0"
23jod-thread = "0.1.0" 23jod-thread = "0.1.0"
24log = "0.4.8" 24log = "0.4.8"
25lsp-types = { version = "0.88.0", features = ["proposed"] } 25lsp-types = { version = "0.89.0", features = ["proposed"] }
26parking_lot = "0.11.0" 26parking_lot = "0.11.0"
27xflags = "0.2.1" 27xflags = "0.2.1"
28oorandom = "11.1.2" 28oorandom = "11.1.2"
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index d5c0d22b8..9fac562ff 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -515,7 +515,8 @@ pub(crate) fn folding_range(
515 | FoldKind::Block 515 | FoldKind::Block
516 | FoldKind::ArgList 516 | FoldKind::ArgList
517 | FoldKind::Consts 517 | FoldKind::Consts
518 | FoldKind::Statics => None, 518 | FoldKind::Statics
519 | FoldKind::Array => None,
519 }; 520 };
520 521
521 let range = range(line_index, fold.range); 522 let range = range(line_index, fold.range);
diff --git a/crates/test_utils/src/bench_fixture.rs b/crates/test_utils/src/bench_fixture.rs
index 3a37c4473..979156263 100644
--- a/crates/test_utils/src/bench_fixture.rs
+++ b/crates/test_utils/src/bench_fixture.rs
@@ -8,7 +8,10 @@ use crate::project_root;
8 8
9pub fn big_struct() -> String { 9pub fn big_struct() -> String {
10 let n = 1_000; 10 let n = 1_000;
11 big_struct_n(n)
12}
11 13
14pub fn big_struct_n(n: u32) -> String {
12 let mut buf = "pub struct RegisterBlock {".to_string(); 15 let mut buf = "pub struct RegisterBlock {".to_string();
13 for i in 0..n { 16 for i in 0..n {
14 format_to!(buf, " /// Doc comment for {}.\n", i); 17 format_to!(buf, " /// Doc comment for {}.\n", i);