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.rs42
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs21
-rw-r--r--crates/ra_hir_ty/src/expr.rs2
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs1
-rw-r--r--crates/ra_hir_ty/src/lib.rs10
-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.rs212
-rw-r--r--crates/ra_hir_ty/src/traits.rs20
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs160
-rw-r--r--crates/ra_hir_ty/src/traits/chalk/tls.rs42
11 files changed, 474 insertions, 81 deletions
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs
index a64be9848..688026a04 100644
--- a/crates/ra_hir_ty/src/_match.rs
+++ b/crates/ra_hir_ty/src/_match.rs
@@ -194,9 +194,10 @@ use smallvec::{smallvec, SmallVec};
194use crate::{ 194use crate::{
195 db::HirDatabase, 195 db::HirDatabase,
196 expr::{Body, Expr, Literal, Pat, PatId}, 196 expr::{Body, Expr, Literal, Pat, PatId},
197 InferenceResult, 197 ApplicationTy, InferenceResult, Ty, TypeCtor,
198}; 198};
199use hir_def::{adt::VariantData, EnumVariantId, VariantId}; 199use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId};
200use ra_arena::Idx;
200 201
201#[derive(Debug, Clone, Copy)] 202#[derive(Debug, Clone, Copy)]
202/// Either a pattern from the source code being analyzed, represented as 203/// Either a pattern from the source code being analyzed, represented as
@@ -512,6 +513,7 @@ pub enum Usefulness {
512} 513}
513 514
514pub struct MatchCheckCtx<'a> { 515pub struct MatchCheckCtx<'a> {
516 pub match_expr: Idx<Expr>,
515 pub body: Arc<Body>, 517 pub body: Arc<Body>,
516 pub infer: Arc<InferenceResult>, 518 pub infer: Arc<InferenceResult>,
517 pub db: &'a dyn HirDatabase, 519 pub db: &'a dyn HirDatabase,
@@ -530,6 +532,16 @@ pub(crate) fn is_useful(
530 matrix: &Matrix, 532 matrix: &Matrix,
531 v: &PatStack, 533 v: &PatStack,
532) -> MatchCheckResult<Usefulness> { 534) -> MatchCheckResult<Usefulness> {
535 // Handle the special case of enums with no variants. In that case, no match
536 // arm is useful.
537 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(AdtId::EnumId(enum_id)), .. }) =
538 cx.infer[cx.match_expr].strip_references()
539 {
540 if cx.db.enum_data(*enum_id).variants.is_empty() {
541 return Ok(Usefulness::NotUseful);
542 }
543 }
544
533 if v.is_empty() { 545 if v.is_empty() {
534 let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful }; 546 let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful };
535 547
@@ -1618,6 +1630,32 @@ mod tests {
1618 1630
1619 check_no_diagnostic(content); 1631 check_no_diagnostic(content);
1620 } 1632 }
1633
1634 #[test]
1635 fn enum_never() {
1636 let content = r"
1637 enum Never {}
1638
1639 fn test_fn(never: Never) {
1640 match never {}
1641 }
1642 ";
1643
1644 check_no_diagnostic(content);
1645 }
1646
1647 #[test]
1648 fn enum_never_ref() {
1649 let content = r"
1650 enum Never {}
1651
1652 fn test_fn(never: &Never) {
1653 match never {}
1654 }
1655 ";
1656
1657 check_no_diagnostic(content);
1658 }
1621} 1659}
1622 1660
1623#[cfg(test)] 1661#[cfg(test)]
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
20const AUTODEREF_RECURSION_LIMIT: usize = 10; 20const 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/expr.rs b/crates/ra_hir_ty/src/expr.rs
index 21abbcf1e..fd59f4320 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -156,7 +156,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
156 None => return, 156 None => return,
157 }; 157 };
158 158
159 let cx = MatchCheckCtx { body, infer: infer.clone(), db }; 159 let cx = MatchCheckCtx { match_expr, body, infer: infer.clone(), db };
160 let pats = arms.iter().map(|arm| arm.pat); 160 let pats = arms.iter().map(|arm| arm.pat);
161 161
162 let mut seen = Matrix::empty(); 162 let mut seen = Matrix::empty();
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)]
35pub(super) struct Canonicalized<T> { 36pub(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/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 18f74d3b1..2677f3af2 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -680,6 +680,16 @@ impl Ty {
680 } 680 }
681 } 681 }
682 682
683 pub fn strip_references(&self) -> &Ty {
684 let mut t: &Ty = self;
685
686 while let Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(_mutability), parameters }) = t {
687 t = parameters.as_single();
688 }
689
690 t
691 }
692
683 pub fn as_adt(&self) -> Option<(AdtId, &Substs)> { 693 pub fn as_adt(&self) -> Option<(AdtId, &Substs)> {
684 match self { 694 match self {
685 Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => { 695 Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => {
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..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]
351fn infer_project_associated_type() { 351fn 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#"
355trait Iterable { 354trait 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
550fn test() { 549fn 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
575fn test() { 574fn 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]
1404fn projection_eq_within_chalk() { 1399fn projection_eq_within_chalk() {
1405 // std::env::set_var("CHALK_DEBUG", "1");
1406 assert_snapshot!( 1400 assert_snapshot!(
1407 infer(r#" 1401 infer(r#"
1408trait Trait1 { 1402trait 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]
1806fn unselected_projection_on_trait_self() { 1800fn 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]
1841fn unselected_projection_on_trait_self() {
1842 let t = type_at(
1843 r#"
1844//- /main.rs
1845trait Trait {
1846 type Item;
1847
1848 fn f(&self) -> Self::Item { loop {} }
1849}
1850
1851struct S;
1852impl Trait for S {
1853 type Item = u32;
1854}
1855
1856fn test() {
1857 S.f()<|>;
1858}
1859"#,
1860 );
1861 assert_eq!(t, "u32");
1862}
1863
1864#[test]
1847fn trait_impl_self_ty() { 1865fn 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]
1945fn inline_assoc_type_bounds_1() {
1946 let t = type_at(
1947 r#"
1948//- /main.rs
1949trait Iterator {
1950 type Item;
1951}
1952trait OtherTrait<T> {
1953 fn foo(&self) -> T;
1954}
1955
1956// workaround for Chalk assoc type normalization problems
1957pub struct S<T>;
1958impl<T: Iterator> Iterator for S<T> {
1959 type Item = <T as Iterator>::Item;
1960}
1961
1962fn 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]
1972fn inline_assoc_type_bounds_2() {
1973 let t = type_at(
1974 r#"
1975//- /main.rs
1976trait Iterator {
1977 type Item;
1978}
1979
1980fn 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]
1990fn proc_macro_server_types() {
1991 assert_snapshot!(
1992 infer_with_mismatches(r#"
1993macro_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}
2004macro_rules! associated_item {
2005 (type TokenStream) =>
2006 (type TokenStream: 'static + Clone;);
2007 (type Group) =>
2008 (type Group: 'static + Clone;);
2009 ($($item:tt)*) => ($($item)*;)
2010}
2011macro_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}
2027with_api!(Self, self_, declare_server_traits);
2028struct Group {}
2029struct TokenStream {}
2030struct Rustc;
2031impl Types for Rustc {
2032 type TokenStream = TokenStream;
2033 type Group = Group;
2034}
2035fn make<T>() -> T { loop {} }
2036impl 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]
1927fn unify_impl_trait() { 2058fn 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]
2157fn associated_type_bound() {
2158 let t = type_at(
2159 r#"
2160//- /main.rs
2161pub trait Trait {
2162 type Item: OtherTrait<u32>;
2163}
2164pub trait OtherTrait<T> {
2165 fn foo(&self) -> T;
2166}
2167
2168// this is just a workaround for chalk#234
2169pub struct S<T>;
2170impl<T: Trait> Trait for S<T> {
2171 type Item = <T as Trait>::Item;
2172}
2173
2174fn 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]
2026fn dyn_trait_through_chalk() { 2184fn 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};
16pub(crate) mod chalk; 16pub(crate) mod chalk;
17mod builtin; 17mod 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.
22const 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.
24const CHALK_SOLVER_FUEL: i32 = 100; 26const CHALK_SOLVER_FUEL: i32 = 100;
25 27
@@ -30,8 +32,7 @@ struct ChalkContext<'a> {
30} 32}
31 33
32fn create_chalk_solver() -> chalk_solve::Solver<Interner> { 34fn 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
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 {
@@ -464,13 +511,13 @@ impl ToChalk for ProjectionTy {
464} 511}
465 512
466impl ToChalk for super::ProjectionPredicate { 513impl 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
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,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
701pub(crate) fn associated_ty_data_query( 804pub(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 @@
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(