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.toml9
-rw-r--r--crates/ra_hir_ty/src/_match.rs350
-rw-r--r--crates/ra_hir_ty/src/db.rs9
-rw-r--r--crates/ra_hir_ty/src/expr.rs68
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs6
-rw-r--r--crates/ra_hir_ty/src/lower.rs42
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs45
-rw-r--r--crates/ra_hir_ty/src/tests.rs4
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs3
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs3
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs100
-rw-r--r--crates/ra_hir_ty/src/traits.rs21
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs162
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs42
14 files changed, 740 insertions, 124 deletions
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 59efc1c31..e891d733f 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -8,6 +8,7 @@ authors = ["rust-analyzer developers"]
8doctest = false 8doctest = false
9 9
10[dependencies] 10[dependencies]
11itertools = "0.9.0"
11arrayvec = "0.5.1" 12arrayvec = "0.5.1"
12smallvec = "1.2.0" 13smallvec = "1.2.0"
13ena = "0.13.1" 14ena = "0.13.1"
@@ -26,9 +27,9 @@ test_utils = { path = "../test_utils" }
26 27
27scoped-tls = "1" 28scoped-tls = "1"
28 29
29chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } 30chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "6222e416b96892b2a86bc08de7dbc9826ff1acea" }
30chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } 31chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "6222e416b96892b2a86bc08de7dbc9826ff1acea" }
31chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "039fc904a05f8cb3d0c682c9a57a63dda7a35356" } 32chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "6222e416b96892b2a86bc08de7dbc9826ff1acea" }
32 33
33[dev-dependencies] 34[dev-dependencies]
34insta = "0.15.0" 35insta = "0.16.0"
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index 9e9a9d047..a64be9848 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -289,7 +289,7 @@ impl PatStack {
289 Self::from_slice(&self.0[1..]) 289 Self::from_slice(&self.0[1..])
290 } 290 }
291 291
292 fn replace_head_with(&self, pat_ids: &[PatId]) -> PatStack { 292 fn replace_head_with<T: Into<PatIdOrWild> + Copy>(&self, pat_ids: &[T]) -> PatStack {
293 let mut patterns: PatStackInner = smallvec![]; 293 let mut patterns: PatStackInner = smallvec![];
294 for pat in pat_ids { 294 for pat in pat_ids {
295 patterns.push((*pat).into()); 295 patterns.push((*pat).into());
@@ -320,12 +320,14 @@ impl PatStack {
320 constructor: &Constructor, 320 constructor: &Constructor,
321 ) -> MatchCheckResult<Option<PatStack>> { 321 ) -> MatchCheckResult<Option<PatStack>> {
322 let result = match (self.head().as_pat(cx), constructor) { 322 let result = match (self.head().as_pat(cx), constructor) {
323 (Pat::Tuple(ref pat_ids), Constructor::Tuple { arity }) => { 323 (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => {
324 debug_assert_eq!( 324 if ellipsis.is_some() {
325 pat_ids.len(), 325 // If there are ellipsis here, we should add the correct number of
326 *arity, 326 // Pat::Wild patterns to `pat_ids`. We should be able to use the
327 "we type check before calling this code, so we should never hit this case", 327 // constructors arity for this, but at the time of writing we aren't
328 ); 328 // correctly calculating this arity when ellipsis are present.
329 return Err(MatchCheckErr::NotImplemented);
330 }
329 331
330 Some(self.replace_head_with(pat_ids)) 332 Some(self.replace_head_with(pat_ids))
331 } 333 }
@@ -351,19 +353,47 @@ impl PatStack {
351 Some(self.to_tail()) 353 Some(self.to_tail())
352 } 354 }
353 } 355 }
354 (Pat::TupleStruct { args: ref pat_ids, .. }, Constructor::Enum(enum_constructor)) => { 356 (
357 Pat::TupleStruct { args: ref pat_ids, ellipsis, .. },
358 Constructor::Enum(enum_constructor),
359 ) => {
355 let pat_id = self.head().as_id().expect("we know this isn't a wild"); 360 let pat_id = self.head().as_id().expect("we know this isn't a wild");
356 if !enum_variant_matches(cx, pat_id, *enum_constructor) { 361 if !enum_variant_matches(cx, pat_id, *enum_constructor) {
357 None 362 None
358 } else { 363 } else {
359 // If the enum variant matches, then we need to confirm 364 let constructor_arity = constructor.arity(cx)?;
360 // that the number of patterns aligns with the expected 365 if let Some(ellipsis_position) = ellipsis {
361 // number of patterns for that enum variant. 366 // If there are ellipsis in the pattern, the ellipsis must take the place
362 if pat_ids.len() != constructor.arity(cx)? { 367 // of at least one sub-pattern, so `pat_ids` should be smaller than the
363 return Err(MatchCheckErr::MalformedMatchArm); 368 // constructor arity.
369 if pat_ids.len() < constructor_arity {
370 let mut new_patterns: Vec<PatIdOrWild> = vec![];
371
372 for pat_id in &pat_ids[0..ellipsis_position] {
373 new_patterns.push((*pat_id).into());
374 }
375
376 for _ in 0..(constructor_arity - pat_ids.len()) {
377 new_patterns.push(PatIdOrWild::Wild);
378 }
379
380 for pat_id in &pat_ids[ellipsis_position..pat_ids.len()] {
381 new_patterns.push((*pat_id).into());
382 }
383
384 Some(self.replace_head_with(&new_patterns))
385 } else {
386 return Err(MatchCheckErr::MalformedMatchArm);
387 }
388 } else {
389 // If there is no ellipsis in the tuple pattern, the number
390 // of patterns must equal the constructor arity.
391 if pat_ids.len() == constructor_arity {
392 Some(self.replace_head_with(pat_ids))
393 } else {
394 return Err(MatchCheckErr::MalformedMatchArm);
395 }
364 } 396 }
365
366 Some(self.replace_head_with(pat_ids))
367 } 397 }
368 } 398 }
369 (Pat::Or(_), _) => return Err(MatchCheckErr::NotImplemented), 399 (Pat::Or(_), _) => return Err(MatchCheckErr::NotImplemented),
@@ -644,7 +674,11 @@ impl Constructor {
644fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { 674fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> {
645 let res = match pat.as_pat(cx) { 675 let res = match pat.as_pat(cx) {
646 Pat::Wild => None, 676 Pat::Wild => None,
647 Pat::Tuple(pats) => Some(Constructor::Tuple { arity: pats.len() }), 677 // FIXME somehow create the Tuple constructor with the proper arity. If there are
678 // ellipsis, the arity is not equal to the number of patterns.
679 Pat::Tuple { args: pats, ellipsis } if ellipsis.is_none() => {
680 Some(Constructor::Tuple { arity: pats.len() })
681 }
648 Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { 682 Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {
649 Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)), 683 Expr::Literal(Literal::Bool(val)) => Some(Constructor::Bool(val)),
650 _ => return Err(MatchCheckErr::NotImplemented), 684 _ => return Err(MatchCheckErr::NotImplemented),
@@ -973,6 +1007,47 @@ mod tests {
973 } 1007 }
974 1008
975 #[test] 1009 #[test]
1010 fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() {
1011 let content = r"
1012 fn test_fn() {
1013 match (false, true, false) {
1014 (false, ..) => {},
1015 (true, ..) => {},
1016 }
1017 }
1018 ";
1019
1020 check_no_diagnostic(content);
1021 }
1022
1023 #[test]
1024 fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() {
1025 let content = r"
1026 fn test_fn() {
1027 match (false, true, false) {
1028 (.., false) => {},
1029 (.., true) => {},
1030 }
1031 }
1032 ";
1033
1034 check_no_diagnostic(content);
1035 }
1036
1037 #[test]
1038 fn tuple_of_bools_with_ellipsis_no_diagnostic() {
1039 let content = r"
1040 fn test_fn() {
1041 match (false, true, false) {
1042 (..) => {},
1043 }
1044 }
1045 ";
1046
1047 check_no_diagnostic(content);
1048 }
1049
1050 #[test]
976 fn tuple_of_tuple_and_bools_no_arms() { 1051 fn tuple_of_tuple_and_bools_no_arms() {
977 let content = r" 1052 let content = r"
978 fn test_fn() { 1053 fn test_fn() {
@@ -1315,8 +1390,9 @@ mod tests {
1315 } 1390 }
1316 "; 1391 ";
1317 1392
1318 // Match arms with the incorrect type are filtered out. 1393 // Match statements with arms that don't match the
1319 check_diagnostic(content); 1394 // expression pattern do not fire this diagnostic.
1395 check_no_diagnostic(content);
1320 } 1396 }
1321 1397
1322 #[test] 1398 #[test]
@@ -1330,8 +1406,9 @@ mod tests {
1330 } 1406 }
1331 "; 1407 ";
1332 1408
1333 // Match arms with the incorrect type are filtered out. 1409 // Match statements with arms that don't match the
1334 check_diagnostic(content); 1410 // expression pattern do not fire this diagnostic.
1411 check_no_diagnostic(content);
1335 } 1412 }
1336 1413
1337 #[test] 1414 #[test]
@@ -1344,8 +1421,9 @@ mod tests {
1344 } 1421 }
1345 "; 1422 ";
1346 1423
1347 // Match arms with the incorrect type are filtered out. 1424 // Match statements with arms that don't match the
1348 check_diagnostic(content); 1425 // expression pattern do not fire this diagnostic.
1426 check_no_diagnostic(content);
1349 } 1427 }
1350 1428
1351 #[test] 1429 #[test]
@@ -1383,6 +1461,163 @@ mod tests {
1383 // we don't create a diagnostic). 1461 // we don't create a diagnostic).
1384 check_no_diagnostic(content); 1462 check_no_diagnostic(content);
1385 } 1463 }
1464
1465 #[test]
1466 fn expr_diverges() {
1467 let content = r"
1468 enum Either {
1469 A,
1470 B,
1471 }
1472 fn test_fn() {
1473 match loop {} {
1474 Either::A => (),
1475 Either::B => (),
1476 }
1477 }
1478 ";
1479
1480 check_no_diagnostic(content);
1481 }
1482
1483 #[test]
1484 fn expr_loop_with_break() {
1485 let content = r"
1486 enum Either {
1487 A,
1488 B,
1489 }
1490 fn test_fn() {
1491 match loop { break Foo::A } {
1492 Either::A => (),
1493 Either::B => (),
1494 }
1495 }
1496 ";
1497
1498 check_no_diagnostic(content);
1499 }
1500
1501 #[test]
1502 fn expr_partially_diverges() {
1503 let content = r"
1504 enum Either<T> {
1505 A(T),
1506 B,
1507 }
1508 fn foo() -> Either<!> {
1509 Either::B
1510 }
1511 fn test_fn() -> u32 {
1512 match foo() {
1513 Either::A(val) => val,
1514 Either::B => 0,
1515 }
1516 }
1517 ";
1518
1519 check_no_diagnostic(content);
1520 }
1521
1522 #[test]
1523 fn enum_tuple_partial_ellipsis_no_diagnostic() {
1524 let content = r"
1525 enum Either {
1526 A(bool, bool, bool, bool),
1527 B,
1528 }
1529 fn test_fn() {
1530 match Either::B {
1531 Either::A(true, .., true) => {},
1532 Either::A(true, .., false) => {},
1533 Either::A(false, .., true) => {},
1534 Either::A(false, .., false) => {},
1535 Either::B => {},
1536 }
1537 }
1538 ";
1539
1540 check_no_diagnostic(content);
1541 }
1542
1543 #[test]
1544 fn enum_tuple_partial_ellipsis_2_no_diagnostic() {
1545 let content = r"
1546 enum Either {
1547 A(bool, bool, bool, bool),
1548 B,
1549 }
1550 fn test_fn() {
1551 match Either::B {
1552 Either::A(true, .., true) => {},
1553 Either::A(true, .., false) => {},
1554 Either::A(.., true) => {},
1555 Either::A(.., false) => {},
1556 Either::B => {},
1557 }
1558 }
1559 ";
1560
1561 check_no_diagnostic(content);
1562 }
1563
1564 #[test]
1565 fn enum_tuple_partial_ellipsis_missing_arm() {
1566 let content = r"
1567 enum Either {
1568 A(bool, bool, bool, bool),
1569 B,
1570 }
1571 fn test_fn() {
1572 match Either::B {
1573 Either::A(true, .., true) => {},
1574 Either::A(true, .., false) => {},
1575 Either::A(false, .., false) => {},
1576 Either::B => {},
1577 }
1578 }
1579 ";
1580
1581 check_diagnostic(content);
1582 }
1583
1584 #[test]
1585 fn enum_tuple_partial_ellipsis_2_missing_arm() {
1586 let content = r"
1587 enum Either {
1588 A(bool, bool, bool, bool),
1589 B,
1590 }
1591 fn test_fn() {
1592 match Either::B {
1593 Either::A(true, .., true) => {},
1594 Either::A(true, .., false) => {},
1595 Either::A(.., true) => {},
1596 Either::B => {},
1597 }
1598 }
1599 ";
1600
1601 check_diagnostic(content);
1602 }
1603
1604 #[test]
1605 fn enum_tuple_ellipsis_no_diagnostic() {
1606 let content = r"
1607 enum Either {
1608 A(bool, bool, bool, bool),
1609 B,
1610 }
1611 fn test_fn() {
1612 match Either::B {
1613 Either::A(..) => {},
1614 Either::B => {},
1615 }
1616 }
1617 ";
1618
1619 check_no_diagnostic(content);
1620 }
1386} 1621}
1387 1622
1388#[cfg(test)] 1623#[cfg(test)]
@@ -1452,4 +1687,75 @@ mod false_negatives {
1452 // We do not currently handle patterns with internal `or`s. 1687 // We do not currently handle patterns with internal `or`s.
1453 check_no_diagnostic(content); 1688 check_no_diagnostic(content);
1454 } 1689 }
1690
1691 #[test]
1692 fn expr_diverges_missing_arm() {
1693 let content = r"
1694 enum Either {
1695 A,
1696 B,
1697 }
1698 fn test_fn() {
1699 match loop {} {
1700 Either::A => (),
1701 }
1702 }
1703 ";
1704
1705 // This is a false negative.
1706 // Even though the match expression diverges, rustc fails
1707 // to compile here since `Either::B` is missing.
1708 check_no_diagnostic(content);
1709 }
1710
1711 #[test]
1712 fn expr_loop_missing_arm() {
1713 let content = r"
1714 enum Either {
1715 A,
1716 B,
1717 }
1718 fn test_fn() {
1719 match loop { break Foo::A } {
1720 Either::A => (),
1721 }
1722 }
1723 ";
1724
1725 // This is a false negative.
1726 // We currently infer the type of `loop { break Foo::A }` to `!`, which
1727 // causes us to skip the diagnostic since `Either::A` doesn't type check
1728 // with `!`.
1729 check_no_diagnostic(content);
1730 }
1731
1732 #[test]
1733 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
1734 let content = r"
1735 fn test_fn() {
1736 match (false, true, false) {
1737 (false, ..) => {},
1738 }
1739 }
1740 ";
1741
1742 // This is a false negative.
1743 // We don't currently handle tuple patterns with ellipsis.
1744 check_no_diagnostic(content);
1745 }
1746
1747 #[test]
1748 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
1749 let content = r"
1750 fn test_fn() {
1751 match (false, true, false) {
1752 (.., false) => {},
1753 }
1754 }
1755 ";
1756
1757 // This is a false negative.
1758 // We don't currently handle tuple patterns with ellipsis.
1759 check_no_diagnostic(content);
1760 }
1455} 1761}
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 1462b053f..33da16b48 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -11,7 +11,7 @@ use ra_db::{impl_intern_key, salsa, CrateId, Upcast};
11use ra_prof::profile; 11use ra_prof::profile;
12 12
13use crate::{ 13use crate::{
14 method_resolution::CrateImplDefs, 14 method_resolution::{CrateImplDefs, TyFingerprint},
15 traits::{chalk, AssocTyValue, Impl}, 15 traits::{chalk, AssocTyValue, Impl},
16 Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty, 16 Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty,
17 TyDefId, TypeCtor, ValueTyDefId, 17 TyDefId, TypeCtor, ValueTyDefId,
@@ -65,7 +65,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
65 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; 65 fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>;
66 66
67 #[salsa::invoke(crate::traits::impls_for_trait_query)] 67 #[salsa::invoke(crate::traits::impls_for_trait_query)]
68 fn impls_for_trait(&self, krate: CrateId, trait_: TraitId) -> Arc<[ImplId]>; 68 fn impls_for_trait(
69 &self,
70 krate: CrateId,
71 trait_: TraitId,
72 self_ty_fp: Option<TyFingerprint>,
73 ) -> Arc<[ImplId]>;
69 74
70 // Interned IDs for Chalk integration 75 // Interned IDs for Chalk integration
71 #[salsa::interned] 76 #[salsa::interned]
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index 827b687de..21abbcf1e 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -89,21 +89,19 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
89 let (_, source_map) = db.body_with_source_map(self.func.into()); 89 let (_, source_map) = db.body_with_source_map(self.func.into());
90 90
91 if let Ok(source_ptr) = source_map.expr_syntax(id) { 91 if let Ok(source_ptr) = source_map.expr_syntax(id) {
92 if let Some(expr) = source_ptr.value.as_ref().left() { 92 let root = source_ptr.file_syntax(db.upcast());
93 let root = source_ptr.file_syntax(db.upcast()); 93 if let ast::Expr::RecordLit(record_lit) = &source_ptr.value.to_node(&root) {
94 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { 94 if let Some(field_list) = record_lit.record_field_list() {
95 if let Some(field_list) = record_lit.record_field_list() { 95 let variant_data = variant_data(db.upcast(), variant_def);
96 let variant_data = variant_data(db.upcast(), variant_def); 96 let missed_fields = missed_fields
97 let missed_fields = missed_fields 97 .into_iter()
98 .into_iter() 98 .map(|idx| variant_data.fields()[idx].name.clone())
99 .map(|idx| variant_data.fields()[idx].name.clone()) 99 .collect();
100 .collect(); 100 self.sink.push(MissingFields {
101 self.sink.push(MissingFields { 101 file: source_ptr.file_id,
102 file: source_ptr.file_id, 102 field_list: AstPtr::new(&field_list),
103 field_list: AstPtr::new(&field_list), 103 missed_fields,
104 missed_fields, 104 })
105 })
106 }
107 } 105 }
108 } 106 }
109 } 107 }
@@ -163,12 +161,6 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
163 161
164 let mut seen = Matrix::empty(); 162 let mut seen = Matrix::empty();
165 for pat in pats { 163 for pat in pats {
166 // We skip any patterns whose type we cannot resolve.
167 //
168 // This could lead to false positives in this diagnostic, so
169 // it might be better to skip the entire diagnostic if we either
170 // cannot resolve a match arm or determine that the match arm has
171 // the wrong type.
172 if let Some(pat_ty) = infer.type_of_pat.get(pat) { 164 if let Some(pat_ty) = infer.type_of_pat.get(pat) {
173 // We only include patterns whose type matches the type 165 // We only include patterns whose type matches the type
174 // of the match expression. If we had a InvalidMatchArmPattern 166 // of the match expression. If we had a InvalidMatchArmPattern
@@ -191,8 +183,15 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
191 // to the matrix here. 183 // to the matrix here.
192 let v = PatStack::from_pattern(pat); 184 let v = PatStack::from_pattern(pat);
193 seen.push(&cx, v); 185 seen.push(&cx, v);
186 continue;
194 } 187 }
195 } 188 }
189
190 // If we can't resolve the type of a pattern, or the pattern type doesn't
191 // fit the match expression, we skip this diagnostic. Skipping the entire
192 // diagnostic rather than just not including this match arm is preferred
193 // to avoid the chance of false positives.
194 return;
196 } 195 }
197 196
198 match is_useful(&cx, &seen, &PatStack::from_wild()) { 197 match is_useful(&cx, &seen, &PatStack::from_wild()) {
@@ -205,18 +204,16 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
205 } 204 }
206 205
207 if let Ok(source_ptr) = source_map.expr_syntax(id) { 206 if let Ok(source_ptr) = source_map.expr_syntax(id) {
208 if let Some(expr) = source_ptr.value.as_ref().left() { 207 let root = source_ptr.file_syntax(db.upcast());
209 let root = source_ptr.file_syntax(db.upcast()); 208 if let ast::Expr::MatchExpr(match_expr) = &source_ptr.value.to_node(&root) {
210 if let ast::Expr::MatchExpr(match_expr) = expr.to_node(&root) { 209 if let (Some(match_expr), Some(arms)) =
211 if let (Some(match_expr), Some(arms)) = 210 (match_expr.expr(), match_expr.match_arm_list())
212 (match_expr.expr(), match_expr.match_arm_list()) 211 {
213 { 212 self.sink.push(MissingMatchArms {
214 self.sink.push(MissingMatchArms { 213 file: source_ptr.file_id,
215 file: source_ptr.file_id, 214 match_expr: AstPtr::new(&match_expr),
216 match_expr: AstPtr::new(&match_expr), 215 arms: AstPtr::new(&arms),
217 arms: AstPtr::new(&arms), 216 })
218 })
219 }
220 } 217 }
221 } 218 }
222 } 219 }
@@ -247,9 +244,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
247 let (_, source_map) = db.body_with_source_map(self.func.into()); 244 let (_, source_map) = db.body_with_source_map(self.func.into());
248 245
249 if let Ok(source_ptr) = source_map.expr_syntax(id) { 246 if let Ok(source_ptr) = source_map.expr_syntax(id) {
250 if let Some(expr) = source_ptr.value.left() { 247 self.sink
251 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); 248 .push(MissingOkInTailExpr { file: source_ptr.file_id, expr: source_ptr.value });
252 }
253 } 249 }
254 } 250 }
255 } 251 }
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 078476f76..8ec4d4ace 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -85,7 +85,7 @@ impl<'a> InferenceContext<'a> {
85 let body = Arc::clone(&self.body); // avoid borrow checker problem 85 let body = Arc::clone(&self.body); // avoid borrow checker problem
86 86
87 let is_non_ref_pat = match &body[pat] { 87 let is_non_ref_pat = match &body[pat] {
88 Pat::Tuple(..) 88 Pat::Tuple { .. }
89 | Pat::Or(..) 89 | Pat::Or(..)
90 | Pat::TupleStruct { .. } 90 | Pat::TupleStruct { .. }
91 | Pat::Record { .. } 91 | Pat::Record { .. }
@@ -116,7 +116,7 @@ impl<'a> InferenceContext<'a> {
116 let expected = expected; 116 let expected = expected;
117 117
118 let ty = match &body[pat] { 118 let ty = match &body[pat] {
119 Pat::Tuple(ref args) => { 119 Pat::Tuple { ref args, .. } => {
120 let expectations = match expected.as_tuple() { 120 let expectations = match expected.as_tuple() {
121 Some(parameters) => &*parameters.0, 121 Some(parameters) => &*parameters.0,
122 _ => &[], 122 _ => &[],
@@ -155,7 +155,7 @@ impl<'a> InferenceContext<'a> {
155 let subty = self.infer_pat(*pat, expectation, default_bm); 155 let subty = self.infer_pat(*pat, expectation, default_bm);
156 Ty::apply_one(TypeCtor::Ref(*mutability), subty) 156 Ty::apply_one(TypeCtor::Ref(*mutability), subty)
157 } 157 }
158 Pat::TupleStruct { path: p, args: subpats } => { 158 Pat::TupleStruct { path: p, args: subpats, .. } => {
159 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat) 159 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm, pat)
160 } 160 }
161 Pat::Record { path: p, args: fields, ellipsis: _ } => { 161 Pat::Record { path: p, args: fields, ellipsis: _ } => {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 6c7bbc448..cc1ac8e3e 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -8,6 +8,8 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use smallvec::SmallVec;
12
11use hir_def::{ 13use hir_def::{
12 adt::StructKind, 14 adt::StructKind,
13 builtin_type::BuiltinType, 15 builtin_type::BuiltinType,
@@ -360,13 +362,23 @@ impl Ty {
360 }, 362 },
361 Some(TypeNs::GenericParam(param_id)) => { 363 Some(TypeNs::GenericParam(param_id)) => {
362 let predicates = ctx.db.generic_predicates_for_param(param_id); 364 let predicates = ctx.db.generic_predicates_for_param(param_id);
363 predicates 365 let mut traits_: Vec<_> = predicates
364 .iter() 366 .iter()
365 .filter_map(|pred| match &pred.value { 367 .filter_map(|pred| match &pred.value {
366 GenericPredicate::Implemented(tr) => Some(tr.trait_), 368 GenericPredicate::Implemented(tr) => Some(tr.trait_),
367 _ => None, 369 _ => None,
368 }) 370 })
369 .collect() 371 .collect();
372 // Handle `Self::Type` referring to own associated type in trait definitions
373 if let GenericDefId::TraitId(trait_id) = param_id.parent {
374 let generics = generics(ctx.db.upcast(), trait_id.into());
375 if generics.params.types[param_id.local_id].provenance
376 == TypeParamProvenance::TraitSelf
377 {
378 traits_.push(trait_id);
379 }
380 }
381 traits_
370 } 382 }
371 _ => return Ty::Unknown, 383 _ => return Ty::Unknown,
372 }; 384 };
@@ -596,21 +608,35 @@ fn assoc_type_bindings_from_type_bound<'a>(
596 .into_iter() 608 .into_iter()
597 .flat_map(|segment| segment.args_and_bindings.into_iter()) 609 .flat_map(|segment| segment.args_and_bindings.into_iter())
598 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) 610 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
599 .map(move |(name, type_ref)| { 611 .flat_map(move |binding| {
600 let associated_ty = associated_type_by_name_including_super_traits( 612 let associated_ty = associated_type_by_name_including_super_traits(
601 ctx.db.upcast(), 613 ctx.db.upcast(),
602 trait_ref.trait_, 614 trait_ref.trait_,
603 &name, 615 &binding.name,
604 ); 616 );
605 let associated_ty = match associated_ty { 617 let associated_ty = match associated_ty {
606 None => return GenericPredicate::Error, 618 None => return SmallVec::<[GenericPredicate; 1]>::new(),
607 Some(t) => t, 619 Some(t) => t,
608 }; 620 };
609 let projection_ty = 621 let projection_ty =
610 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; 622 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
611 let ty = Ty::from_hir(ctx, type_ref); 623 let mut preds = SmallVec::with_capacity(
612 let projection_predicate = ProjectionPredicate { projection_ty, ty }; 624 binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
613 GenericPredicate::Projection(projection_predicate) 625 );
626 if let Some(type_ref) = &binding.type_ref {
627 let ty = Ty::from_hir(ctx, type_ref);
628 let projection_predicate =
629 ProjectionPredicate { projection_ty: projection_ty.clone(), ty };
630 preds.push(GenericPredicate::Projection(projection_predicate));
631 }
632 for bound in &binding.bounds {
633 preds.extend(GenericPredicate::from_type_bound(
634 ctx,
635 bound,
636 Ty::Projection(projection_ty.clone()),
637 ));
638 }
639 preds
614 }) 640 })
615} 641}
616 642
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index 74a0bc7db..657284fd0 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -34,7 +34,7 @@ impl TyFingerprint {
34 /// Creates a TyFingerprint for looking up an impl. Only certain types can 34 /// Creates a TyFingerprint for looking up an impl. Only certain types can
35 /// have impls: if we have some `struct S`, we can have an `impl S`, but not 35 /// have impls: if we have some `struct S`, we can have an `impl S`, but not
36 /// `impl &S`. Hence, this will return `None` for reference types and such. 36 /// `impl &S`. Hence, this will return `None` for reference types and such.
37 fn for_impl(ty: &Ty) -> Option<TyFingerprint> { 37 pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
38 match ty { 38 match ty {
39 Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)), 39 Ty::Apply(a_ty) => Some(TyFingerprint::Apply(a_ty.ctor)),
40 _ => None, 40 _ => None,
@@ -45,7 +45,7 @@ impl TyFingerprint {
45#[derive(Debug, PartialEq, Eq)] 45#[derive(Debug, PartialEq, Eq)]
46pub struct CrateImplDefs { 46pub struct CrateImplDefs {
47 impls: FxHashMap<TyFingerprint, Vec<ImplId>>, 47 impls: FxHashMap<TyFingerprint, Vec<ImplId>>,
48 impls_by_trait: FxHashMap<TraitId, Vec<ImplId>>, 48 impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>,
49} 49}
50 50
51impl CrateImplDefs { 51impl CrateImplDefs {
@@ -59,7 +59,14 @@ impl CrateImplDefs {
59 for impl_id in module_data.scope.impls() { 59 for impl_id in module_data.scope.impls() {
60 match db.impl_trait(impl_id) { 60 match db.impl_trait(impl_id) {
61 Some(tr) => { 61 Some(tr) => {
62 res.impls_by_trait.entry(tr.value.trait_).or_default().push(impl_id); 62 let self_ty = db.impl_self_ty(impl_id);
63 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value);
64 res.impls_by_trait
65 .entry(tr.value.trait_)
66 .or_default()
67 .entry(self_ty_fp)
68 .or_default()
69 .push(impl_id);
63 } 70 }
64 None => { 71 None => {
65 let self_ty = db.impl_self_ty(impl_id); 72 let self_ty = db.impl_self_ty(impl_id);
@@ -79,11 +86,39 @@ impl CrateImplDefs {
79 } 86 }
80 87
81 pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { 88 pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ {
82 self.impls_by_trait.get(&tr).into_iter().flatten().copied() 89 self.impls_by_trait
90 .get(&tr)
91 .into_iter()
92 .flat_map(|m| m.values().flat_map(|v| v.iter().copied()))
93 }
94
95 pub fn lookup_impl_defs_for_trait_and_ty(
96 &self,
97 tr: TraitId,
98 fp: TyFingerprint,
99 ) -> impl Iterator<Item = ImplId> + '_ {
100 self.impls_by_trait
101 .get(&tr)
102 .and_then(|m| m.get(&Some(fp)))
103 .into_iter()
104 .flatten()
105 .copied()
106 .chain(
107 self.impls_by_trait
108 .get(&tr)
109 .and_then(|m| m.get(&None))
110 .into_iter()
111 .flatten()
112 .copied(),
113 )
83 } 114 }
84 115
85 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { 116 pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a {
86 self.impls.values().chain(self.impls_by_trait.values()).flatten().copied() 117 self.impls
118 .values()
119 .chain(self.impls_by_trait.values().flat_map(|m| m.values()))
120 .flatten()
121 .copied()
87 } 122 }
88} 123}
89 124
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index 54e31602f..81fc0f63a 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -82,9 +82,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
82 82
83 for (expr, ty) in inference_result.type_of_expr.iter() { 83 for (expr, ty) in inference_result.type_of_expr.iter() {
84 let syntax_ptr = match body_source_map.expr_syntax(expr) { 84 let syntax_ptr = match body_source_map.expr_syntax(expr) {
85 Ok(sp) => { 85 Ok(sp) => sp.map(|ast| ast.syntax_node_ptr()),
86 sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
87 }
88 Err(SyntheticSyntax) => continue, 86 Err(SyntheticSyntax) => continue,
89 }; 87 };
90 types.push((syntax_ptr.clone(), ty)); 88 types.push((syntax_ptr.clone(), ty));
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
index 6e5d2247c..07cbc521a 100644
--- a/crates/ra_hir_ty/src/tests/patterns.rs
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -1,7 +1,8 @@
1use super::{infer, infer_with_mismatches};
2use insta::assert_snapshot; 1use insta::assert_snapshot;
3use test_utils::covers; 2use test_utils::covers;
4 3
4use super::{infer, infer_with_mismatches};
5
5#[test] 6#[test]
6fn infer_pattern() { 7fn infer_pattern() {
7 assert_snapshot!( 8 assert_snapshot!(
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
index 3402e0cb5..d69115a2f 100644
--- a/crates/ra_hir_ty/src/tests/regression.rs
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -451,8 +451,7 @@ pub mod str {
451"#, 451"#,
452 ); 452 );
453 453
454 // should be Option<char>, but currently not because of Chalk ambiguity problem 454 assert_eq!("(Option<char>, Option<char>)", super::type_at_pos(&db, pos));
455 assert_eq!("(Option<{unknown}>, Option<{unknown}>)", super::type_at_pos(&db, pos));
456} 455}
457 456
458#[test] 457#[test]
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 22ae6ca90..b3a2fc439 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1803,7 +1803,7 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
1803} 1803}
1804 1804
1805#[test] 1805#[test]
1806fn unselected_projection_on_trait_self() { 1806fn unselected_projection_on_impl_self() {
1807 assert_snapshot!(infer( 1807 assert_snapshot!(infer(
1808 r#" 1808 r#"
1809//- /main.rs 1809//- /main.rs
@@ -1844,6 +1844,30 @@ impl Trait for S2 {
1844} 1844}
1845 1845
1846#[test] 1846#[test]
1847fn unselected_projection_on_trait_self() {
1848 let t = type_at(
1849 r#"
1850//- /main.rs
1851trait Trait {
1852 type Item;
1853
1854 fn f(&self) -> Self::Item { loop {} }
1855}
1856
1857struct S;
1858impl Trait for S {
1859 type Item = u32;
1860}
1861
1862fn test() {
1863 S.f()<|>;
1864}
1865"#,
1866 );
1867 assert_eq!(t, "u32");
1868}
1869
1870#[test]
1847fn trait_impl_self_ty() { 1871fn trait_impl_self_ty() {
1848 let t = type_at( 1872 let t = type_at(
1849 r#" 1873 r#"
@@ -1924,6 +1948,53 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
1924} 1948}
1925 1949
1926#[test] 1950#[test]
1951fn inline_assoc_type_bounds_1() {
1952 let t = type_at(
1953 r#"
1954//- /main.rs
1955trait Iterator {
1956 type Item;
1957}
1958trait OtherTrait<T> {
1959 fn foo(&self) -> T;
1960}
1961
1962// workaround for Chalk assoc type normalization problems
1963pub struct S<T>;
1964impl<T: Iterator> Iterator for S<T> {
1965 type Item = <T as Iterator>::Item;
1966}
1967
1968fn test<I: Iterator<Item: OtherTrait<u32>>>() {
1969 let x: <S<I> as Iterator>::Item;
1970 x.foo()<|>;
1971}
1972"#,
1973 );
1974 assert_eq!(t, "u32");
1975}
1976
1977#[test]
1978fn inline_assoc_type_bounds_2() {
1979 let t = type_at(
1980 r#"
1981//- /main.rs
1982trait Iterator {
1983 type Item;
1984}
1985
1986fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
1987 let x: <<I as Iterator>::Item as Iterator>::Item;
1988 x<|>;
1989}
1990"#,
1991 );
1992 // assert_eq!(t, "u32");
1993 // doesn't currently work, Chalk #234
1994 assert_eq!(t, "{unknown}");
1995}
1996
1997#[test]
1927fn unify_impl_trait() { 1998fn unify_impl_trait() {
1928 assert_snapshot!( 1999 assert_snapshot!(
1929 infer_with_mismatches(r#" 2000 infer_with_mismatches(r#"
@@ -2023,6 +2094,33 @@ fn main() {
2023} 2094}
2024 2095
2025#[test] 2096#[test]
2097fn associated_type_bound() {
2098 let t = type_at(
2099 r#"
2100//- /main.rs
2101pub trait Trait {
2102 type Item: OtherTrait<u32>;
2103}
2104pub trait OtherTrait<T> {
2105 fn foo(&self) -> T;
2106}
2107
2108// this is just a workaround for chalk#234
2109pub struct S<T>;
2110impl<T: Trait> Trait for S<T> {
2111 type Item = <T as Trait>::Item;
2112}
2113
2114fn test<T: Trait>() {
2115 let y: <S<T> as Trait>::Item = no_matter;
2116 y.foo()<|>;
2117}
2118"#,
2119 );
2120 assert_eq!(t, "u32");
2121}
2122
2123#[test]
2026fn dyn_trait_through_chalk() { 2124fn dyn_trait_through_chalk() {
2027 let t = type_at( 2125 let t = type_at(
2028 r#" 2126 r#"
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 21e233379..44fbdb197 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -7,7 +7,7 @@ use ra_db::{impl_intern_key, salsa, CrateId};
7use ra_prof::profile; 7use ra_prof::profile;
8use rustc_hash::FxHashSet; 8use rustc_hash::FxHashSet;
9 9
10use crate::{db::HirDatabase, DebruijnIndex}; 10use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex};
11 11
12use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 12use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
13 13
@@ -40,7 +40,12 @@ pub(crate) fn impls_for_trait_query(
40 db: &dyn HirDatabase, 40 db: &dyn HirDatabase,
41 krate: CrateId, 41 krate: CrateId,
42 trait_: TraitId, 42 trait_: TraitId,
43 self_ty_fp: Option<TyFingerprint>,
43) -> Arc<[ImplId]> { 44) -> Arc<[ImplId]> {
45 // FIXME: We could be a lot smarter here - because of the orphan rules and
46 // the fact that the trait and the self type need to be in the dependency
47 // tree of a crate somewhere for an impl to exist, we could skip looking in
48 // a lot of crates completely
44 let mut impls = FxHashSet::default(); 49 let mut impls = FxHashSet::default();
45 // We call the query recursively here. On the one hand, this means we can 50 // We call the query recursively here. On the one hand, this means we can
46 // reuse results from queries for different crates; on the other hand, this 51 // reuse results from queries for different crates; on the other hand, this
@@ -48,10 +53,13 @@ pub(crate) fn impls_for_trait_query(
48 // ones the user is editing), so this may actually be a waste of memory. I'm 53 // ones the user is editing), so this may actually be a waste of memory. I'm
49 // doing it like this mainly for simplicity for now. 54 // doing it like this mainly for simplicity for now.
50 for dep in &db.crate_graph()[krate].dependencies { 55 for dep in &db.crate_graph()[krate].dependencies {
51 impls.extend(db.impls_for_trait(dep.crate_id, trait_).iter()); 56 impls.extend(db.impls_for_trait(dep.crate_id, trait_, self_ty_fp).iter());
52 } 57 }
53 let crate_impl_defs = db.impls_in_crate(krate); 58 let crate_impl_defs = db.impls_in_crate(krate);
54 impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)); 59 match self_ty_fp {
60 Some(fp) => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp)),
61 None => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)),
62 }
55 impls.into_iter().collect() 63 impls.into_iter().collect()
56} 64}
57 65
@@ -186,13 +194,16 @@ fn solve(
186 } 194 }
187 remaining > 0 195 remaining > 0
188 }; 196 };
189 let mut solve = || solver.solve_limited(&context, goal, should_continue); 197 let mut solve = || {
198 let solution = solver.solve_limited(&context, goal, should_continue);
199 log::debug!("solve({:?}) => {:?}", goal, solution);
200 solution
201 };
190 // don't set the TLS for Chalk unless Chalk debugging is active, to make 202 // don't set the TLS for Chalk unless Chalk debugging is active, to make
191 // extra sure we only use it for debugging 203 // extra sure we only use it for debugging
192 let solution = 204 let solution =
193 if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; 205 if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() };
194 206
195 log::debug!("solve({:?}) => {:?}", goal, solution);
196 solution 207 solution
197} 208}
198 209
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index c5f1b5232..55eb0ffcb 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -16,8 +16,8 @@ use ra_db::{
16 16
17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 17use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
18use crate::{ 18use crate::{
19 db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate, 19 db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics,
20 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 20 ApplicationTy, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
21}; 21};
22 22
23pub(super) mod tls; 23pub(super) mod tls;
@@ -32,6 +32,9 @@ impl chalk_ir::interner::Interner for Interner {
32 type InternedGoal = Arc<GoalData<Self>>; 32 type InternedGoal = Arc<GoalData<Self>>;
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>;
36 type InternedProgramClauses = Vec<chalk_ir::ProgramClause<Self>>;
37 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>;
35 type Identifier = TypeAliasId; 38 type Identifier = TypeAliasId;
36 type DefId = InternId; 39 type DefId = InternId;
37 40
@@ -181,6 +184,48 @@ impl chalk_ir::interner::Interner for Interner {
181 ) -> &'a [Parameter<Self>] { 184 ) -> &'a [Parameter<Self>] {
182 substitution 185 substitution
183 } 186 }
187
188 fn intern_program_clause(
189 &self,
190 data: chalk_ir::ProgramClauseData<Self>,
191 ) -> chalk_ir::ProgramClauseData<Self> {
192 data
193 }
194
195 fn program_clause_data<'a>(
196 &self,
197 clause: &'a chalk_ir::ProgramClauseData<Self>,
198 ) -> &'a chalk_ir::ProgramClauseData<Self> {
199 clause
200 }
201
202 fn intern_program_clauses(
203 &self,
204 data: impl IntoIterator<Item = chalk_ir::ProgramClause<Self>>,
205 ) -> Vec<chalk_ir::ProgramClause<Self>> {
206 data.into_iter().collect()
207 }
208
209 fn program_clauses_data<'a>(
210 &self,
211 clauses: &'a Vec<chalk_ir::ProgramClause<Self>>,
212 ) -> &'a [chalk_ir::ProgramClause<Self>] {
213 clauses
214 }
215
216 fn intern_quantified_where_clauses(
217 &self,
218 data: impl IntoIterator<Item = chalk_ir::QuantifiedWhereClause<Self>>,
219 ) -> Self::InternedQuantifiedWhereClauses {
220 data.into_iter().collect()
221 }
222
223 fn quantified_where_clauses_data<'a>(
224 &self,
225 clauses: &'a Self::InternedQuantifiedWhereClauses,
226 ) -> &'a [chalk_ir::QuantifiedWhereClause<Self>] {
227 clauses
228 }
184} 229}
185 230
186impl chalk_ir::interner::HasInterner for Interner { 231impl chalk_ir::interner::HasInterner for Interner {
@@ -238,12 +283,10 @@ impl ToChalk for Ty {
238 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner), 283 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx).intern(&Interner),
239 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 284 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
240 Ty::Dyn(predicates) => { 285 Ty::Dyn(predicates) => {
241 let where_clauses = predicates 286 let where_clauses = chalk_ir::QuantifiedWhereClauses::from(
242 .iter() 287 &Interner,
243 .filter(|p| !p.is_error()) 288 predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)),
244 .cloned() 289 );
245 .map(|p| p.to_chalk(db))
246 .collect();
247 let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) }; 290 let bounded_ty = chalk_ir::DynTy { bounds: make_binders(where_clauses, 1) };
248 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner) 291 chalk_ir::TyData::Dyn(bounded_ty).intern(&Interner)
249 } 292 }
@@ -281,8 +324,12 @@ impl ToChalk for Ty {
281 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, 324 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
282 chalk_ir::TyData::Dyn(where_clauses) => { 325 chalk_ir::TyData::Dyn(where_clauses) => {
283 assert_eq!(where_clauses.bounds.binders.len(), 1); 326 assert_eq!(where_clauses.bounds.binders.len(), 1);
284 let predicates = 327 let predicates = where_clauses
285 where_clauses.bounds.value.into_iter().map(|c| from_chalk(db, c)).collect(); 328 .bounds
329 .skip_binders()
330 .iter(&Interner)
331 .map(|c| from_chalk(db, c.clone()))
332 .collect();
286 Ty::Dyn(predicates) 333 Ty::Dyn(predicates)
287 } 334 }
288 } 335 }
@@ -426,7 +473,7 @@ impl ToChalk for GenericPredicate {
426 ) -> GenericPredicate { 473 ) -> GenericPredicate {
427 // we don't produce any where clauses with binders and can't currently deal with them 474 // we don't produce any where clauses with binders and can't currently deal with them
428 match where_clause 475 match where_clause
429 .value 476 .skip_binders()
430 .shifted_out(&Interner) 477 .shifted_out(&Interner)
431 .expect("unexpected bound vars in where clause") 478 .expect("unexpected bound vars in where clause")
432 { 479 {
@@ -521,7 +568,7 @@ impl ToChalk for Arc<super::TraitEnvironment> {
521 pred.clone().to_chalk(db).cast(&Interner); 568 pred.clone().to_chalk(db).cast(&Interner);
522 clauses.push(program_clause.into_from_env_clause(&Interner)); 569 clauses.push(program_clause.into_from_env_clause(&Interner));
523 } 570 }
524 chalk_ir::Environment::new().add_clauses(clauses) 571 chalk_ir::Environment::new(&Interner).add_clauses(&Interner, clauses)
525 } 572 }
526 573
527 fn from_chalk( 574 fn from_chalk(
@@ -603,10 +650,10 @@ impl ToChalk for builtin::BuiltinImplAssocTyValueData {
603} 650}
604 651
605fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 652fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
606 chalk_ir::Binders { 653 chalk_ir::Binders::new(
654 std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(),
607 value, 655 value,
608 binders: std::iter::repeat(chalk_ir::ParameterKind::Ty(())).take(num_vars).collect(), 656 )
609 }
610} 657}
611 658
612fn convert_where_clauses( 659fn convert_where_clauses(
@@ -626,6 +673,55 @@ fn convert_where_clauses(
626 result 673 result
627} 674}
628 675
676fn generic_predicate_to_inline_bound(
677 db: &dyn HirDatabase,
678 pred: &GenericPredicate,
679 self_ty: &Ty,
680) -> Option<chalk_rust_ir::InlineBound<Interner>> {
681 // An InlineBound is like a GenericPredicate, except the self type is left out.
682 // We don't have a special type for this, but Chalk does.
683 match pred {
684 GenericPredicate::Implemented(trait_ref) => {
685 if &trait_ref.substs[0] != self_ty {
686 // we can only convert predicates back to type bounds if they
687 // have the expected self type
688 return None;
689 }
690 let args_no_self = trait_ref.substs[1..]
691 .iter()
692 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
693 .collect();
694 let trait_bound =
695 chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self };
696 Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound))
697 }
698 GenericPredicate::Projection(proj) => {
699 if &proj.projection_ty.parameters[0] != self_ty {
700 return None;
701 }
702 let trait_ = match proj.projection_ty.associated_ty.lookup(db.upcast()).container {
703 AssocContainerId::TraitId(t) => t,
704 _ => panic!("associated type not in trait"),
705 };
706 let args_no_self = proj.projection_ty.parameters[1..]
707 .iter()
708 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
709 .collect();
710 let alias_eq_bound = chalk_rust_ir::AliasEqBound {
711 value: proj.ty.clone().to_chalk(db),
712 trait_bound: chalk_rust_ir::TraitBound {
713 trait_id: trait_.to_chalk(db),
714 args_no_self,
715 },
716 associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db),
717 parameters: Vec::new(), // FIXME we don't support generic associated types yet
718 };
719 Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound))
720 }
721 GenericPredicate::Error => None,
722 }
723}
724
629impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { 725impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
630 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { 726 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> {
631 self.db.associated_ty_data(id) 727 self.db.associated_ty_data(id)
@@ -647,19 +743,22 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
647 debug!("impls_for_trait {:?}", trait_id); 743 debug!("impls_for_trait {:?}", trait_id);
648 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 744 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
649 745
746 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
747
748 let self_ty_fp = TyFingerprint::for_impl(&ty);
749
650 // Note: Since we're using impls_for_trait, only impls where the trait 750 // Note: Since we're using impls_for_trait, only impls where the trait
651 // can be resolved should ever reach Chalk. `impl_datum` relies on that 751 // can be resolved should ever reach Chalk. `impl_datum` relies on that
652 // and will panic if the trait can't be resolved. 752 // and will panic if the trait can't be resolved.
653 let mut result: Vec<_> = self 753 let mut result: Vec<_> = self
654 .db 754 .db
655 .impls_for_trait(self.krate, trait_) 755 .impls_for_trait(self.krate, trait_, self_ty_fp)
656 .iter() 756 .iter()
657 .copied() 757 .copied()
658 .map(Impl::ImplDef) 758 .map(Impl::ImplDef)
659 .map(|impl_| impl_.to_chalk(self.db)) 759 .map(|impl_| impl_.to_chalk(self.db))
660 .collect(); 760 .collect();
661 761
662 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone());
663 let arg: Option<Ty> = 762 let arg: Option<Ty> =
664 parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); 763 parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone()));
665 764
@@ -693,6 +792,12 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
693 fn interner(&self) -> &Interner { 792 fn interner(&self) -> &Interner {
694 &Interner 793 &Interner
695 } 794 }
795 fn well_known_trait_id(
796 &self,
797 _well_known_trait: chalk_rust_ir::WellKnownTrait,
798 ) -> chalk_ir::TraitId<Interner> {
799 unimplemented!()
800 }
696} 801}
697 802
698pub(crate) fn associated_ty_data_query( 803pub(crate) fn associated_ty_data_query(
@@ -705,12 +810,25 @@ pub(crate) fn associated_ty_data_query(
705 AssocContainerId::TraitId(t) => t, 810 AssocContainerId::TraitId(t) => t,
706 _ => panic!("associated type not in trait"), 811 _ => panic!("associated type not in trait"),
707 }; 812 };
813
814 // Lower bounds -- we could/should maybe move this to a separate query in `lower`
815 let type_alias_data = db.type_alias_data(type_alias);
708 let generic_params = generics(db.upcast(), type_alias.into()); 816 let generic_params = generics(db.upcast(), type_alias.into());
709 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { 817 let bound_vars = Substs::bound_vars(&generic_params);
710 // FIXME add bounds and where clauses 818 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
711 bounds: vec![], 819 let ctx = crate::TyLoweringContext::new(db, &resolver)
712 where_clauses: vec![], 820 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
713 }; 821 let self_ty = Ty::Bound(crate::BoundVar::new(crate::DebruijnIndex::INNERMOST, 0));
822 let bounds = type_alias_data
823 .bounds
824 .iter()
825 .flat_map(|bound| GenericPredicate::from_type_bound(&ctx, bound, self_ty.clone()))
826 .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty))
827 .map(|bound| make_binders(bound.shifted_in(&Interner), 0))
828 .collect();
829
830 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
831 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { bounds, where_clauses };
714 let datum = AssociatedTyDatum { 832 let datum = AssociatedTyDatum {
715 trait_id: trait_.to_chalk(db), 833 trait_id: trait_.to_chalk(db),
716 id, 834 id,
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs
index d9bbb54a5..fa8e4d1ad 100644
--- a/crates/ra_hir_ty/src/traits/chalk/tls.rs
+++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs
@@ -2,10 +2,11 @@
2use std::fmt; 2use std::fmt;
3 3
4use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; 4use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName};
5use itertools::Itertools;
5 6
6use super::{from_chalk, Interner}; 7use super::{from_chalk, Interner};
7use crate::{db::HirDatabase, CallableDef, TypeCtor}; 8use crate::{db::HirDatabase, CallableDef, TypeCtor};
8use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId}; 9use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId};
9 10
10pub use unsafe_tls::{set_current_program, with_current_program}; 11pub use unsafe_tls::{set_current_program, with_current_program};
11 12
@@ -69,7 +70,27 @@ impl DebugContext<'_> {
69 write!(f, "{}::{}", trait_name, name)?; 70 write!(f, "{}::{}", trait_name, name)?;
70 } 71 }
71 TypeCtor::Closure { def, expr } => { 72 TypeCtor::Closure { def, expr } => {
72 write!(f, "{{closure {:?} in {:?}}}", expr.into_raw(), def)?; 73 write!(f, "{{closure {:?} in ", expr.into_raw())?;
74 match def {
75 DefWithBodyId::FunctionId(func) => {
76 write!(f, "fn {}", self.0.function_data(func).name)?
77 }
78 DefWithBodyId::StaticId(s) => {
79 if let Some(name) = self.0.static_data(s).name.as_ref() {
80 write!(f, "body of static {}", name)?;
81 } else {
82 write!(f, "body of unnamed static {:?}", s)?;
83 }
84 }
85 DefWithBodyId::ConstId(c) => {
86 if let Some(name) = self.0.const_data(c).name.as_ref() {
87 write!(f, "body of const {}", name)?;
88 } else {
89 write!(f, "body of unnamed const {:?}", c)?;
90 }
91 }
92 };
93 write!(f, "}}")?;
73 } 94 }
74 } 95 }
75 Ok(()) 96 Ok(())
@@ -113,14 +134,15 @@ impl DebugContext<'_> {
113 }; 134 };
114 let trait_data = self.0.trait_data(trait_); 135 let trait_data = self.0.trait_data(trait_);
115 let params = alias.substitution.parameters(&Interner); 136 let params = alias.substitution.parameters(&Interner);
116 write!( 137 write!(fmt, "<{:?} as {}", &params[0], trait_data.name,)?;
117 fmt, 138 if params.len() > 1 {
118 "<{:?} as {}<{:?}>>::{}", 139 write!(
119 &params[0], 140 fmt,
120 trait_data.name, 141 "<{}>",
121 &params[1..], 142 &params[1..].iter().format_with(", ", |x, f| f(&format_args!("{:?}", x))),
122 type_alias_data.name 143 )?;
123 ) 144 }
145 write!(fmt, ">::{}", type_alias_data.name)
124 } 146 }
125 147
126 pub fn debug_ty( 148 pub fn debug_ty(