aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty')
-rw-r--r--crates/ra_hir_ty/Cargo.toml6
-rw-r--r--crates/ra_hir_ty/src/_match.rs336
-rw-r--r--crates/ra_hir_ty/src/db.rs7
-rw-r--r--crates/ra_hir_ty/src/infer.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs6
-rw-r--r--crates/ra_hir_ty/src/lib.rs2
-rw-r--r--crates/ra_hir_ty/src/test_db.rs36
-rw-r--r--crates/ra_hir_ty/src/tests.rs52
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs26
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs41
-rw-r--r--crates/ra_hir_ty/src/traits.rs2
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs145
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs33
13 files changed, 605 insertions, 91 deletions
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 177bdbcb0..04d3cd6a2 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -27,9 +27,9 @@ test_utils = { path = "../test_utils" }
27 27
28scoped-tls = "1" 28scoped-tls = "1"
29 29
30chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "28cef6ff403d403e6ad2f3d27d944e9ffac1bce8" } 30chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" }
31chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "28cef6ff403d403e6ad2f3d27d944e9ffac1bce8" } 31chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" }
32chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "28cef6ff403d403e6ad2f3d27d944e9ffac1bce8" } 32chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "2c072cc830d04af5f10b390e6643327f85108282" }
33 33
34[dev-dependencies] 34[dev-dependencies]
35insta = "0.16.0" 35insta = "0.16.0"
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index 688026a04..779e78574 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -235,10 +235,19 @@ impl From<PatId> for PatIdOrWild {
235 } 235 }
236} 236}
237 237
238impl From<&PatId> for PatIdOrWild {
239 fn from(pat_id: &PatId) -> Self {
240 Self::PatId(*pat_id)
241 }
242}
243
238#[derive(Debug, Clone, Copy, PartialEq)] 244#[derive(Debug, Clone, Copy, PartialEq)]
239pub enum MatchCheckErr { 245pub enum MatchCheckErr {
240 NotImplemented, 246 NotImplemented,
241 MalformedMatchArm, 247 MalformedMatchArm,
248 /// Used when type inference cannot resolve the type of
249 /// a pattern or expression.
250 Unknown,
242} 251}
243 252
244/// The return type of `is_useful` is either an indication of usefulness 253/// The return type of `is_useful` is either an indication of usefulness
@@ -290,10 +299,14 @@ impl PatStack {
290 Self::from_slice(&self.0[1..]) 299 Self::from_slice(&self.0[1..])
291 } 300 }
292 301
293 fn replace_head_with<T: Into<PatIdOrWild> + Copy>(&self, pat_ids: &[T]) -> PatStack { 302 fn replace_head_with<I, T>(&self, pats: I) -> PatStack
303 where
304 I: Iterator<Item = T>,
305 T: Into<PatIdOrWild>,
306 {
294 let mut patterns: PatStackInner = smallvec![]; 307 let mut patterns: PatStackInner = smallvec![];
295 for pat in pat_ids { 308 for pat in pats {
296 patterns.push((*pat).into()); 309 patterns.push(pat.into());
297 } 310 }
298 for pat in &self.0[1..] { 311 for pat in &self.0[1..] {
299 patterns.push(*pat); 312 patterns.push(*pat);
@@ -330,7 +343,7 @@ impl PatStack {
330 return Err(MatchCheckErr::NotImplemented); 343 return Err(MatchCheckErr::NotImplemented);
331 } 344 }
332 345
333 Some(self.replace_head_with(pat_ids)) 346 Some(self.replace_head_with(pat_ids.iter()))
334 } 347 }
335 (Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => { 348 (Pat::Lit(lit_expr), Constructor::Bool(constructor_val)) => {
336 match cx.body.exprs[lit_expr] { 349 match cx.body.exprs[lit_expr] {
@@ -382,7 +395,7 @@ impl PatStack {
382 new_patterns.push((*pat_id).into()); 395 new_patterns.push((*pat_id).into());
383 } 396 }
384 397
385 Some(self.replace_head_with(&new_patterns)) 398 Some(self.replace_head_with(new_patterns.into_iter()))
386 } else { 399 } else {
387 return Err(MatchCheckErr::MalformedMatchArm); 400 return Err(MatchCheckErr::MalformedMatchArm);
388 } 401 }
@@ -390,13 +403,41 @@ impl PatStack {
390 // If there is no ellipsis in the tuple pattern, the number 403 // If there is no ellipsis in the tuple pattern, the number
391 // of patterns must equal the constructor arity. 404 // of patterns must equal the constructor arity.
392 if pat_ids.len() == constructor_arity { 405 if pat_ids.len() == constructor_arity {
393 Some(self.replace_head_with(pat_ids)) 406 Some(self.replace_head_with(pat_ids.into_iter()))
394 } else { 407 } else {
395 return Err(MatchCheckErr::MalformedMatchArm); 408 return Err(MatchCheckErr::MalformedMatchArm);
396 } 409 }
397 } 410 }
398 } 411 }
399 } 412 }
413 (Pat::Record { args: ref arg_patterns, .. }, Constructor::Enum(e)) => {
414 let pat_id = self.head().as_id().expect("we know this isn't a wild");
415 if !enum_variant_matches(cx, pat_id, *e) {
416 None
417 } else {
418 match cx.db.enum_data(e.parent).variants[e.local_id].variant_data.as_ref() {
419 VariantData::Record(struct_field_arena) => {
420 // Here we treat any missing fields in the record as the wild pattern, as
421 // if the record has ellipsis. We want to do this here even if the
422 // record does not contain ellipsis, because it allows us to continue
423 // enforcing exhaustiveness for the rest of the match statement.
424 //
425 // Creating the diagnostic for the missing field in the pattern
426 // should be done in a different diagnostic.
427 let patterns = struct_field_arena.iter().map(|(_, struct_field)| {
428 arg_patterns
429 .iter()
430 .find(|pat| pat.name == struct_field.name)
431 .map(|pat| PatIdOrWild::from(pat.pat))
432 .unwrap_or(PatIdOrWild::Wild)
433 });
434
435 Some(self.replace_head_with(patterns))
436 }
437 _ => return Err(MatchCheckErr::Unknown),
438 }
439 }
440 }
400 (Pat::Or(_), _) => return Err(MatchCheckErr::NotImplemented), 441 (Pat::Or(_), _) => return Err(MatchCheckErr::NotImplemented),
401 (_, _) => return Err(MatchCheckErr::NotImplemented), 442 (_, _) => return Err(MatchCheckErr::NotImplemented),
402 }; 443 };
@@ -655,8 +696,8 @@ impl Constructor {
655 Constructor::Enum(e) => { 696 Constructor::Enum(e) => {
656 match cx.db.enum_data(e.parent).variants[e.local_id].variant_data.as_ref() { 697 match cx.db.enum_data(e.parent).variants[e.local_id].variant_data.as_ref() {
657 VariantData::Tuple(struct_field_data) => struct_field_data.len(), 698 VariantData::Tuple(struct_field_data) => struct_field_data.len(),
699 VariantData::Record(struct_field_data) => struct_field_data.len(),
658 VariantData::Unit => 0, 700 VariantData::Unit => 0,
659 _ => return Err(MatchCheckErr::NotImplemented),
660 } 701 }
661 } 702 }
662 }; 703 };
@@ -695,10 +736,10 @@ fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Opt
695 Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)), 736 Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)),
696 _ => return Err(MatchCheckErr::NotImplemented), 737 _ => return Err(MatchCheckErr::NotImplemented),
697 }, 738 },
698 Pat::TupleStruct { .. } | Pat::Path(_) => { 739 Pat::TupleStruct { .. } | Pat::Path(_) | Pat::Record { .. } => {
699 let pat_id = pat.as_id().expect("we already know this pattern is not a wild"); 740 let pat_id = pat.as_id().expect("we already know this pattern is not a wild");
700 let variant_id = 741 let variant_id =
701 cx.infer.variant_resolution_for_pat(pat_id).ok_or(MatchCheckErr::NotImplemented)?; 742 cx.infer.variant_resolution_for_pat(pat_id).ok_or(MatchCheckErr::Unknown)?;
702 match variant_id { 743 match variant_id {
703 VariantId::EnumVariantId(enum_variant_id) => { 744 VariantId::EnumVariantId(enum_variant_id) => {
704 Some(Constructor::Enum(enum_variant_id)) 745 Some(Constructor::Enum(enum_variant_id))
@@ -759,20 +800,22 @@ mod tests {
759 pub(super) use insta::assert_snapshot; 800 pub(super) use insta::assert_snapshot;
760 pub(super) use ra_db::fixture::WithFixture; 801 pub(super) use ra_db::fixture::WithFixture;
761 802
762 pub(super) use crate::test_db::TestDB; 803 pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB};
763 804
764 pub(super) fn check_diagnostic_message(content: &str) -> String { 805 pub(super) fn check_diagnostic_message(content: &str) -> String {
765 TestDB::with_single_file(content).0.diagnostics().0 806 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().0
766 } 807 }
767 808
768 pub(super) fn check_diagnostic(content: &str) { 809 pub(super) fn check_diagnostic(content: &str) {
769 let diagnostic_count = TestDB::with_single_file(content).0.diagnostics().1; 810 let diagnostic_count =
811 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1;
770 812
771 assert_eq!(1, diagnostic_count, "no diagnostic reported"); 813 assert_eq!(1, diagnostic_count, "no diagnostic reported");
772 } 814 }
773 815
774 pub(super) fn check_no_diagnostic(content: &str) { 816 pub(super) fn check_no_diagnostic(content: &str) {
775 let diagnostic_count = TestDB::with_single_file(content).0.diagnostics().1; 817 let diagnostic_count =
818 TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1;
776 819
777 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one"); 820 assert_eq!(0, diagnostic_count, "expected no diagnostic, found one");
778 } 821 }
@@ -1532,6 +1575,236 @@ mod tests {
1532 } 1575 }
1533 1576
1534 #[test] 1577 #[test]
1578 fn enum_record_no_arms() {
1579 let content = r"
1580 enum Either {
1581 A { foo: bool },
1582 B,
1583 }
1584 fn test_fn() {
1585 let a = Either::A { foo: true };
1586 match a {
1587 }
1588 }
1589 ";
1590
1591 check_diagnostic(content);
1592 }
1593
1594 #[test]
1595 fn enum_record_missing_arms() {
1596 let content = r"
1597 enum Either {
1598 A { foo: bool },
1599 B,
1600 }
1601 fn test_fn() {
1602 let a = Either::A { foo: true };
1603 match a {
1604 Either::A { foo: true } => (),
1605 }
1606 }
1607 ";
1608
1609 check_diagnostic(content);
1610 }
1611
1612 #[test]
1613 fn enum_record_no_diagnostic() {
1614 let content = r"
1615 enum Either {
1616 A { foo: bool },
1617 B,
1618 }
1619 fn test_fn() {
1620 let a = Either::A { foo: true };
1621 match a {
1622 Either::A { foo: true } => (),
1623 Either::A { foo: false } => (),
1624 Either::B => (),
1625 }
1626 }
1627 ";
1628
1629 check_no_diagnostic(content);
1630 }
1631
1632 #[test]
1633 fn enum_record_missing_field_no_diagnostic() {
1634 let content = r"
1635 enum Either {
1636 A { foo: bool },
1637 B,
1638 }
1639 fn test_fn() {
1640 let a = Either::B;
1641 match a {
1642 Either::A { } => (),
1643 Either::B => (),
1644 }
1645 }
1646 ";
1647
1648 // When `Either::A` is missing a struct member, we don't want
1649 // to fire the missing match arm diagnostic. This should fire
1650 // some other diagnostic.
1651 check_no_diagnostic(content);
1652 }
1653
1654 #[test]
1655 fn enum_record_missing_field_missing_match_arm() {
1656 let content = r"
1657 enum Either {
1658 A { foo: bool },
1659 B,
1660 }
1661 fn test_fn() {
1662 let a = Either::B;
1663 match a {
1664 Either::A { } => (),
1665 }
1666 }
1667 ";
1668
1669 // Even though `Either::A` is missing fields, we still want to fire
1670 // the missing arm diagnostic here, since we know `Either::B` is missing.
1671 check_diagnostic(content);
1672 }
1673
1674 #[test]
1675 fn enum_record_no_diagnostic_wild() {
1676 let content = r"
1677 enum Either {
1678 A { foo: bool },
1679 B,
1680 }
1681 fn test_fn() {
1682 let a = Either::A { foo: true };
1683 match a {
1684 Either::A { foo: _ } => (),
1685 Either::B => (),
1686 }
1687 }
1688 ";
1689
1690 check_no_diagnostic(content);
1691 }
1692
1693 #[test]
1694 fn enum_record_fields_out_of_order_missing_arm() {
1695 let content = r"
1696 enum Either {
1697 A { foo: bool, bar: () },
1698 B,
1699 }
1700 fn test_fn() {
1701 let a = Either::A { foo: true };
1702 match a {
1703 Either::A { bar: (), foo: false } => (),
1704 Either::A { foo: true, bar: () } => (),
1705 }
1706 }
1707 ";
1708
1709 check_diagnostic(content);
1710 }
1711
1712 #[test]
1713 fn enum_record_fields_out_of_order_no_diagnostic() {
1714 let content = r"
1715 enum Either {
1716 A { foo: bool, bar: () },
1717 B,
1718 }
1719 fn test_fn() {
1720 let a = Either::A { foo: true };
1721 match a {
1722 Either::A { bar: (), foo: false } => (),
1723 Either::A { foo: true, bar: () } => (),
1724 Either::B => (),
1725 }
1726 }
1727 ";
1728
1729 check_no_diagnostic(content);
1730 }
1731
1732 #[test]
1733 fn enum_record_ellipsis_missing_arm() {
1734 let content = r"
1735 enum Either {
1736 A { foo: bool, bar: bool },
1737 B,
1738 }
1739 fn test_fn() {
1740 match Either::B {
1741 Either::A { foo: true, .. } => (),
1742 Either::B => (),
1743 }
1744 }
1745 ";
1746
1747 check_diagnostic(content);
1748 }
1749
1750 #[test]
1751 fn enum_record_ellipsis_no_diagnostic() {
1752 let content = r"
1753 enum Either {
1754 A { foo: bool, bar: bool },
1755 B,
1756 }
1757 fn test_fn() {
1758 let a = Either::A { foo: true };
1759 match a {
1760 Either::A { foo: true, .. } => (),
1761 Either::A { foo: false, .. } => (),
1762 Either::B => (),
1763 }
1764 }
1765 ";
1766
1767 check_no_diagnostic(content);
1768 }
1769
1770 #[test]
1771 fn enum_record_ellipsis_all_fields_missing_arm() {
1772 let content = r"
1773 enum Either {
1774 A { foo: bool, bar: bool },
1775 B,
1776 }
1777 fn test_fn() {
1778 let a = Either::B;
1779 match a {
1780 Either::A { .. } => (),
1781 }
1782 }
1783 ";
1784
1785 check_diagnostic(content);
1786 }
1787
1788 #[test]
1789 fn enum_record_ellipsis_all_fields_no_diagnostic() {
1790 let content = r"
1791 enum Either {
1792 A { foo: bool, bar: bool },
1793 B,
1794 }
1795 fn test_fn() {
1796 let a = Either::B;
1797 match a {
1798 Either::A { .. } => (),
1799 Either::B => (),
1800 }
1801 }
1802 ";
1803
1804 check_no_diagnostic(content);
1805 }
1806
1807 #[test]
1535 fn enum_tuple_partial_ellipsis_no_diagnostic() { 1808 fn enum_tuple_partial_ellipsis_no_diagnostic() {
1536 let content = r" 1809 let content = r"
1537 enum Either { 1810 enum Either {
@@ -1689,25 +1962,6 @@ mod false_negatives {
1689 } 1962 }
1690 1963
1691 #[test] 1964 #[test]
1692 fn enum_record() {
1693 let content = r"
1694 enum Either {
1695 A { foo: u32 },
1696 B,
1697 }
1698 fn test_fn() {
1699 match Either::B {
1700 Either::A { foo: 5 } => (),
1701 }
1702 }
1703 ";
1704
1705 // This is a false negative.
1706 // We don't currently handle enum record types.
1707 check_no_diagnostic(content);
1708 }
1709
1710 #[test]
1711 fn internal_or() { 1965 fn internal_or() {
1712 let content = r" 1966 let content = r"
1713 fn test_fn() { 1967 fn test_fn() {
@@ -1796,4 +2050,22 @@ mod false_negatives {
1796 // We don't currently handle tuple patterns with ellipsis. 2050 // We don't currently handle tuple patterns with ellipsis.
1797 check_no_diagnostic(content); 2051 check_no_diagnostic(content);
1798 } 2052 }
2053
2054 #[test]
2055 fn struct_missing_arm() {
2056 let content = r"
2057 struct Foo {
2058 a: bool,
2059 }
2060 fn test_fn(f: Foo) {
2061 match f {
2062 Foo { a: true } => {},
2063 }
2064 }
2065 ";
2066
2067 // This is a false negative.
2068 // We don't currently handle structs.
2069 check_no_diagnostic(content);
2070 }
1799} 2071}
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 33da16b48..9e5dfeab3 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -107,6 +107,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
107 krate: CrateId, 107 krate: CrateId,
108 goal: crate::Canonical<crate::InEnvironment<crate::Obligation>>, 108 goal: crate::Canonical<crate::InEnvironment<crate::Obligation>>,
109 ) -> Option<crate::traits::Solution>; 109 ) -> Option<crate::traits::Solution>;
110
111 #[salsa::invoke(crate::traits::chalk::program_clauses_for_chalk_env_query)]
112 fn program_clauses_for_chalk_env(
113 &self,
114 krate: CrateId,
115 env: chalk_ir::Environment<chalk::Interner>,
116 ) -> chalk_ir::ProgramClauses<chalk::Interner>;
110} 117}
111 118
112fn infer_wait(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { 119fn infer_wait(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index b6d9b3438..dfb6a435f 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -127,6 +127,7 @@ pub struct InferenceResult {
127 field_resolutions: FxHashMap<ExprId, StructFieldId>, 127 field_resolutions: FxHashMap<ExprId, StructFieldId>,
128 /// For each field in record literal, records the field it resolves to. 128 /// For each field in record literal, records the field it resolves to.
129 record_field_resolutions: FxHashMap<ExprId, StructFieldId>, 129 record_field_resolutions: FxHashMap<ExprId, StructFieldId>,
130 record_field_pat_resolutions: FxHashMap<PatId, StructFieldId>,
130 /// For each struct literal, records the variant it resolves to. 131 /// For each struct literal, records the variant it resolves to.
131 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, 132 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
132 /// For each associated item record what it resolves to 133 /// For each associated item record what it resolves to
@@ -147,6 +148,9 @@ impl InferenceResult {
147 pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructFieldId> { 148 pub fn record_field_resolution(&self, expr: ExprId) -> Option<StructFieldId> {
148 self.record_field_resolutions.get(&expr).copied() 149 self.record_field_resolutions.get(&expr).copied()
149 } 150 }
151 pub fn record_field_pat_resolution(&self, pat: PatId) -> Option<StructFieldId> {
152 self.record_field_pat_resolutions.get(&pat).copied()
153 }
150 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { 154 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
151 self.variant_resolutions.get(&id.into()).copied() 155 self.variant_resolutions.get(&id.into()).copied()
152 } 156 }
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 8ec4d4ace..7c2ad4384 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -7,6 +7,7 @@ use hir_def::{
7 expr::{BindingAnnotation, Pat, PatId, RecordFieldPat}, 7 expr::{BindingAnnotation, Pat, PatId, RecordFieldPat},
8 path::Path, 8 path::Path,
9 type_ref::Mutability, 9 type_ref::Mutability,
10 StructFieldId,
10}; 11};
11use hir_expand::name::Name; 12use hir_expand::name::Name;
12use test_utils::tested_by; 13use test_utils::tested_by;
@@ -67,6 +68,11 @@ impl<'a> InferenceContext<'a> {
67 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); 68 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
68 for subpat in subpats { 69 for subpat in subpats {
69 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); 70 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
71 if let Some(local_id) = matching_field {
72 let field_def = StructFieldId { parent: def.unwrap(), local_id };
73 self.result.record_field_pat_resolutions.insert(subpat.pat, field_def);
74 }
75
70 let expected_ty = 76 let expected_ty =
71 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs)); 77 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
72 let expected_ty = self.normalize_associated_types_in(expected_ty); 78 let expected_ty = self.normalize_associated_types_in(expected_ty);
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index a4b8d6683..279c06d65 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -863,7 +863,7 @@ pub trait TypeWalk {
863 &mut |ty, binders| { 863 &mut |ty, binders| {
864 if let &mut Ty::Bound(bound) = ty { 864 if let &mut Ty::Bound(bound) = ty {
865 if bound.debruijn >= binders { 865 if bound.debruijn >= binders {
866 *ty = substs.0[bound.index].clone(); 866 *ty = substs.0[bound.index].clone().shift_bound_vars(binders);
867 } 867 }
868 } 868 }
869 }, 869 },
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 3a4d58bf9..8498d3d96 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -12,7 +12,7 @@ use ra_db::{
12}; 12};
13use stdx::format_to; 13use stdx::format_to;
14 14
15use crate::{db::HirDatabase, expr::ExprValidator}; 15use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator};
16 16
17#[salsa::database( 17#[salsa::database(
18 ra_db::SourceDatabaseExtStorage, 18 ra_db::SourceDatabaseExtStorage,
@@ -104,10 +104,7 @@ impl TestDB {
104 panic!("Can't find module for file") 104 panic!("Can't find module for file")
105 } 105 }
106 106
107 // FIXME: don't duplicate this 107 fn diag<F: FnMut(&dyn Diagnostic)>(&self, mut cb: F) {
108 pub fn diagnostics(&self) -> (String, u32) {
109 let mut buf = String::new();
110 let mut count = 0;
111 let crate_graph = self.crate_graph(); 108 let crate_graph = self.crate_graph();
112 for krate in crate_graph.iter() { 109 for krate in crate_graph.iter() {
113 let crate_def_map = self.crate_def_map(krate); 110 let crate_def_map = self.crate_def_map(krate);
@@ -132,15 +129,36 @@ impl TestDB {
132 129
133 for f in fns { 130 for f in fns {
134 let infer = self.infer(f.into()); 131 let infer = self.infer(f.into());
135 let mut sink = DiagnosticSink::new(|d| { 132 let mut sink = DiagnosticSink::new(&mut cb);
136 format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
137 count += 1;
138 });
139 infer.add_diagnostics(self, f, &mut sink); 133 infer.add_diagnostics(self, f, &mut sink);
140 let mut validator = ExprValidator::new(f, infer, &mut sink); 134 let mut validator = ExprValidator::new(f, infer, &mut sink);
141 validator.validate_body(self); 135 validator.validate_body(self);
142 } 136 }
143 } 137 }
138 }
139
140 pub fn diagnostics(&self) -> (String, u32) {
141 let mut buf = String::new();
142 let mut count = 0;
143 self.diag(|d| {
144 format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
145 count += 1;
146 });
147 (buf, count)
148 }
149
150 /// Like `diagnostics`, but filtered for a single diagnostic.
151 pub fn diagnostic<D: Diagnostic>(&self) -> (String, u32) {
152 let mut buf = String::new();
153 let mut count = 0;
154 self.diag(|d| {
155 // We want to filter diagnostics by the particular one we are testing for, to
156 // avoid surprising results in tests.
157 if d.downcast_ref::<D>().is_some() {
158 format_to!(buf, "{:?}: {}\n", d.syntax_node(self).text(), d.message());
159 count += 1;
160 };
161 });
144 (buf, count) 162 (buf, count)
145 } 163 }
146} 164}
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 81fc0f63a..846005baa 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -18,16 +18,19 @@ use hir_def::{
18 nameres::CrateDefMap, 18 nameres::CrateDefMap,
19 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId, 19 AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
20}; 20};
21use hir_expand::InFile; 21use hir_expand::{db::AstDatabase, InFile};
22use insta::assert_snapshot; 22use insta::assert_snapshot;
23use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; 23use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
24use ra_syntax::{ 24use ra_syntax::{
25 algo, 25 algo,
26 ast::{self, AstNode}, 26 ast::{self, AstNode},
27 SyntaxNode,
27}; 28};
28use stdx::format_to; 29use stdx::format_to;
29 30
30use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResult}; 31use crate::{
32 db::HirDatabase, display::HirDisplay, infer::TypeMismatch, test_db::TestDB, InferenceResult, Ty,
33};
31 34
32// These tests compare the inference results for all expressions in a file 35// These tests compare the inference results for all expressions in a file
33// against snapshots of the expected results using insta. Use cargo-insta to 36// against snapshots of the expected results using insta. Use cargo-insta to
@@ -67,13 +70,19 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
67 70
68 let mut infer_def = |inference_result: Arc<InferenceResult>, 71 let mut infer_def = |inference_result: Arc<InferenceResult>,
69 body_source_map: Arc<BodySourceMap>| { 72 body_source_map: Arc<BodySourceMap>| {
70 let mut types = Vec::new(); 73 let mut types: Vec<(InFile<SyntaxNode>, &Ty)> = Vec::new();
71 let mut mismatches = Vec::new(); 74 let mut mismatches: Vec<(InFile<SyntaxNode>, &TypeMismatch)> = Vec::new();
72 75
73 for (pat, ty) in inference_result.type_of_pat.iter() { 76 for (pat, ty) in inference_result.type_of_pat.iter() {
74 let syntax_ptr = match body_source_map.pat_syntax(pat) { 77 let syntax_ptr = match body_source_map.pat_syntax(pat) {
75 Ok(sp) => { 78 Ok(sp) => {
76 sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr())) 79 let root = db.parse_or_expand(sp.file_id).unwrap();
80 sp.map(|ptr| {
81 ptr.either(
82 |it| it.to_node(&root).syntax().clone(),
83 |it| it.to_node(&root).syntax().clone(),
84 )
85 })
77 } 86 }
78 Err(SyntheticSyntax) => continue, 87 Err(SyntheticSyntax) => continue,
79 }; 88 };
@@ -81,29 +90,31 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
81 } 90 }
82 91
83 for (expr, ty) in inference_result.type_of_expr.iter() { 92 for (expr, ty) in inference_result.type_of_expr.iter() {
84 let syntax_ptr = match body_source_map.expr_syntax(expr) { 93 let node = match body_source_map.expr_syntax(expr) {
85 Ok(sp) => sp.map(|ast| ast.syntax_node_ptr()), 94 Ok(sp) => {
95 let root = db.parse_or_expand(sp.file_id).unwrap();
96 sp.map(|ptr| ptr.to_node(&root).syntax().clone())
97 }
86 Err(SyntheticSyntax) => continue, 98 Err(SyntheticSyntax) => continue,
87 }; 99 };
88 types.push((syntax_ptr.clone(), ty)); 100 types.push((node.clone(), ty));
89 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) { 101 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) {
90 mismatches.push((syntax_ptr, mismatch)); 102 mismatches.push((node, mismatch));
91 } 103 }
92 } 104 }
93 105
94 // sort ranges for consistency 106 // sort ranges for consistency
95 types.sort_by_key(|(src_ptr, _)| { 107 types.sort_by_key(|(node, _)| {
96 (src_ptr.value.range().start(), src_ptr.value.range().end()) 108 let range = node.value.text_range();
109 (range.start(), range.end())
97 }); 110 });
98 for (src_ptr, ty) in &types { 111 for (node, ty) in &types {
99 let node = src_ptr.value.to_node(&src_ptr.file_syntax(&db)); 112 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) {
100
101 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) {
102 (self_param.self_token().unwrap().text_range(), "self".to_string()) 113 (self_param.self_token().unwrap().text_range(), "self".to_string())
103 } else { 114 } else {
104 (src_ptr.value.range(), node.text().to_string().replace("\n", " ")) 115 (node.value.text_range(), node.value.text().to_string().replace("\n", " "))
105 }; 116 };
106 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" }; 117 let macro_prefix = if node.file_id != file_id.into() { "!" } else { "" };
107 format_to!( 118 format_to!(
108 buf, 119 buf,
109 "{}{} '{}': {}\n", 120 "{}{} '{}': {}\n",
@@ -114,11 +125,12 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
114 ); 125 );
115 } 126 }
116 if include_mismatches { 127 if include_mismatches {
117 mismatches.sort_by_key(|(src_ptr, _)| { 128 mismatches.sort_by_key(|(node, _)| {
118 (src_ptr.value.range().start(), src_ptr.value.range().end()) 129 let range = node.value.text_range();
130 (range.start(), range.end())
119 }); 131 });
120 for (src_ptr, mismatch) in &mismatches { 132 for (src_ptr, mismatch) in &mismatches {
121 let range = src_ptr.value.range(); 133 let range = src_ptr.value.text_range();
122 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" }; 134 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
123 format_to!( 135 format_to!(
124 buf, 136 buf,
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index 07cbc521a..6ea51d5d3 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -455,3 +455,29 @@ fn test() {
455 "### 455 "###
456 ); 456 );
457} 457}
458
459#[test]
460fn infer_guard() {
461 assert_snapshot!(
462 infer(r#"
463struct S;
464impl S { fn foo(&self) -> bool { false } }
465
466fn main() {
467 match S {
468 s if s.foo() => (),
469 }
470}
471 "#), @"
472 [28; 32) 'self': &S
473 [42; 51) '{ false }': bool
474 [44; 49) 'false': bool
475 [65; 116) '{ ... } }': ()
476 [71; 114) 'match ... }': ()
477 [77; 78) 'S': S
478 [89; 90) 's': S
479 [94; 95) 's': S
480 [94; 101) 's.foo()': bool
481 [105; 107) '()': ()
482 ")
483}
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 61284d672..61a6801fc 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -533,3 +533,44 @@ fn foo(b: Bar) {
533 "### 533 "###
534 ); 534 );
535} 535}
536
537#[test]
538fn issue_4053_diesel_where_clauses() {
539 assert_snapshot!(
540 infer(r#"
541trait BoxedDsl<DB> {
542 type Output;
543 fn internal_into_boxed(self) -> Self::Output;
544}
545
546struct SelectStatement<From, Select, Distinct, Where, Order, LimitOffset, GroupBy, Locking> {
547 order: Order,
548}
549
550trait QueryFragment<DB: Backend> {}
551
552trait Into<T> { fn into(self) -> T; }
553
554impl<F, S, D, W, O, LOf, DB> BoxedDsl<DB>
555 for SelectStatement<F, S, D, W, O, LOf, G>
556where
557 O: Into<dyn QueryFragment<DB>>,
558{
559 type Output = XXX;
560
561 fn internal_into_boxed(self) -> Self::Output {
562 self.order.into();
563 }
564}
565"#),
566 @r###"
567 [66; 70) 'self': Self
568 [268; 272) 'self': Self
569 [467; 471) 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
570 [489; 523) '{ ... }': ()
571 [499; 503) 'self': SelectStatement<F, S, D, W, O, LOf, {unknown}, {unknown}>
572 [499; 509) 'self.order': O
573 [499; 516) 'self.o...into()': dyn QueryFragment<DB>
574 "###
575 );
576}
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 05791a848..6bc6d474c 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -225,7 +225,7 @@ fn solution_from_chalk(
225 None => unimplemented!(), 225 None => unimplemented!(),
226 }) 226 })
227 .collect(); 227 .collect();
228 let result = Canonical { value, num_vars: subst.binders.len() }; 228 let result = Canonical { value, num_vars: subst.binders.len(&Interner) };
229 SolutionVariables(result) 229 SolutionVariables(result)
230 }; 230 };
231 match solution { 231 match solution {
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index e00a82db2..1ccb7c3b4 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -4,8 +4,8 @@ use std::{fmt, sync::Arc};
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{ 6use chalk_ir::{
7 cast::Cast, fold::shift::Shift, Goal, GoalData, Parameter, PlaceholderIndex, TypeName, 7 cast::Cast, fold::shift::Shift, interner::HasInterner, Goal, GoalData, Parameter,
8 UniverseIndex, 8 PlaceholderIndex, TypeName, UniverseIndex,
9}; 9};
10 10
11use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId}; 11use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId};
@@ -33,8 +33,10 @@ impl chalk_ir::interner::Interner for Interner {
33 type InternedGoals = Vec<Goal<Self>>; 33 type InternedGoals = Vec<Goal<Self>>;
34 type InternedSubstitution = Vec<Parameter<Self>>; 34 type InternedSubstitution = Vec<Parameter<Self>>;
35 type InternedProgramClause = chalk_ir::ProgramClauseData<Self>; 35 type InternedProgramClause = chalk_ir::ProgramClauseData<Self>;
36 type InternedProgramClauses = Vec<chalk_ir::ProgramClause<Self>>; 36 type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>;
37 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; 37 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
38 type InternedParameterKinds = Vec<chalk_ir::ParameterKind<()>>;
39 type InternedCanonicalVarKinds = Vec<chalk_ir::ParameterKind<UniverseIndex>>;
38 type Identifier = TypeAliasId; 40 type Identifier = TypeAliasId;
39 type DefId = InternId; 41 type DefId = InternId;
40 42
@@ -60,6 +62,27 @@ impl chalk_ir::interner::Interner for Interner {
60 tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt))) 62 tls::with_current_program(|prog| Some(prog?.debug_alias(alias, fmt)))
61 } 63 }
62 64
65 fn debug_projection_ty(
66 proj: &chalk_ir::ProjectionTy<Interner>,
67 fmt: &mut fmt::Formatter<'_>,
68 ) -> Option<fmt::Result> {
69 tls::with_current_program(|prog| Some(prog?.debug_projection_ty(proj, fmt)))
70 }
71
72 fn debug_opaque_ty(
73 opaque_ty: &chalk_ir::OpaqueTy<Interner>,
74 fmt: &mut fmt::Formatter<'_>,
75 ) -> Option<fmt::Result> {
76 tls::with_current_program(|prog| Some(prog?.debug_opaque_ty(opaque_ty, fmt)))
77 }
78
79 fn debug_opaque_ty_id(
80 opaque_ty_id: chalk_ir::OpaqueTyId<Self>,
81 fmt: &mut fmt::Formatter<'_>,
82 ) -> Option<fmt::Result> {
83 tls::with_current_program(|prog| Some(prog?.debug_opaque_ty_id(opaque_ty_id, fmt)))
84 }
85
63 fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 86 fn debug_ty(ty: &chalk_ir::Ty<Interner>, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> {
64 tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt))) 87 tls::with_current_program(|prog| Some(prog?.debug_ty(ty, fmt)))
65 } 88 }
@@ -202,15 +225,15 @@ impl chalk_ir::interner::Interner for Interner {
202 fn intern_program_clauses( 225 fn intern_program_clauses(
203 &self, 226 &self,
204 data: impl IntoIterator<Item = chalk_ir::ProgramClause<Self>>, 227 data: impl IntoIterator<Item = chalk_ir::ProgramClause<Self>>,
205 ) -> Vec<chalk_ir::ProgramClause<Self>> { 228 ) -> Arc<[chalk_ir::ProgramClause<Self>]> {
206 data.into_iter().collect() 229 data.into_iter().collect()
207 } 230 }
208 231
209 fn program_clauses_data<'a>( 232 fn program_clauses_data<'a>(
210 &self, 233 &self,
211 clauses: &'a Vec<chalk_ir::ProgramClause<Self>>, 234 clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>,
212 ) -> &'a [chalk_ir::ProgramClause<Self>] { 235 ) -> &'a [chalk_ir::ProgramClause<Self>] {
213 clauses 236 &clauses
214 } 237 }
215 238
216 fn intern_quantified_where_clauses( 239 fn intern_quantified_where_clauses(
@@ -226,6 +249,34 @@ impl chalk_ir::interner::Interner for Interner {
226 ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] { 249 ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] {
227 clauses 250 clauses
228 } 251 }
252
253 fn intern_parameter_kinds(
254 &self,
255 data: impl IntoIterator<Item = chalk_ir::ParameterKind<()>>,
256 ) -> Self::InternedParameterKinds {
257 data.into_iter().collect()
258 }
259
260 fn parameter_kinds_data<'a>(
261 &self,
262 parameter_kinds: &'a Self::InternedParameterKinds,
263 ) -> &'a [chalk_ir::ParameterKind<()>] {
264 &parameter_kinds
265 }
266
267 fn intern_canonical_var_kinds(
268 &self,
269 data: impl IntoIterator<Item = chalk_ir::ParameterKind<UniverseIndex>>,
270 ) -> Self::InternedCanonicalVarKinds {
271 data.into_iter().collect()
272 }
273
274 fn canonical_var_kinds_data<'a>(
275 &self,
276 canonical_var_kinds: &'a Self::InternedCanonicalVarKinds,
277 ) -> &'a [chalk_ir::ParameterKind<UniverseIndex>] {
278 &canonical_var_kinds
279 }
229} 280}
230 281
231impl chalk_ir::interner::HasInterner for Interner { 282impl chalk_ir::interner::HasInterner for Interner {
@@ -268,9 +319,12 @@ impl ToChalk for Ty {
268 Ty::Projection(proj_ty) => { 319 Ty::Projection(proj_ty) => {
269 let associated_ty_id = proj_ty.associated_ty.to_chalk(db); 320 let associated_ty_id = proj_ty.associated_ty.to_chalk(db);
270 let substitution = proj_ty.parameters.to_chalk(db); 321 let substitution = proj_ty.parameters.to_chalk(db);
271 chalk_ir::AliasTy { associated_ty_id, substitution } 322 chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
272 .cast(&Interner) 323 associated_ty_id,
273 .intern(&Interner) 324 substitution,
325 })
326 .cast(&Interner)
327 .intern(&Interner)
274 } 328 }
275 Ty::Placeholder(id) => { 329 Ty::Placeholder(id) => {
276 let interned_id = db.intern_type_param_id(id); 330 let interned_id = db.intern_type_param_id(id);
@@ -314,16 +368,17 @@ impl ToChalk for Ty {
314 ); 368 );
315 Ty::Placeholder(db.lookup_intern_type_param_id(interned_id)) 369 Ty::Placeholder(db.lookup_intern_type_param_id(interned_id))
316 } 370 }
317 chalk_ir::TyData::Alias(proj) => { 371 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Projection(proj)) => {
318 let associated_ty = from_chalk(db, proj.associated_ty_id); 372 let associated_ty = from_chalk(db, proj.associated_ty_id);
319 let parameters = from_chalk(db, proj.substitution); 373 let parameters = from_chalk(db, proj.substitution);
320 Ty::Projection(ProjectionTy { associated_ty, parameters }) 374 Ty::Projection(ProjectionTy { associated_ty, parameters })
321 } 375 }
376 chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(),
322 chalk_ir::TyData::Function(_) => unimplemented!(), 377 chalk_ir::TyData::Function(_) => unimplemented!(),
323 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), 378 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx),
324 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, 379 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
325 chalk_ir::TyData::Dyn(where_clauses) => { 380 chalk_ir::TyData::Dyn(where_clauses) => {
326 assert_eq!(where_clauses.bounds.binders.len(), 1); 381 assert_eq!(where_clauses.bounds.binders.len(&Interner), 1);
327 let predicates = where_clauses 382 let predicates = where_clauses
328 .bounds 383 .bounds
329 .skip_binders() 384 .skip_binders()
@@ -404,6 +459,7 @@ impl ToChalk for TypeCtor {
404 match type_name { 459 match type_name {
405 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()), 460 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
406 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)), 461 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
462 TypeName::OpaqueType(_) => unreachable!(),
407 TypeName::Error => { 463 TypeName::Error => {
408 // this should not be reached, since we don't represent TypeName::Error with TypeCtor 464 // this should not be reached, since we don't represent TypeName::Error with TypeCtor
409 unreachable!() 465 unreachable!()
@@ -460,7 +516,8 @@ impl ToChalk for GenericPredicate {
460 } 516 }
461 GenericPredicate::Projection(projection_pred) => { 517 GenericPredicate::Projection(projection_pred) => {
462 let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner); 518 let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner);
463 let alias = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner); 519 let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner);
520 let alias = chalk_ir::AliasTy::Projection(projection);
464 make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0) 521 make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0)
465 } 522 }
466 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), 523 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
@@ -481,7 +538,13 @@ impl ToChalk for GenericPredicate {
481 GenericPredicate::Implemented(from_chalk(db, tr)) 538 GenericPredicate::Implemented(from_chalk(db, tr))
482 } 539 }
483 chalk_ir::WhereClause::AliasEq(projection_eq) => { 540 chalk_ir::WhereClause::AliasEq(projection_eq) => {
484 let projection_ty = from_chalk(db, projection_eq.alias); 541 let projection_ty = from_chalk(
542 db,
543 match projection_eq.alias {
544 chalk_ir::AliasTy::Projection(p) => p,
545 _ => unimplemented!(),
546 },
547 );
485 let ty = from_chalk(db, projection_eq.ty); 548 let ty = from_chalk(db, projection_eq.ty);
486 GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty }) 549 GenericPredicate::Projection(super::ProjectionPredicate { projection_ty, ty })
487 } 550 }
@@ -490,10 +553,10 @@ impl ToChalk for GenericPredicate {
490} 553}
491 554
492impl ToChalk for ProjectionTy { 555impl ToChalk for ProjectionTy {
493 type Chalk = chalk_ir::AliasTy<Interner>; 556 type Chalk = chalk_ir::ProjectionTy<Interner>;
494 557
495 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasTy<Interner> { 558 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> {
496 chalk_ir::AliasTy { 559 chalk_ir::ProjectionTy {
497 associated_ty_id: self.associated_ty.to_chalk(db), 560 associated_ty_id: self.associated_ty.to_chalk(db),
498 substitution: self.parameters.to_chalk(db), 561 substitution: self.parameters.to_chalk(db),
499 } 562 }
@@ -501,7 +564,7 @@ impl ToChalk for ProjectionTy {
501 564
502 fn from_chalk( 565 fn from_chalk(
503 db: &dyn HirDatabase, 566 db: &dyn HirDatabase,
504 projection_ty: chalk_ir::AliasTy<Interner>, 567 projection_ty: chalk_ir::ProjectionTy<Interner>,
505 ) -> ProjectionTy { 568 ) -> ProjectionTy {
506 ProjectionTy { 569 ProjectionTy {
507 associated_ty: from_chalk(db, projection_ty.associated_ty_id), 570 associated_ty: from_chalk(db, projection_ty.associated_ty_id),
@@ -514,7 +577,10 @@ impl ToChalk for super::ProjectionPredicate {
514 type Chalk = chalk_ir::AliasEq<Interner>; 577 type Chalk = chalk_ir::AliasEq<Interner>;
515 578
516 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { 579 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
517 chalk_ir::AliasEq { alias: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db) } 580 chalk_ir::AliasEq {
581 alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)),
582 ty: self.ty.to_chalk(db),
583 }
518 } 584 }
519 585
520 fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { 586 fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self {
@@ -540,17 +606,24 @@ impl ToChalk for Obligation {
540impl<T> ToChalk for Canonical<T> 606impl<T> ToChalk for Canonical<T>
541where 607where
542 T: ToChalk, 608 T: ToChalk,
609 T::Chalk: HasInterner<Interner = Interner>,
543{ 610{
544 type Chalk = chalk_ir::Canonical<T::Chalk>; 611 type Chalk = chalk_ir::Canonical<T::Chalk>;
545 612
546 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { 613 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
547 let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT); 614 let parameter = chalk_ir::ParameterKind::Ty(chalk_ir::UniverseIndex::ROOT);
548 let value = self.value.to_chalk(db); 615 let value = self.value.to_chalk(db);
549 chalk_ir::Canonical { value, binders: vec![parameter; self.num_vars] } 616 chalk_ir::Canonical {
617 value,
618 binders: chalk_ir::CanonicalVarKinds::from(&Interner, vec![parameter; self.num_vars]),
619 }
550 } 620 }
551 621
552 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { 622 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
553 Canonical { num_vars: canonical.binders.len(), value: from_chalk(db, canonical.value) } 623 Canonical {
624 num_vars: canonical.binders.len(&Interner),
625 value: from_chalk(db, canonical.value),
626 }
554 } 627 }
555} 628}
556 629
@@ -649,9 +722,15 @@ impl ToChalk for builtin::BuiltinImplAssocTyValueData {
649 } 722 }
650} 723}
651 724
652fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 725fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
726where
727 T: HasInterner<Interner = Interner>,
728{
653 chalk_ir::Binders::new( 729 chalk_ir::Binders::new(
654 std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(), 730 chalk_ir::ParameterKinds::from(
731 &Interner,
732 std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars),
733 ),
655 value, 734 value,
656 ) 735 )
657} 736}
@@ -799,6 +878,28 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
799 // FIXME tell Chalk about well-known traits (here and in trait_datum) 878 // FIXME tell Chalk about well-known traits (here and in trait_datum)
800 None 879 None
801 } 880 }
881
882 fn program_clauses_for_env(
883 &self,
884 environment: &chalk_ir::Environment<Interner>,
885 ) -> chalk_ir::ProgramClauses<Interner> {
886 self.db.program_clauses_for_chalk_env(self.krate, environment.clone())
887 }
888
889 fn opaque_ty_data(
890 &self,
891 _id: chalk_ir::OpaqueTyId<Interner>,
892 ) -> Arc<chalk_rust_ir::OpaqueTyDatum<Interner>> {
893 unimplemented!()
894 }
895}
896
897pub(crate) fn program_clauses_for_chalk_env_query(
898 db: &dyn HirDatabase,
899 krate: CrateId,
900 environment: chalk_ir::Environment<Interner>,
901) -> chalk_ir::ProgramClauses<Interner> {
902 chalk_solve::program_clauses_for_env(&ChalkContext { db, krate }, &environment)
802} 903}
803 904
804pub(crate) fn associated_ty_data_query( 905pub(crate) fn associated_ty_data_query(
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
index fa8e4d1ad..4867cb17e 100644
--- a/crates/ra_hir_ty/src/traits/chalk/tls.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -121,19 +121,38 @@ impl DebugContext<'_> {
121 write!(fmt, "{}::{}", trait_data.name, type_alias_data.name) 121 write!(fmt, "{}::{}", trait_data.name, type_alias_data.name)
122 } 122 }
123 123
124 pub fn debug_opaque_ty_id(
125 &self,
126 opaque_ty_id: chalk_ir::OpaqueTyId<Interner>,
127 fmt: &mut fmt::Formatter<'_>,
128 ) -> Result<(), fmt::Error> {
129 fmt.debug_struct("OpaqueTyId").field("index", &opaque_ty_id.0).finish()
130 }
131
124 pub fn debug_alias( 132 pub fn debug_alias(
125 &self, 133 &self,
126 alias: &AliasTy<Interner>, 134 alias_ty: &AliasTy<Interner>,
135 fmt: &mut fmt::Formatter<'_>,
136 ) -> Result<(), fmt::Error> {
137 match alias_ty {
138 AliasTy::Projection(projection_ty) => self.debug_projection_ty(projection_ty, fmt),
139 AliasTy::Opaque(opaque_ty) => self.debug_opaque_ty(opaque_ty, fmt),
140 }
141 }
142
143 pub fn debug_projection_ty(
144 &self,
145 projection_ty: &chalk_ir::ProjectionTy<Interner>,
127 fmt: &mut fmt::Formatter<'_>, 146 fmt: &mut fmt::Formatter<'_>,
128 ) -> Result<(), fmt::Error> { 147 ) -> Result<(), fmt::Error> {
129 let type_alias: TypeAliasId = from_chalk(self.0, alias.associated_ty_id); 148 let type_alias: TypeAliasId = from_chalk(self.0, projection_ty.associated_ty_id);
130 let type_alias_data = self.0.type_alias_data(type_alias); 149 let type_alias_data = self.0.type_alias_data(type_alias);
131 let trait_ = match type_alias.lookup(self.0.upcast()).container { 150 let trait_ = match type_alias.lookup(self.0.upcast()).container {
132 AssocContainerId::TraitId(t) => t, 151 AssocContainerId::TraitId(t) => t,
133 _ => panic!("associated type not in trait"), 152 _ => panic!("associated type not in trait"),
134 }; 153 };
135 let trait_data = self.0.trait_data(trait_); 154 let trait_data = self.0.trait_data(trait_);
136 let params = alias.substitution.parameters(&Interner); 155 let params = projection_ty.substitution.parameters(&Interner);
137 write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?; 156 write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
138 if params.len() > 1 { 157 if params.len() > 1 {
139 write!( 158 write!(
@@ -145,6 +164,14 @@ impl DebugContext<'_> {
145 write!(fmt, ">::{}", type_alias_data.name) 164 write!(fmt, ">::{}", type_alias_data.name)
146 } 165 }
147 166
167 pub fn debug_opaque_ty(
168 &self,
169 opaque_ty: &chalk_ir::OpaqueTy<Interner>,
170 fmt: &mut fmt::Formatter<'_>,
171 ) -> Result<(), fmt::Error> {
172 write!(fmt, "{:?}", opaque_ty.opaque_ty_id)
173 }
174
148 pub fn debug_ty( 175 pub fn debug_ty(
149 &self, 176 &self,
150 ty: &chalk_ir::Ty<Interner>, 177 ty: &chalk_ir::Ty<Interner>,