aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLukas Wirth <[email protected]>2020-11-24 12:41:21 +0000
committerLukas Wirth <[email protected]>2020-11-24 12:56:20 +0000
commit35dd62e915905b6a93e2069a6d155cdf00cd254a (patch)
treeebaf611da8e52f8df0c2d308b18bb9b6368fe3ef
parent6294286fee6e53c29e8ad563f476721ad85ef266 (diff)
Properly infer tuple patterns when encountering ellipsis
-rw-r--r--crates/hir_ty/src/infer/pat.rs25
-rw-r--r--crates/hir_ty/src/tests/patterns.rs47
2 files changed, 64 insertions, 8 deletions
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index cde2ab82b..b3fd74eab 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -111,20 +111,29 @@ impl<'a> InferenceContext<'a> {
111 let expected = expected; 111 let expected = expected;
112 112
113 let ty = match &body[pat] { 113 let ty = match &body[pat] {
114 Pat::Tuple { ref args, .. } => { 114 Pat::Tuple { ref args, ellipsis } => {
115 let expectations = match expected.as_tuple() { 115 let expectations = match expected.as_tuple() {
116 Some(parameters) => &*parameters.0, 116 Some(parameters) => &*parameters.0,
117 _ => &[], 117 _ => &[],
118 }; 118 };
119 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
120 119
121 let inner_tys = args 120 let (pre, post) = match ellipsis {
122 .iter() 121 &Some(idx) => args.split_at(idx),
123 .zip(expectations_iter) 122 None => (&args[..], &[][..]),
124 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm)) 123 };
125 .collect(); 124 let uncovered_range = pre.len()..expectations.len().saturating_sub(post.len());
125 let mut expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
126 let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm);
127
128 let mut inner_tys = Vec::with_capacity(expectations.len());
129 inner_tys.extend(pre.iter().zip(expectations_iter.by_ref()).map(&mut infer_pat));
130 inner_tys.extend(expectations_iter.by_ref().take(uncovered_range.len()).cloned());
131 inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat));
126 132
127 Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys)) 133 Ty::apply(
134 TypeCtor::Tuple { cardinality: inner_tys.len() as u16 },
135 Substs(inner_tys.into()),
136 )
128 } 137 }
129 Pat::Or(ref pats) => { 138 Pat::Or(ref pats) => {
130 if let Some((first_pat, rest)) = pats.split_first() { 139 if let Some((first_pat, rest)) = pats.split_first() {
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 6a965ac4f..5776de280 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -679,3 +679,50 @@ fn box_pattern() {
679 "#]], 679 "#]],
680 ); 680 );
681} 681}
682
683#[test]
684fn tuple_ellipsis_pattern() {
685 check_infer(
686 r#"
687fn foo(tuple: (u8, i16, f32)) {
688 match tuple {
689 (.., b, c) => {},
690 (a, .., c) => {},
691 (a, b, ..) => {},
692 (a, b) => {/*too short*/}
693 (a, b, c, d) => {/*too long*/}
694 _ => {}
695 }
696}"#,
697 expect![[r#"
698 7..12 'tuple': (u8, i16, f32)
699 30..224 '{ ... } }': ()
700 36..222 'match ... }': ()
701 42..47 'tuple': (u8, i16, f32)
702 58..68 '(.., b, c)': (u8, i16, f32)
703 63..64 'b': i16
704 66..67 'c': f32
705 72..74 '{}': ()
706 84..94 '(a, .., c)': (u8, i16, f32)
707 85..86 'a': u8
708 92..93 'c': f32
709 98..100 '{}': ()
710 110..120 '(a, b, ..)': (u8, i16, f32)
711 111..112 'a': u8
712 114..115 'b': i16
713 124..126 '{}': ()
714 136..142 '(a, b)': (u8, i16, f32)
715 137..138 'a': u8
716 140..141 'b': i16
717 146..161 '{/*too short*/}': ()
718 170..182 '(a, b, c, d)': (u8, i16, f32, {unknown})
719 171..172 'a': u8
720 174..175 'b': i16
721 177..178 'c': f32
722 180..181 'd': {unknown}
723 186..200 '{/*too long*/}': ()
724 209..210 '_': (u8, i16, f32)
725 214..216 '{}': ()
726 "#]],
727 );
728}