diff options
author | Lukas Wirth <[email protected]> | 2020-11-24 12:41:21 +0000 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2020-11-24 12:56:20 +0000 |
commit | 35dd62e915905b6a93e2069a6d155cdf00cd254a (patch) | |
tree | ebaf611da8e52f8df0c2d308b18bb9b6368fe3ef /crates/hir_ty | |
parent | 6294286fee6e53c29e8ad563f476721ad85ef266 (diff) |
Properly infer tuple patterns when encountering ellipsis
Diffstat (limited to 'crates/hir_ty')
-rw-r--r-- | crates/hir_ty/src/infer/pat.rs | 25 | ||||
-rw-r--r-- | crates/hir_ty/src/tests/patterns.rs | 47 |
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] | ||
684 | fn tuple_ellipsis_pattern() { | ||
685 | check_infer( | ||
686 | r#" | ||
687 | fn 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 | } | ||