Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/expr_store/lower.rs5
-rw-r--r--crates/hir-def/src/expr_store/pretty.rs13
-rw-r--r--crates/hir-def/src/expr_store/tests/body.rs2
-rw-r--r--crates/hir-def/src/hir.rs1
-rw-r--r--crates/hir-ty/src/infer/expr.rs3
-rw-r--r--crates/hir-ty/src/infer/pat.rs49
-rw-r--r--crates/hir-ty/src/mir/lower/pattern_matching.rs2
-rw-r--r--crates/hir-ty/src/tests/patterns.rs41
8 files changed, 87 insertions, 29 deletions
diff --git a/crates/hir-def/src/expr_store/lower.rs b/crates/hir-def/src/expr_store/lower.rs
index c13a7e92cc..e3bfc5b753 100644
--- a/crates/hir-def/src/expr_store/lower.rs
+++ b/crates/hir-def/src/expr_store/lower.rs
@@ -2410,7 +2410,10 @@ impl ExprCollector<'_> {
let start = range_part_lower(p.start());
let end = range_part_lower(p.end());
// FIXME: Exclusive ended pattern range is stabilised
- Pat::Range { start, end }
+ match p.op_kind() {
+ Some(range_type) => Pat::Range { start, end, range_type },
+ None => Pat::Missing,
+ }
}
};
let ptr = AstPtr::new(&pat);
diff --git a/crates/hir-def/src/expr_store/pretty.rs b/crates/hir-def/src/expr_store/pretty.rs
index 3b3188398e..4ba70938d0 100644
--- a/crates/hir-def/src/expr_store/pretty.rs
+++ b/crates/hir-def/src/expr_store/pretty.rs
@@ -9,7 +9,7 @@ use std::{
use hir_expand::{Lookup, mod_path::PathKind};
use itertools::Itertools;
use span::Edition;
-use syntax::ast::HasName;
+use syntax::ast::{HasName, RangeOp};
use crate::{
AdtId, DefWithBodyId, GenericDefId, TypeParamId, VariantId,
@@ -735,8 +735,8 @@ impl Printer<'_> {
self.print_expr_in(prec, *lhs);
}
match range_type {
- ast::RangeOp::Exclusive => w!(self, ".."),
- ast::RangeOp::Inclusive => w!(self, "..="),
+ RangeOp::Exclusive => w!(self, ".."),
+ RangeOp::Inclusive => w!(self, "..="),
};
if let Some(rhs) = rhs {
self.print_expr_in(prec, *rhs);
@@ -937,11 +937,14 @@ impl Printer<'_> {
});
w!(self, "}}");
}
- Pat::Range { start, end } => {
+ Pat::Range { start, end, range_type } => {
if let Some(start) = start {
self.print_expr_in(prec, *start);
}
- w!(self, "..=");
+ match range_type {
+ RangeOp::Inclusive => w!(self, "..="),
+ RangeOp::Exclusive => w!(self, ".."),
+ }
if let Some(end) = end {
self.print_expr_in(prec, *end);
}
diff --git a/crates/hir-def/src/expr_store/tests/body.rs b/crates/hir-def/src/expr_store/tests/body.rs
index 0a982b9e39..4a775568bc 100644
--- a/crates/hir-def/src/expr_store/tests/body.rs
+++ b/crates/hir-def/src/expr_store/tests/body.rs
@@ -580,7 +580,7 @@ const fn f(x: i32) -> i32 {
let MatchArm { pat, .. } = mtch_arms[1];
match body[pat] {
- Pat::Range { start, end } => {
+ Pat::Range { start, end, range_type: _ } => {
let hir_start = &body[start.unwrap()];
let hir_end = &body[end.unwrap()];
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index 8ca8308512..66eade2245 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -661,6 +661,7 @@ pub enum Pat {
Range {
start: Option<ExprId>,
end: Option<ExprId>,
+ range_type: RangeOp,
},
Slice {
prefix: Box<[PatId]>,
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 50bc70f4ee..7487660a76 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -772,8 +772,7 @@ impl<'db> InferenceContext<'_, 'db> {
Expr::Range { lhs, rhs, range_type } => {
let lhs_ty =
lhs.map(|e| self.infer_expr_inner(e, &Expectation::none(), ExprIsRead::Yes));
- let rhs_expect =
- lhs_ty.as_ref().map_or_else(Expectation::none, |ty| Expectation::has_type(*ty));
+ let rhs_expect = lhs_ty.map_or_else(Expectation::none, Expectation::has_type);
let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect, ExprIsRead::Yes));
let single_arg_adt = |adt, ty: Ty<'db>| {
Ty::new_adt(
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index b3cf94aef4..d8b02dea15 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -11,6 +11,7 @@ use hir_expand::name::Name;
use rustc_ast_ir::Mutability;
use rustc_type_ir::inherent::{GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Ty as _};
use stdx::TupleExt;
+use syntax::ast::RangeOp;
use crate::{
DeclContext, DeclOrigin, InferenceDiagnostic,
@@ -349,9 +350,51 @@ impl<'db> InferenceContext<'_, 'db> {
self.infer_slice_pat(expected, prefix, *slice, suffix, default_bm, decl)
}
Pat::Wild => expected,
- Pat::Range { .. } => {
- // FIXME: do some checks here.
- expected
+ Pat::Range { start, end, range_type } => {
+ // FIXME: Expectation
+ let lhs_expectation = Expectation::none();
+ let lhs_ty =
+ start.map(|start| self.infer_expr(start, &lhs_expectation, ExprIsRead::Yes));
+ let rhs_expectation = lhs_ty.map_or_else(Expectation::none, Expectation::HasType);
+ let rhs_ty = end.map(|end| self.infer_expr(end, &rhs_expectation, ExprIsRead::Yes));
+ let single_arg_adt = |adt, ty: Ty<'db>| {
+ Ty::new_adt(
+ self.interner(),
+ adt,
+ GenericArgs::new_from_iter(self.interner(), [ty.into()]),
+ )
+ };
+ match (range_type, lhs_ty, rhs_ty) {
+ (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
+ Some(adt) => Ty::new_adt(self.interner(), adt, self.types.empty_args),
+ None => self.err_ty(),
+ },
+ (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
+ Some(adt) => single_arg_adt(adt, ty),
+ None => self.err_ty(),
+ },
+ (RangeOp::Inclusive, None, Some(ty)) => {
+ match self.resolve_range_to_inclusive() {
+ Some(adt) => single_arg_adt(adt, ty),
+ None => self.err_ty(),
+ }
+ }
+ (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
+ Some(adt) => single_arg_adt(adt, ty),
+ None => self.err_ty(),
+ },
+ (RangeOp::Inclusive, Some(_), Some(ty)) => {
+ match self.resolve_range_inclusive() {
+ Some(adt) => single_arg_adt(adt, ty),
+ None => self.err_ty(),
+ }
+ }
+ (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
+ Some(adt) => single_arg_adt(adt, ty),
+ None => self.err_ty(),
+ },
+ (RangeOp::Inclusive, _, None) => self.err_ty(),
+ }
}
&Pat::Lit(expr) => {
// Don't emit type mismatches again, the expression lowering already did that.
diff --git a/crates/hir-ty/src/mir/lower/pattern_matching.rs b/crates/hir-ty/src/mir/lower/pattern_matching.rs
index c722a807d7..c3a4814a3a 100644
--- a/crates/hir-ty/src/mir/lower/pattern_matching.rs
+++ b/crates/hir-ty/src/mir/lower/pattern_matching.rs
@@ -207,7 +207,7 @@ impl<'db> MirLowerCtx<'_, 'db> {
mode,
)?
}
- Pat::Range { start, end } => {
+ Pat::Range { start, end, range_type: _ } => {
let mut add_check = |l: &ExprId, binop| -> Result<'db, ()> {
let lv = self.lower_literal_or_const_to_operand(self.infer[pattern], l)?;
let else_target = *current_else.get_or_insert_with(|| self.new_basic_block());
diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs
index 5d81d52ec7..5e150e2bcc 100644
--- a/crates/hir-ty/src/tests/patterns.rs
+++ b/crates/hir-ty/src/tests/patterns.rs
@@ -189,24 +189,33 @@ fn infer_literal_pattern() {
fn infer_range_pattern() {
check_infer_with_mismatches(
r#"
- fn test(x: &i32) {
- if let 1..76 = 2u32 {}
- if let 1..=76 = 2u32 {}
- }
+//- minicore: range
+fn test(x..y: &core::ops::Range<u32>) {
+ if let 1..76 = 2u32 {}
+ if let 1..=76 = 2u32 {}
+}
"#,
expect![[r#"
- 8..9 'x': &'? i32
- 17..75 '{ ...2 {} }': ()
- 23..45 'if let...u32 {}': ()
- 26..42 'let 1....= 2u32': bool
- 30..35 '1..76': u32
- 38..42 '2u32': u32
- 43..45 '{}': ()
- 50..73 'if let...u32 {}': ()
- 53..70 'let 1....= 2u32': bool
- 57..63 '1..=76': u32
- 66..70 '2u32': u32
- 71..73 '{}': ()
+ 8..9 'x': u32
+ 8..12 'x..y': Range<u32>
+ 11..12 'y': u32
+ 38..96 '{ ...2 {} }': ()
+ 44..66 'if let...u32 {}': ()
+ 47..63 'let 1....= 2u32': bool
+ 51..52 '1': i32
+ 51..56 '1..76': Range<i32>
+ 54..56 '76': i32
+ 59..63 '2u32': u32
+ 64..66 '{}': ()
+ 71..94 'if let...u32 {}': ()
+ 74..91 'let 1....= 2u32': bool
+ 78..79 '1': i32
+ 78..84 '1..=76': RangeInclusive<i32>
+ 82..84 '76': i32
+ 87..91 '2u32': u32
+ 92..94 '{}': ()
+ 51..56: expected u32, got Range<i32>
+ 78..84: expected u32, got RangeInclusive<i32>
"#]],
);
}