diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/_match.rs | 350 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/db.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/expr.rs | 68 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/pat.rs | 6 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 45 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/patterns.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/regression.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 100 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 162 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk/tls.rs | 42 |
13 files changed, 735 insertions, 120 deletions
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 { | |||
644 | fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Option<Constructor>> { | 674 | fn 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}; | |||
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | 12 | ||
13 | use crate::{ | 13 | use 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 @@ | |||
8 | use std::iter; | 8 | use std::iter; |
9 | use std::sync::Arc; | 9 | use std::sync::Arc; |
10 | 10 | ||
11 | use smallvec::SmallVec; | ||
12 | |||
11 | use hir_def::{ | 13 | use 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)] |
46 | pub struct CrateImplDefs { | 46 | pub 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 | ||
51 | impl CrateImplDefs { | 51 | impl 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 @@ | |||
1 | use super::{infer, infer_with_mismatches}; | ||
2 | use insta::assert_snapshot; | 1 | use insta::assert_snapshot; |
3 | use test_utils::covers; | 2 | use test_utils::covers; |
4 | 3 | ||
4 | use super::{infer, infer_with_mismatches}; | ||
5 | |||
5 | #[test] | 6 | #[test] |
6 | fn infer_pattern() { | 7 | fn 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] |
1806 | fn unselected_projection_on_trait_self() { | 1806 | fn 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] |
1847 | fn unselected_projection_on_trait_self() { | ||
1848 | let t = type_at( | ||
1849 | r#" | ||
1850 | //- /main.rs | ||
1851 | trait Trait { | ||
1852 | type Item; | ||
1853 | |||
1854 | fn f(&self) -> Self::Item { loop {} } | ||
1855 | } | ||
1856 | |||
1857 | struct S; | ||
1858 | impl Trait for S { | ||
1859 | type Item = u32; | ||
1860 | } | ||
1861 | |||
1862 | fn test() { | ||
1863 | S.f()<|>; | ||
1864 | } | ||
1865 | "#, | ||
1866 | ); | ||
1867 | assert_eq!(t, "u32"); | ||
1868 | } | ||
1869 | |||
1870 | #[test] | ||
1847 | fn trait_impl_self_ty() { | 1871 | fn 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] |
1951 | fn inline_assoc_type_bounds_1() { | ||
1952 | let t = type_at( | ||
1953 | r#" | ||
1954 | //- /main.rs | ||
1955 | trait Iterator { | ||
1956 | type Item; | ||
1957 | } | ||
1958 | trait OtherTrait<T> { | ||
1959 | fn foo(&self) -> T; | ||
1960 | } | ||
1961 | |||
1962 | // workaround for Chalk assoc type normalization problems | ||
1963 | pub struct S<T>; | ||
1964 | impl<T: Iterator> Iterator for S<T> { | ||
1965 | type Item = <T as Iterator>::Item; | ||
1966 | } | ||
1967 | |||
1968 | fn 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] | ||
1978 | fn inline_assoc_type_bounds_2() { | ||
1979 | let t = type_at( | ||
1980 | r#" | ||
1981 | //- /main.rs | ||
1982 | trait Iterator { | ||
1983 | type Item; | ||
1984 | } | ||
1985 | |||
1986 | fn 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] | ||
1927 | fn unify_impl_trait() { | 1998 | fn 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] |
2097 | fn associated_type_bound() { | ||
2098 | let t = type_at( | ||
2099 | r#" | ||
2100 | //- /main.rs | ||
2101 | pub trait Trait { | ||
2102 | type Item: OtherTrait<u32>; | ||
2103 | } | ||
2104 | pub trait OtherTrait<T> { | ||
2105 | fn foo(&self) -> T; | ||
2106 | } | ||
2107 | |||
2108 | // this is just a workaround for chalk#234 | ||
2109 | pub struct S<T>; | ||
2110 | impl<T: Trait> Trait for S<T> { | ||
2111 | type Item = <T as Trait>::Item; | ||
2112 | } | ||
2113 | |||
2114 | fn 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] | ||
2026 | fn dyn_trait_through_chalk() { | 2124 | fn 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}; | |||
7 | use ra_prof::profile; | 7 | use ra_prof::profile; |
8 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
9 | 9 | ||
10 | use crate::{db::HirDatabase, DebruijnIndex}; | 10 | use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex}; |
11 | 11 | ||
12 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 12 | use 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 | ||
17 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; | 17 | use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; |
18 | use crate::{ | 18 | use 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 | ||
23 | pub(super) mod tls; | 23 | pub(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 | ||
186 | impl chalk_ir::interner::HasInterner for Interner { | 231 | impl 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 | ||
605 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | 652 | fn 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 | ||
612 | fn convert_where_clauses( | 659 | fn convert_where_clauses( |
@@ -626,6 +673,55 @@ fn convert_where_clauses( | |||
626 | result | 673 | result |
627 | } | 674 | } |
628 | 675 | ||
676 | fn 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 | |||
629 | impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | 725 | impl<'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 | ||
698 | pub(crate) fn associated_ty_data_query( | 803 | pub(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 @@ | |||
2 | use std::fmt; | 2 | use std::fmt; |
3 | 3 | ||
4 | use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; | 4 | use chalk_ir::{AliasTy, Goal, Goals, Lifetime, Parameter, ProgramClauseImplication, TypeName}; |
5 | use itertools::Itertools; | ||
5 | 6 | ||
6 | use super::{from_chalk, Interner}; | 7 | use super::{from_chalk, Interner}; |
7 | use crate::{db::HirDatabase, CallableDef, TypeCtor}; | 8 | use crate::{db::HirDatabase, CallableDef, TypeCtor}; |
8 | use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId}; | 9 | use hir_def::{AdtId, AssocContainerId, DefWithBodyId, Lookup, TypeAliasId}; |
9 | 10 | ||
10 | pub use unsafe_tls::{set_current_program, with_current_program}; | 11 | pub 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 {}", ¶ms[0], trait_data.name,)?; |
117 | fmt, | 138 | if params.len() > 1 { |
118 | "<{:?} as {}<{:?}>>::{}", | 139 | write!( |
119 | ¶ms[0], | 140 | fmt, |
120 | trait_data.name, | 141 | "<{}>", |
121 | ¶ms[1..], | 142 | ¶ms[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( |