Skip to content

Commit a0ffa15

Browse files
Merge pull request #21026 from Veykril/veykril/push-xtwpvurpxywx
Infer range pattern fully
2 parents 9075b4a + 069d644 commit a0ffa15

File tree

8 files changed

+87
-29
lines changed

8 files changed

+87
-29
lines changed

crates/hir-def/src/expr_store/lower.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2410,7 +2410,10 @@ impl ExprCollector<'_> {
24102410
let start = range_part_lower(p.start());
24112411
let end = range_part_lower(p.end());
24122412
// FIXME: Exclusive ended pattern range is stabilised
2413-
Pat::Range { start, end }
2413+
match p.op_kind() {
2414+
Some(range_type) => Pat::Range { start, end, range_type },
2415+
None => Pat::Missing,
2416+
}
24142417
}
24152418
};
24162419
let ptr = AstPtr::new(&pat);

crates/hir-def/src/expr_store/pretty.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::{
99
use hir_expand::{Lookup, mod_path::PathKind};
1010
use itertools::Itertools;
1111
use span::Edition;
12-
use syntax::ast::HasName;
12+
use syntax::ast::{HasName, RangeOp};
1313

1414
use crate::{
1515
AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId,
@@ -735,8 +735,8 @@ impl Printer<'_> {
735735
self.print_expr_in(prec, *lhs);
736736
}
737737
match range_type {
738-
ast::RangeOp::Exclusive => w!(self, ".."),
739-
ast::RangeOp::Inclusive => w!(self, "..="),
738+
RangeOp::Exclusive => w!(self, ".."),
739+
RangeOp::Inclusive => w!(self, "..="),
740740
};
741741
if let Some(rhs) = rhs {
742742
self.print_expr_in(prec, *rhs);
@@ -937,11 +937,14 @@ impl Printer<'_> {
937937
});
938938
w!(self, "}}");
939939
}
940-
Pat::Range { start, end } => {
940+
Pat::Range { start, end, range_type } => {
941941
if let Some(start) = start {
942942
self.print_expr_in(prec, *start);
943943
}
944-
w!(self, "..=");
944+
match range_type {
945+
RangeOp::Inclusive => w!(self, "..="),
946+
RangeOp::Exclusive => w!(self, ".."),
947+
}
945948
if let Some(end) = end {
946949
self.print_expr_in(prec, *end);
947950
}

crates/hir-def/src/expr_store/tests/body.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -580,7 +580,7 @@ const fn f(x: i32) -> i32 {
580580

581581
let MatchArm { pat, .. } = mtch_arms[1];
582582
match body[pat] {
583-
Pat::Range { start, end } => {
583+
Pat::Range { start, end, range_type: _ } => {
584584
let hir_start = &body[start.unwrap()];
585585
let hir_end = &body[end.unwrap()];
586586

crates/hir-def/src/hir.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,7 @@ pub enum Pat {
661661
Range {
662662
start: Option<ExprId>,
663663
end: Option<ExprId>,
664+
range_type: RangeOp,
664665
},
665666
Slice {
666667
prefix: Box<[PatId]>,

crates/hir-ty/src/infer/expr.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -772,8 +772,7 @@ impl<'db> InferenceContext<'_, 'db> {
772772
Expr::Range { lhs, rhs, range_type } => {
773773
let lhs_ty =
774774
lhs.map(|e| self.infer_expr_inner(e, &Expectation::none(), ExprIsRead::Yes));
775-
let rhs_expect =
776-
lhs_ty.as_ref().map_or_else(Expectation::none, |ty| Expectation::has_type(*ty));
775+
let rhs_expect = lhs_ty.map_or_else(Expectation::none, Expectation::has_type);
777776
let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect, ExprIsRead::Yes));
778777
let single_arg_adt = |adt, ty: Ty<'db>| {
779778
Ty::new_adt(

crates/hir-ty/src/infer/pat.rs

Lines changed: 46 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use hir_expand::name::Name;
1111
use rustc_ast_ir::Mutability;
1212
use rustc_type_ir::inherent::{GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Ty as _};
1313
use stdx::TupleExt;
14+
use syntax::ast::RangeOp;
1415

1516
use crate::{
1617
DeclContext, DeclOrigin, InferenceDiagnostic,
@@ -349,9 +350,51 @@ impl<'db> InferenceContext<'_, 'db> {
349350
self.infer_slice_pat(expected, prefix, *slice, suffix, default_bm, decl)
350351
}
351352
Pat::Wild => expected,
352-
Pat::Range { .. } => {
353-
// FIXME: do some checks here.
354-
expected
353+
Pat::Range { start, end, range_type } => {
354+
// FIXME: Expectation
355+
let lhs_expectation = Expectation::none();
356+
let lhs_ty =
357+
start.map(|start| self.infer_expr(start, &lhs_expectation, ExprIsRead::Yes));
358+
let rhs_expectation = lhs_ty.map_or_else(Expectation::none, Expectation::HasType);
359+
let rhs_ty = end.map(|end| self.infer_expr(end, &rhs_expectation, ExprIsRead::Yes));
360+
let single_arg_adt = |adt, ty: Ty<'db>| {
361+
Ty::new_adt(
362+
self.interner(),
363+
adt,
364+
GenericArgs::new_from_iter(self.interner(), [ty.into()]),
365+
)
366+
};
367+
match (range_type, lhs_ty, rhs_ty) {
368+
(RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
369+
Some(adt) => Ty::new_adt(self.interner(), adt, self.types.empty_args),
370+
None => self.err_ty(),
371+
},
372+
(RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
373+
Some(adt) => single_arg_adt(adt, ty),
374+
None => self.err_ty(),
375+
},
376+
(RangeOp::Inclusive, None, Some(ty)) => {
377+
match self.resolve_range_to_inclusive() {
378+
Some(adt) => single_arg_adt(adt, ty),
379+
None => self.err_ty(),
380+
}
381+
}
382+
(RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
383+
Some(adt) => single_arg_adt(adt, ty),
384+
None => self.err_ty(),
385+
},
386+
(RangeOp::Inclusive, Some(_), Some(ty)) => {
387+
match self.resolve_range_inclusive() {
388+
Some(adt) => single_arg_adt(adt, ty),
389+
None => self.err_ty(),
390+
}
391+
}
392+
(RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
393+
Some(adt) => single_arg_adt(adt, ty),
394+
None => self.err_ty(),
395+
},
396+
(RangeOp::Inclusive, _, None) => self.err_ty(),
397+
}
355398
}
356399
&Pat::Lit(expr) => {
357400
// Don't emit type mismatches again, the expression lowering already did that.

crates/hir-ty/src/mir/lower/pattern_matching.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
207207
mode,
208208
)?
209209
}
210-
Pat::Range { start, end } => {
210+
Pat::Range { start, end, range_type: _ } => {
211211
let mut add_check = |l: &ExprId, binop| -> Result<'db, ()> {
212212
let lv = self.lower_literal_or_const_to_operand(self.infer[pattern], l)?;
213213
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());

crates/hir-ty/src/tests/patterns.rs

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -189,24 +189,33 @@ fn infer_literal_pattern() {
189189
fn infer_range_pattern() {
190190
check_infer_with_mismatches(
191191
r#"
192-
fn test(x: &i32) {
193-
if let 1..76 = 2u32 {}
194-
if let 1..=76 = 2u32 {}
195-
}
192+
//- minicore: range
193+
fn test(x..y: &core::ops::Range<u32>) {
194+
if let 1..76 = 2u32 {}
195+
if let 1..=76 = 2u32 {}
196+
}
196197
"#,
197198
expect![[r#"
198-
8..9 'x': &'? i32
199-
17..75 '{ ...2 {} }': ()
200-
23..45 'if let...u32 {}': ()
201-
26..42 'let 1....= 2u32': bool
202-
30..35 '1..76': u32
203-
38..42 '2u32': u32
204-
43..45 '{}': ()
205-
50..73 'if let...u32 {}': ()
206-
53..70 'let 1....= 2u32': bool
207-
57..63 '1..=76': u32
208-
66..70 '2u32': u32
209-
71..73 '{}': ()
199+
8..9 'x': u32
200+
8..12 'x..y': Range<u32>
201+
11..12 'y': u32
202+
38..96 '{ ...2 {} }': ()
203+
44..66 'if let...u32 {}': ()
204+
47..63 'let 1....= 2u32': bool
205+
51..52 '1': i32
206+
51..56 '1..76': Range<i32>
207+
54..56 '76': i32
208+
59..63 '2u32': u32
209+
64..66 '{}': ()
210+
71..94 'if let...u32 {}': ()
211+
74..91 'let 1....= 2u32': bool
212+
78..79 '1': i32
213+
78..84 '1..=76': RangeInclusive<i32>
214+
82..84 '76': i32
215+
87..91 '2u32': u32
216+
92..94 '{}': ()
217+
51..56: expected u32, got Range<i32>
218+
78..84: expected u32, got RangeInclusive<i32>
210219
"#]],
211220
);
212221
}

0 commit comments

Comments
 (0)