diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/autoderef.rs | 21 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/unify.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/regression.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 212 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 160 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk/tls.rs | 42 |
8 files changed, 423 insertions, 78 deletions
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs index d91c21e24..1b0f84c5c 100644 --- a/crates/ra_hir_ty/src/autoderef.rs +++ b/crates/ra_hir_ty/src/autoderef.rs | |||
@@ -14,7 +14,7 @@ use crate::{ | |||
14 | db::HirDatabase, | 14 | db::HirDatabase, |
15 | traits::{InEnvironment, Solution}, | 15 | traits::{InEnvironment, Solution}, |
16 | utils::generics, | 16 | utils::generics, |
17 | BoundVar, Canonical, DebruijnIndex, Substs, Ty, | 17 | BoundVar, Canonical, DebruijnIndex, Obligation, Substs, TraitRef, Ty, |
18 | }; | 18 | }; |
19 | 19 | ||
20 | const AUTODEREF_RECURSION_LIMIT: usize = 10; | 20 | const AUTODEREF_RECURSION_LIMIT: usize = 10; |
@@ -66,6 +66,20 @@ fn deref_by_trait( | |||
66 | let parameters = | 66 | let parameters = |
67 | Substs::build_for_generics(&generic_params).push(ty.value.value.clone()).build(); | 67 | Substs::build_for_generics(&generic_params).push(ty.value.value.clone()).build(); |
68 | 68 | ||
69 | // Check that the type implements Deref at all | ||
70 | let trait_ref = TraitRef { trait_: deref_trait, substs: parameters.clone() }; | ||
71 | let implements_goal = super::Canonical { | ||
72 | num_vars: ty.value.num_vars, | ||
73 | value: InEnvironment { | ||
74 | value: Obligation::Trait(trait_ref), | ||
75 | environment: ty.environment.clone(), | ||
76 | }, | ||
77 | }; | ||
78 | if db.trait_solve(krate, implements_goal).is_none() { | ||
79 | return None; | ||
80 | } | ||
81 | |||
82 | // Now do the assoc type projection | ||
69 | let projection = super::traits::ProjectionPredicate { | 83 | let projection = super::traits::ProjectionPredicate { |
70 | ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)), | 84 | ty: Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, ty.value.num_vars)), |
71 | projection_ty: super::ProjectionTy { associated_ty: target, parameters }, | 85 | projection_ty: super::ProjectionTy { associated_ty: target, parameters }, |
@@ -91,6 +105,11 @@ fn deref_by_trait( | |||
91 | // they're just being 'passed through'. In the 'standard' case where | 105 | // they're just being 'passed through'. In the 'standard' case where |
92 | // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be | 106 | // we have `impl<T> Deref for Foo<T> { Target = T }`, that should be |
93 | // the case. | 107 | // the case. |
108 | |||
109 | // FIXME: if the trait solver decides to truncate the type, these | ||
110 | // assumptions will be broken. We would need to properly introduce | ||
111 | // new variables in that case | ||
112 | |||
94 | for i in 1..vars.0.num_vars { | 113 | for i in 1..vars.0.num_vars { |
95 | if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) | 114 | if vars.0.value[i - 1] != Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) |
96 | { | 115 | { |
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs index ac25f8a80..5f6cea8d3 100644 --- a/crates/ra_hir_ty/src/infer/unify.rs +++ b/crates/ra_hir_ty/src/infer/unify.rs | |||
@@ -32,6 +32,7 @@ where | |||
32 | var_stack: Vec<TypeVarId>, | 32 | var_stack: Vec<TypeVarId>, |
33 | } | 33 | } |
34 | 34 | ||
35 | #[derive(Debug)] | ||
35 | pub(super) struct Canonicalized<T> { | 36 | pub(super) struct Canonicalized<T> { |
36 | pub value: Canonical<T>, | 37 | pub value: Canonical<T>, |
37 | free_vars: Vec<InferTy>, | 38 | free_vars: Vec<InferTy>, |
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/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..0a889f805 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -349,7 +349,6 @@ trait Trait: SuperTrait { | |||
349 | 349 | ||
350 | #[test] | 350 | #[test] |
351 | fn infer_project_associated_type() { | 351 | fn infer_project_associated_type() { |
352 | // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234 | ||
353 | assert_snapshot!( | 352 | assert_snapshot!( |
354 | infer(r#" | 353 | infer(r#" |
355 | trait Iterable { | 354 | trait Iterable { |
@@ -368,12 +367,12 @@ fn test<T: Iterable>() { | |||
368 | [108; 261) '{ ...ter; }': () | 367 | [108; 261) '{ ...ter; }': () |
369 | [118; 119) 'x': u32 | 368 | [118; 119) 'x': u32 |
370 | [145; 146) '1': u32 | 369 | [145; 146) '1': u32 |
371 | [156; 157) 'y': {unknown} | 370 | [156; 157) 'y': Iterable::Item<T> |
372 | [183; 192) 'no_matter': {unknown} | 371 | [183; 192) 'no_matter': Iterable::Item<T> |
373 | [202; 203) 'z': {unknown} | 372 | [202; 203) 'z': Iterable::Item<T> |
374 | [215; 224) 'no_matter': {unknown} | 373 | [215; 224) 'no_matter': Iterable::Item<T> |
375 | [234; 235) 'a': {unknown} | 374 | [234; 235) 'a': Iterable::Item<T> |
376 | [249; 258) 'no_matter': {unknown} | 375 | [249; 258) 'no_matter': Iterable::Item<T> |
377 | "### | 376 | "### |
378 | ); | 377 | ); |
379 | } | 378 | } |
@@ -433,8 +432,8 @@ fn test<T: Iterable<Item=u32>>() { | |||
433 | "#), | 432 | "#), |
434 | @r###" | 433 | @r###" |
435 | [67; 100) '{ ...own; }': () | 434 | [67; 100) '{ ...own; }': () |
436 | [77; 78) 'y': {unknown} | 435 | [77; 78) 'y': u32 |
437 | [90; 97) 'unknown': {unknown} | 436 | [90; 97) 'unknown': u32 |
438 | "### | 437 | "### |
439 | ); | 438 | ); |
440 | } | 439 | } |
@@ -549,7 +548,7 @@ impl std::ops::Index<u32> for Bar { | |||
549 | 548 | ||
550 | fn test() { | 549 | fn test() { |
551 | let a = Bar; | 550 | let a = Bar; |
552 | let b = a[1]; | 551 | let b = a[1u32]; |
553 | b<|>; | 552 | b<|>; |
554 | } | 553 | } |
555 | 554 | ||
@@ -574,7 +573,7 @@ fn infer_ops_index_autoderef() { | |||
574 | //- /main.rs crate:main deps:std | 573 | //- /main.rs crate:main deps:std |
575 | fn test() { | 574 | fn test() { |
576 | let a = &[1u32, 2, 3]; | 575 | let a = &[1u32, 2, 3]; |
577 | let b = a[1]; | 576 | let b = a[1u32]; |
578 | b<|>; | 577 | b<|>; |
579 | } | 578 | } |
580 | 579 | ||
@@ -916,11 +915,7 @@ fn test<T: ApplyL>(t: T) { | |||
916 | } | 915 | } |
917 | "#, | 916 | "#, |
918 | ); | 917 | ); |
919 | // FIXME here Chalk doesn't normalize the type to a placeholder. I think we | 918 | assert_eq!(t, "ApplyL::Out<T>"); |
920 | // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>) | ||
921 | // to the trait env ourselves here; probably Chalk can't do this by itself. | ||
922 | // assert_eq!(t, "ApplyL::Out<[missing name]>"); | ||
923 | assert_eq!(t, "{unknown}"); | ||
924 | } | 919 | } |
925 | 920 | ||
926 | #[test] | 921 | #[test] |
@@ -1329,16 +1324,16 @@ fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { | |||
1329 | [263; 264) 'y': impl Trait<Type = i64> | 1324 | [263; 264) 'y': impl Trait<Type = i64> |
1330 | [290; 398) '{ ...r>); }': () | 1325 | [290; 398) '{ ...r>); }': () |
1331 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type | 1326 | [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type |
1332 | [296; 302) 'get(x)': {unknown} | 1327 | [296; 302) 'get(x)': u32 |
1333 | [300; 301) 'x': T | 1328 | [300; 301) 'x': T |
1334 | [308; 312) 'get2': fn get2<{unknown}, T>(T) -> {unknown} | 1329 | [308; 312) 'get2': fn get2<u32, T>(T) -> u32 |
1335 | [308; 315) 'get2(x)': {unknown} | 1330 | [308; 315) 'get2(x)': u32 |
1336 | [313; 314) 'x': T | 1331 | [313; 314) 'x': T |
1337 | [321; 324) 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type | 1332 | [321; 324) 'get': fn get<impl Trait<Type = i64>>(impl Trait<Type = i64>) -> <impl Trait<Type = i64> as Trait>::Type |
1338 | [321; 327) 'get(y)': {unknown} | 1333 | [321; 327) 'get(y)': i64 |
1339 | [325; 326) 'y': impl Trait<Type = i64> | 1334 | [325; 326) 'y': impl Trait<Type = i64> |
1340 | [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> {unknown} | 1335 | [333; 337) 'get2': fn get2<i64, impl Trait<Type = i64>>(impl Trait<Type = i64>) -> i64 |
1341 | [333; 340) 'get2(y)': {unknown} | 1336 | [333; 340) 'get2(y)': i64 |
1342 | [338; 339) 'y': impl Trait<Type = i64> | 1337 | [338; 339) 'y': impl Trait<Type = i64> |
1343 | [346; 349) 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type | 1338 | [346; 349) 'get': fn get<S<u64>>(S<u64>) -> <S<u64> as Trait>::Type |
1344 | [346; 357) 'get(set(S))': u64 | 1339 | [346; 357) 'get(set(S))': u64 |
@@ -1402,7 +1397,6 @@ mod iter { | |||
1402 | 1397 | ||
1403 | #[test] | 1398 | #[test] |
1404 | fn projection_eq_within_chalk() { | 1399 | fn projection_eq_within_chalk() { |
1405 | // std::env::set_var("CHALK_DEBUG", "1"); | ||
1406 | assert_snapshot!( | 1400 | assert_snapshot!( |
1407 | infer(r#" | 1401 | infer(r#" |
1408 | trait Trait1 { | 1402 | trait Trait1 { |
@@ -1422,7 +1416,7 @@ fn test<T: Trait1<Type = u32>>(x: T) { | |||
1422 | [164; 165) 'x': T | 1416 | [164; 165) 'x': T |
1423 | [170; 186) '{ ...o(); }': () | 1417 | [170; 186) '{ ...o(); }': () |
1424 | [176; 177) 'x': T | 1418 | [176; 177) 'x': T |
1425 | [176; 183) 'x.foo()': {unknown} | 1419 | [176; 183) 'x.foo()': u32 |
1426 | "### | 1420 | "### |
1427 | ); | 1421 | ); |
1428 | } | 1422 | } |
@@ -1578,7 +1572,7 @@ fn test<F: FnOnce(u32, u64) -> u128>(f: F) { | |||
1578 | [150; 151) 'f': F | 1572 | [150; 151) 'f': F |
1579 | [156; 184) '{ ...2)); }': () | 1573 | [156; 184) '{ ...2)); }': () |
1580 | [162; 163) 'f': F | 1574 | [162; 163) 'f': F |
1581 | [162; 181) 'f.call...1, 2))': {unknown} | 1575 | [162; 181) 'f.call...1, 2))': u128 |
1582 | [174; 180) '(1, 2)': (u32, u64) | 1576 | [174; 180) '(1, 2)': (u32, u64) |
1583 | [175; 176) '1': u32 | 1577 | [175; 176) '1': u32 |
1584 | [178; 179) '2': u64 | 1578 | [178; 179) '2': u64 |
@@ -1803,7 +1797,7 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> { | |||
1803 | } | 1797 | } |
1804 | 1798 | ||
1805 | #[test] | 1799 | #[test] |
1806 | fn unselected_projection_on_trait_self() { | 1800 | fn unselected_projection_on_impl_self() { |
1807 | assert_snapshot!(infer( | 1801 | assert_snapshot!(infer( |
1808 | r#" | 1802 | r#" |
1809 | //- /main.rs | 1803 | //- /main.rs |
@@ -1829,7 +1823,7 @@ impl Trait for S2 { | |||
1829 | "#, | 1823 | "#, |
1830 | ), @r###" | 1824 | ), @r###" |
1831 | [54; 58) 'self': &Self | 1825 | [54; 58) 'self': &Self |
1832 | [60; 61) 'x': {unknown} | 1826 | [60; 61) 'x': Trait::Item<Self> |
1833 | [140; 144) 'self': &S | 1827 | [140; 144) 'self': &S |
1834 | [146; 147) 'x': u32 | 1828 | [146; 147) 'x': u32 |
1835 | [161; 175) '{ let y = x; }': () | 1829 | [161; 175) '{ let y = x; }': () |
@@ -1844,6 +1838,30 @@ impl Trait for S2 { | |||
1844 | } | 1838 | } |
1845 | 1839 | ||
1846 | #[test] | 1840 | #[test] |
1841 | fn unselected_projection_on_trait_self() { | ||
1842 | let t = type_at( | ||
1843 | r#" | ||
1844 | //- /main.rs | ||
1845 | trait Trait { | ||
1846 | type Item; | ||
1847 | |||
1848 | fn f(&self) -> Self::Item { loop {} } | ||
1849 | } | ||
1850 | |||
1851 | struct S; | ||
1852 | impl Trait for S { | ||
1853 | type Item = u32; | ||
1854 | } | ||
1855 | |||
1856 | fn test() { | ||
1857 | S.f()<|>; | ||
1858 | } | ||
1859 | "#, | ||
1860 | ); | ||
1861 | assert_eq!(t, "u32"); | ||
1862 | } | ||
1863 | |||
1864 | #[test] | ||
1847 | fn trait_impl_self_ty() { | 1865 | fn trait_impl_self_ty() { |
1848 | let t = type_at( | 1866 | let t = type_at( |
1849 | r#" | 1867 | r#" |
@@ -1924,6 +1942,119 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> { | |||
1924 | } | 1942 | } |
1925 | 1943 | ||
1926 | #[test] | 1944 | #[test] |
1945 | fn inline_assoc_type_bounds_1() { | ||
1946 | let t = type_at( | ||
1947 | r#" | ||
1948 | //- /main.rs | ||
1949 | trait Iterator { | ||
1950 | type Item; | ||
1951 | } | ||
1952 | trait OtherTrait<T> { | ||
1953 | fn foo(&self) -> T; | ||
1954 | } | ||
1955 | |||
1956 | // workaround for Chalk assoc type normalization problems | ||
1957 | pub struct S<T>; | ||
1958 | impl<T: Iterator> Iterator for S<T> { | ||
1959 | type Item = <T as Iterator>::Item; | ||
1960 | } | ||
1961 | |||
1962 | fn test<I: Iterator<Item: OtherTrait<u32>>>() { | ||
1963 | let x: <S<I> as Iterator>::Item; | ||
1964 | x.foo()<|>; | ||
1965 | } | ||
1966 | "#, | ||
1967 | ); | ||
1968 | assert_eq!(t, "u32"); | ||
1969 | } | ||
1970 | |||
1971 | #[test] | ||
1972 | fn inline_assoc_type_bounds_2() { | ||
1973 | let t = type_at( | ||
1974 | r#" | ||
1975 | //- /main.rs | ||
1976 | trait Iterator { | ||
1977 | type Item; | ||
1978 | } | ||
1979 | |||
1980 | fn test<I: Iterator<Item: Iterator<Item = u32>>>() { | ||
1981 | let x: <<I as Iterator>::Item as Iterator>::Item; | ||
1982 | x<|>; | ||
1983 | } | ||
1984 | "#, | ||
1985 | ); | ||
1986 | assert_eq!(t, "u32"); | ||
1987 | } | ||
1988 | |||
1989 | #[test] | ||
1990 | fn proc_macro_server_types() { | ||
1991 | assert_snapshot!( | ||
1992 | infer_with_mismatches(r#" | ||
1993 | macro_rules! with_api { | ||
1994 | ($S:ident, $self:ident, $m:ident) => { | ||
1995 | $m! { | ||
1996 | TokenStream { | ||
1997 | fn new() -> $S::TokenStream; | ||
1998 | }, | ||
1999 | Group { | ||
2000 | }, | ||
2001 | } | ||
2002 | }; | ||
2003 | } | ||
2004 | macro_rules! associated_item { | ||
2005 | (type TokenStream) => | ||
2006 | (type TokenStream: 'static + Clone;); | ||
2007 | (type Group) => | ||
2008 | (type Group: 'static + Clone;); | ||
2009 | ($($item:tt)*) => ($($item)*;) | ||
2010 | } | ||
2011 | macro_rules! declare_server_traits { | ||
2012 | ($($name:ident { | ||
2013 | $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* | ||
2014 | }),* $(,)?) => { | ||
2015 | pub trait Types { | ||
2016 | $(associated_item!(type $name);)* | ||
2017 | } | ||
2018 | |||
2019 | $(pub trait $name: Types { | ||
2020 | $(associated_item!(fn $method(&mut self, $($arg: $arg_ty),*) $(-> $ret_ty)?);)* | ||
2021 | })* | ||
2022 | |||
2023 | pub trait Server: Types $(+ $name)* {} | ||
2024 | impl<S: Types $(+ $name)*> Server for S {} | ||
2025 | } | ||
2026 | } | ||
2027 | with_api!(Self, self_, declare_server_traits); | ||
2028 | struct Group {} | ||
2029 | struct TokenStream {} | ||
2030 | struct Rustc; | ||
2031 | impl Types for Rustc { | ||
2032 | type TokenStream = TokenStream; | ||
2033 | type Group = Group; | ||
2034 | } | ||
2035 | fn make<T>() -> T { loop {} } | ||
2036 | impl TokenStream for Rustc { | ||
2037 | fn new() -> Self::TokenStream { | ||
2038 | let group: Self::Group = make(); | ||
2039 | make() | ||
2040 | } | ||
2041 | } | ||
2042 | "#, true), | ||
2043 | @r###" | ||
2044 | [1115; 1126) '{ loop {} }': T | ||
2045 | [1117; 1124) 'loop {}': ! | ||
2046 | [1122; 1124) '{}': () | ||
2047 | [1190; 1253) '{ ... }': {unknown} | ||
2048 | [1204; 1209) 'group': {unknown} | ||
2049 | [1225; 1229) 'make': fn make<{unknown}>() -> {unknown} | ||
2050 | [1225; 1231) 'make()': {unknown} | ||
2051 | [1241; 1245) 'make': fn make<{unknown}>() -> {unknown} | ||
2052 | [1241; 1247) 'make()': {unknown} | ||
2053 | "### | ||
2054 | ); | ||
2055 | } | ||
2056 | |||
2057 | #[test] | ||
1927 | fn unify_impl_trait() { | 2058 | fn unify_impl_trait() { |
1928 | assert_snapshot!( | 2059 | assert_snapshot!( |
1929 | infer_with_mismatches(r#" | 2060 | infer_with_mismatches(r#" |
@@ -2023,6 +2154,33 @@ fn main() { | |||
2023 | } | 2154 | } |
2024 | 2155 | ||
2025 | #[test] | 2156 | #[test] |
2157 | fn associated_type_bound() { | ||
2158 | let t = type_at( | ||
2159 | r#" | ||
2160 | //- /main.rs | ||
2161 | pub trait Trait { | ||
2162 | type Item: OtherTrait<u32>; | ||
2163 | } | ||
2164 | pub trait OtherTrait<T> { | ||
2165 | fn foo(&self) -> T; | ||
2166 | } | ||
2167 | |||
2168 | // this is just a workaround for chalk#234 | ||
2169 | pub struct S<T>; | ||
2170 | impl<T: Trait> Trait for S<T> { | ||
2171 | type Item = <T as Trait>::Item; | ||
2172 | } | ||
2173 | |||
2174 | fn test<T: Trait>() { | ||
2175 | let y: <S<T> as Trait>::Item = no_matter; | ||
2176 | y.foo()<|>; | ||
2177 | } | ||
2178 | "#, | ||
2179 | ); | ||
2180 | assert_eq!(t, "u32"); | ||
2181 | } | ||
2182 | |||
2183 | #[test] | ||
2026 | fn dyn_trait_through_chalk() { | 2184 | fn dyn_trait_through_chalk() { |
2027 | let t = type_at( | 2185 | let t = type_at( |
2028 | r#" | 2186 | r#" |
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 43d8d1e80..05791a848 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -16,10 +16,12 @@ use self::chalk::{from_chalk, Interner, ToChalk}; | |||
16 | pub(crate) mod chalk; | 16 | pub(crate) mod chalk; |
17 | mod builtin; | 17 | mod builtin; |
18 | 18 | ||
19 | /// This controls the maximum size of types Chalk considers. If we set this too | 19 | // This controls the maximum size of types Chalk considers. If we set this too |
20 | /// high, we can run into slow edge cases; if we set it too low, Chalk won't | 20 | // high, we can run into slow edge cases; if we set it too low, Chalk won't |
21 | /// find some solutions. | 21 | // find some solutions. |
22 | const CHALK_SOLVER_MAX_SIZE: usize = 10; | 22 | // FIXME this is currently hardcoded in the recursive solver |
23 | // const CHALK_SOLVER_MAX_SIZE: usize = 10; | ||
24 | |||
23 | /// This controls how much 'time' we give the Chalk solver before giving up. | 25 | /// This controls how much 'time' we give the Chalk solver before giving up. |
24 | const CHALK_SOLVER_FUEL: i32 = 100; | 26 | const CHALK_SOLVER_FUEL: i32 = 100; |
25 | 27 | ||
@@ -30,8 +32,7 @@ struct ChalkContext<'a> { | |||
30 | } | 32 | } |
31 | 33 | ||
32 | fn create_chalk_solver() -> chalk_solve::Solver<Interner> { | 34 | fn create_chalk_solver() -> chalk_solve::Solver<Interner> { |
33 | let solver_choice = | 35 | let solver_choice = chalk_solve::SolverChoice::recursive(); |
34 | chalk_solve::SolverChoice::SLG { max_size: CHALK_SOLVER_MAX_SIZE, expected_answers: None }; | ||
35 | solver_choice.into_solver() | 36 | solver_choice.into_solver() |
36 | } | 37 | } |
37 | 38 | ||
@@ -194,13 +195,16 @@ fn solve( | |||
194 | } | 195 | } |
195 | remaining > 0 | 196 | remaining > 0 |
196 | }; | 197 | }; |
197 | let mut solve = || solver.solve_limited(&context, goal, should_continue); | 198 | let mut solve = || { |
199 | let solution = solver.solve_limited(&context, goal, should_continue); | ||
200 | log::debug!("solve({:?}) => {:?}", goal, solution); | ||
201 | solution | ||
202 | }; | ||
198 | // don't set the TLS for Chalk unless Chalk debugging is active, to make | 203 | // don't set the TLS for Chalk unless Chalk debugging is active, to make |
199 | // extra sure we only use it for debugging | 204 | // extra sure we only use it for debugging |
200 | let solution = | 205 | let solution = |
201 | if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; | 206 | if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; |
202 | 207 | ||
203 | log::debug!("solve({:?}) => {:?}", goal, solution); | ||
204 | solution | 208 | solution |
205 | } | 209 | } |
206 | 210 | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index e05fea843..60d70d18e 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 | ||
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 | { |
@@ -464,13 +511,13 @@ impl ToChalk for ProjectionTy { | |||
464 | } | 511 | } |
465 | 512 | ||
466 | impl ToChalk for super::ProjectionPredicate { | 513 | impl ToChalk for super::ProjectionPredicate { |
467 | type Chalk = chalk_ir::Normalize<Interner>; | 514 | type Chalk = chalk_ir::AliasEq<Interner>; |
468 | 515 | ||
469 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Normalize<Interner> { | 516 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { |
470 | chalk_ir::Normalize { alias: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db) } | 517 | chalk_ir::AliasEq { alias: self.projection_ty.to_chalk(db), ty: self.ty.to_chalk(db) } |
471 | } | 518 | } |
472 | 519 | ||
473 | fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::Normalize<Interner>) -> Self { | 520 | fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { |
474 | unimplemented!() | 521 | unimplemented!() |
475 | } | 522 | } |
476 | } | 523 | } |
@@ -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) |
@@ -696,6 +792,13 @@ 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 | ) -> Option<chalk_ir::TraitId<Interner>> { | ||
799 | // FIXME tell Chalk about well-known traits (here and in trait_datum) | ||
800 | None | ||
801 | } | ||
699 | } | 802 | } |
700 | 803 | ||
701 | pub(crate) fn associated_ty_data_query( | 804 | pub(crate) fn associated_ty_data_query( |
@@ -708,12 +811,25 @@ pub(crate) fn associated_ty_data_query( | |||
708 | AssocContainerId::TraitId(t) => t, | 811 | AssocContainerId::TraitId(t) => t, |
709 | _ => panic!("associated type not in trait"), | 812 | _ => panic!("associated type not in trait"), |
710 | }; | 813 | }; |
814 | |||
815 | // Lower bounds -- we could/should maybe move this to a separate query in `lower` | ||
816 | let type_alias_data = db.type_alias_data(type_alias); | ||
711 | let generic_params = generics(db.upcast(), type_alias.into()); | 817 | let generic_params = generics(db.upcast(), type_alias.into()); |
712 | let bound_data = chalk_rust_ir::AssociatedTyDatumBound { | 818 | let bound_vars = Substs::bound_vars(&generic_params); |
713 | // FIXME add bounds and where clauses | 819 | let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); |
714 | bounds: vec![], | 820 | let ctx = crate::TyLoweringContext::new(db, &resolver) |
715 | where_clauses: vec![], | 821 | .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); |
716 | }; | 822 | let self_ty = Ty::Bound(crate::BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)); |
823 | let bounds = type_alias_data | ||
824 | .bounds | ||
825 | .iter() | ||
826 | .flat_map(|bound| GenericPredicate::from_type_bound(&ctx, bound, self_ty.clone())) | ||
827 | .filter_map(|pred| generic_predicate_to_inline_bound(db, &pred, &self_ty)) | ||
828 | .map(|bound| make_binders(bound.shifted_in(&Interner), 0)) | ||
829 | .collect(); | ||
830 | |||
831 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | ||
832 | let bound_data = chalk_rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; | ||
717 | let datum = AssociatedTyDatum { | 833 | let datum = AssociatedTyDatum { |
718 | trait_id: trait_.to_chalk(db), | 834 | trait_id: trait_.to_chalk(db), |
719 | id, | 835 | 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( |