aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r--crates/ra_hir_ty/src/_match.rs160
-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/tests/regression.rs3
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs100
-rw-r--r--crates/ra_hir_ty/src/traits.rs7
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs151
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs42
8 files changed, 420 insertions, 91 deletions
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index c482cf619..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),
@@ -1507,6 +1541,67 @@ mod tests {
1507 } 1541 }
1508 1542
1509 #[test] 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]
1510 fn enum_tuple_ellipsis_no_diagnostic() { 1605 fn enum_tuple_ellipsis_no_diagnostic() {
1511 let content = r" 1606 let content = r"
1512 enum Either { 1607 enum Either {
@@ -1645,11 +1740,7 @@ mod false_negatives {
1645 "; 1740 ";
1646 1741
1647 // This is a false negative. 1742 // This is a false negative.
1648 // The `..` pattern is currently lowered to a single `Pat::Wild` 1743 // We don't currently handle tuple patterns with ellipsis.
1649 // no matter how many fields the `..` pattern is covering. This
1650 // causes the match arm in this test not to type check against
1651 // the match expression, which causes this diagnostic not to
1652 // fire.
1653 check_no_diagnostic(content); 1744 check_no_diagnostic(content);
1654 } 1745 }
1655 1746
@@ -1664,32 +1755,7 @@ mod false_negatives {
1664 "; 1755 ";
1665 1756
1666 // This is a false negative. 1757 // This is a false negative.
1667 // See comments on `tuple_of_bools_with_ellipsis_at_end_missing_arm`. 1758 // We don't currently handle tuple patterns with ellipsis.
1668 check_no_diagnostic(content);
1669 }
1670
1671 #[test]
1672 fn enum_tuple_partial_ellipsis_missing_arm() {
1673 let content = r"
1674 enum Either {
1675 A(bool, bool, bool, bool),
1676 B,
1677 }
1678 fn test_fn() {
1679 match Either::B {
1680 Either::A(true, .., true) => {},
1681 Either::A(true, .., false) => {},
1682 Either::A(false, .., false) => {},
1683 Either::B => {},
1684 }
1685 }
1686 ";
1687
1688 // This is a false negative.
1689 // The `..` pattern is currently lowered to a single `Pat::Wild`
1690 // no matter how many fields the `..` pattern is covering. This
1691 // causes us to return a `MatchCheckErr::MalformedMatchArm` in
1692 // `Pat::specialize_constructor`.
1693 check_no_diagnostic(content); 1759 check_no_diagnostic(content);
1694 } 1760 }
1695} 1761}
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/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 43d8d1e80..44fbdb197 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -194,13 +194,16 @@ fn solve(
194 } 194 }
195 remaining > 0 195 remaining > 0
196 }; 196 };
197 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 };
198 // 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
199 // extra sure we only use it for debugging 203 // extra sure we only use it for debugging
200 let solution = 204 let solution =
201 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() };
202 206
203 log::debug!("solve({:?}) => {:?}", goal, solution);
204 solution 207 solution
205} 208}
206 209
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index e05fea843..55eb0ffcb 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -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)
@@ -696,6 +792,12 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
696 fn interner(&self) -> &Interner { 792 fn interner(&self) -> &Interner {
697 &Interner 793 &Interner
698 } 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 }
699} 801}
700 802
701pub(crate) fn associated_ty_data_query( 803pub(crate) fn associated_ty_data_query(
@@ -708,12 +810,25 @@ pub(crate) fn associated_ty_data_query(
708 AssocContainerId::TraitId(t) => t, 810 AssocContainerId::TraitId(t) => t,
709 _ => panic!("associated type not in trait"), 811 _ => panic!("associated type not in trait"),
710 }; 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);
711 let generic_params = generics(db.upcast(), type_alias.into()); 816 let generic_params = generics(db.upcast(), type_alias.into());
712 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { 817 let bound_vars = Substs::bound_vars(&generic_params);
713 // FIXME add bounds and where clauses 818 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
714 bounds: vec![], 819 let ctx = crate::TyLoweringContext::new(db, &resolver)
715 where_clauses: vec![], 820 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
716 }; 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 };
717 let datum = AssociatedTyDatum { 832 let datum = AssociatedTyDatum {
718 trait_id: trait_.to_chalk(db), 833 trait_id: trait_.to_chalk(db),
719 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(