aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_hir_ty/src/infer.rs27
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs1
-rw-r--r--crates/ra_hir_ty/src/marks.rs1
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs65
4 files changed, 91 insertions, 3 deletions
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index af42854cc..98ba05fc2 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -32,6 +32,7 @@ use hir_def::{
32use hir_expand::{diagnostics::DiagnosticSink, name::name}; 32use hir_expand::{diagnostics::DiagnosticSink, name::name};
33use ra_arena::map::ArenaMap; 33use ra_arena::map::ArenaMap;
34use ra_prof::profile; 34use ra_prof::profile;
35use test_utils::tested_by;
35 36
36use super::{ 37use super::{
37 primitive::{FloatTy, IntTy}, 38 primitive::{FloatTy, IntTy},
@@ -274,6 +275,29 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
274 self.normalize_associated_types_in(ty) 275 self.normalize_associated_types_in(ty)
275 } 276 }
276 277
278 /// Replaces `impl Trait` in `ty` by type variables and obligations for
279 /// those variables. This is done for function arguments when calling a
280 /// function, and for return types when inside the function body, i.e. in
281 /// the cases where the `impl Trait` is 'transparent'. In other cases, `impl
282 /// Trait` is represented by `Ty::Opaque`.
283 fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty {
284 ty.fold(&mut |ty| match ty {
285 Ty::Opaque(preds) => {
286 tested_by!(insert_vars_for_impl_trait);
287 let var = self.table.new_type_var();
288 let var_subst = Substs::builder(1).push(var.clone()).build();
289 self.obligations.extend(
290 preds
291 .iter()
292 .map(|pred| pred.clone().subst_bound_vars(&var_subst))
293 .filter_map(Obligation::from_predicate),
294 );
295 var
296 }
297 _ => ty,
298 })
299 }
300
277 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. 301 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
278 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 302 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
279 match ty { 303 match ty {
@@ -414,7 +438,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
414 438
415 self.infer_pat(*pat, &ty, BindingMode::default()); 439 self.infer_pat(*pat, &ty, BindingMode::default());
416 } 440 }
417 self.return_ty = self.make_ty(&data.ret_type); 441 let return_ty = self.make_ty(&data.ret_type);
442 self.return_ty = self.insert_vars_for_impl_trait(return_ty);
418 } 443 }
419 444
420 fn infer_body(&mut self) { 445 fn infer_body(&mut self) {
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 2e3cdd53a..924ad3e81 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -613,6 +613,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
613 continue; 613 continue;
614 } 614 }
615 615
616 let param_ty = self.insert_vars_for_impl_trait(param_ty);
616 let param_ty = self.normalize_associated_types_in(param_ty); 617 let param_ty = self.normalize_associated_types_in(param_ty);
617 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); 618 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
618 } 619 }
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
index 0f754eb9c..fe74acf11 100644
--- a/crates/ra_hir_ty/src/marks.rs
+++ b/crates/ra_hir_ty/src/marks.rs
@@ -6,4 +6,5 @@ test_utils::marks!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 match_ergonomics_ref 7 match_ergonomics_ref
8 coerce_merge_fail_fallback 8 coerce_merge_fail_fallback
9 insert_vars_for_impl_trait
9); 10);
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
index 6139adb72..802937cb0 100644
--- a/crates/ra_hir_ty/src/tests/traits.rs
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -1,7 +1,10 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot; 1use insta::assert_snapshot;
2
4use ra_db::fixture::WithFixture; 3use ra_db::fixture::WithFixture;
4use test_utils::covers;
5
6use super::{infer, infer_with_mismatches, type_at, type_at_pos};
7use crate::test_db::TestDB;
5 8
6#[test] 9#[test]
7fn infer_await() { 10fn infer_await() {
@@ -1486,3 +1489,61 @@ fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
1486 // this is a legitimate cycle 1489 // this is a legitimate cycle
1487 assert_eq!(t, "{unknown}"); 1490 assert_eq!(t, "{unknown}");
1488} 1491}
1492
1493#[test]
1494fn unify_impl_trait() {
1495 covers!(insert_vars_for_impl_trait);
1496 assert_snapshot!(
1497 infer_with_mismatches(r#"
1498trait Trait<T> {}
1499
1500fn foo(x: impl Trait<u32>) { loop {} }
1501fn bar<T>(x: impl Trait<T>) -> T { loop {} }
1502
1503struct S<T>(T);
1504impl<T> Trait<T> for S<T> {}
1505
1506fn default<T>() -> T { loop {} }
1507
1508fn test() -> impl Trait<i32> {
1509 let s1 = S(default());
1510 foo(s1);
1511 let x: i32 = bar(S(default()));
1512 S(default())
1513}
1514"#, true),
1515 @r###"
1516 [27; 28) 'x': impl Trait<u32>
1517 [47; 58) '{ loop {} }': ()
1518 [49; 56) 'loop {}': !
1519 [54; 56) '{}': ()
1520 [69; 70) 'x': impl Trait<T>
1521 [92; 103) '{ loop {} }': T
1522 [94; 101) 'loop {}': !
1523 [99; 101) '{}': ()
1524 [172; 183) '{ loop {} }': T
1525 [174; 181) 'loop {}': !
1526 [179; 181) '{}': ()
1527 [214; 310) '{ ...t()) }': S<i32>
1528 [224; 226) 's1': S<u32>
1529 [229; 230) 'S': S<u32>(T) -> S<T>
1530 [229; 241) 'S(default())': S<u32>
1531 [231; 238) 'default': fn default<u32>() -> T
1532 [231; 240) 'default()': u32
1533 [247; 250) 'foo': fn foo(impl Trait<u32>) -> ()
1534 [247; 254) 'foo(s1)': ()
1535 [251; 253) 's1': S<u32>
1536 [264; 265) 'x': i32
1537 [273; 276) 'bar': fn bar<i32>(impl Trait<T>) -> T
1538 [273; 290) 'bar(S(...lt()))': i32
1539 [277; 278) 'S': S<i32>(T) -> S<T>
1540 [277; 289) 'S(default())': S<i32>
1541 [279; 286) 'default': fn default<i32>() -> T
1542 [279; 288) 'default()': i32
1543 [296; 297) 'S': S<i32>(T) -> S<T>
1544 [296; 308) 'S(default())': S<i32>
1545 [298; 305) 'default': fn default<i32>() -> T
1546 [298; 307) 'default()': i32
1547 "###
1548 );
1549}