Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 62d6b5a

Browse files
committed
Generalize some inference functions for patterns
1 parent c1c8675 commit 62d6b5a

File tree

2 files changed

+107
-64
lines changed

2 files changed

+107
-64
lines changed

crates/hir-ty/src/infer.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,31 @@ impl Default for BindingMode {
125125
}
126126
}
127127

128+
/// Used to generalize patterns and assignee expressions.
129+
trait PatLike: Into<ExprOrPatId> + Copy {
130+
type BindingMode: Copy;
131+
132+
fn infer(
133+
this: &mut InferenceContext,
134+
id: Self,
135+
expected_ty: &Ty,
136+
default_bm: Self::BindingMode,
137+
) -> Ty;
138+
}
139+
140+
impl PatLike for PatId {
141+
type BindingMode = BindingMode;
142+
143+
fn infer(
144+
this: &mut InferenceContext,
145+
id: Self,
146+
expected_ty: &Ty,
147+
default_bm: Self::BindingMode,
148+
) -> Ty {
149+
this.infer_pat(id, expected_ty, default_bm)
150+
}
151+
}
152+
128153
#[derive(Debug)]
129154
pub(crate) struct InferOk<T> {
130155
value: T,

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

Lines changed: 82 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::iter::repeat_with;
44

55
use chalk_ir::Mutability;
66
use hir_def::{
7-
expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat},
7+
expr::{BindingAnnotation, Expr, Literal, Pat, PatId},
88
path::Path,
99
type_ref::ConstScalar,
1010
};
@@ -17,15 +17,20 @@ use crate::{
1717
TyKind,
1818
};
1919

20+
use super::PatLike;
21+
2022
impl<'a> InferenceContext<'a> {
21-
fn infer_tuple_struct_pat(
23+
/// Infers type for tuple struct pattern or its corresponding assignee expression.
24+
///
25+
/// Ellipses found in the original pattern or expression must be filtered out.
26+
pub(super) fn infer_tuple_struct_pat_like<T: PatLike>(
2227
&mut self,
2328
path: Option<&Path>,
24-
subpats: &[PatId],
2529
expected: &Ty,
26-
default_bm: BindingMode,
27-
id: PatId,
30+
default_bm: T::BindingMode,
31+
id: T,
2832
ellipsis: Option<usize>,
33+
subs: &[T],
2934
) -> Ty {
3035
let (ty, def) = self.resolve_variant(path, true);
3136
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
@@ -39,8 +44,8 @@ impl<'a> InferenceContext<'a> {
3944

4045
let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
4146
let (pre, post) = match ellipsis {
42-
Some(idx) => subpats.split_at(idx),
43-
None => (subpats, &[][..]),
47+
Some(idx) => subs.split_at(idx),
48+
None => (subs, &[][..]),
4449
};
4550
let post_idx_offset = field_tys.iter().count().saturating_sub(post.len());
4651

@@ -54,22 +59,22 @@ impl<'a> InferenceContext<'a> {
5459
field_tys[field].clone().substitute(Interner, &substs)
5560
});
5661
let expected_ty = self.normalize_associated_types_in(expected_ty);
57-
self.infer_pat(subpat, &expected_ty, default_bm);
62+
T::infer(self, subpat, &expected_ty, default_bm);
5863
}
5964

6065
ty
6166
}
6267

63-
fn infer_record_pat(
68+
/// Infers type for record pattern or its corresponding assignee expression.
69+
pub(super) fn infer_record_pat_like<T: PatLike>(
6470
&mut self,
6571
path: Option<&Path>,
66-
subpats: &[RecordFieldPat],
6772
expected: &Ty,
68-
default_bm: BindingMode,
69-
id: PatId,
73+
default_bm: T::BindingMode,
74+
id: T,
75+
subs: impl Iterator<Item = (Name, T)>,
7076
) -> Ty {
7177
let (ty, def) = self.resolve_variant(path, false);
72-
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
7378
if let Some(variant) = def {
7479
self.write_variant_resolution(id.into(), variant);
7580
}
@@ -80,18 +85,64 @@ impl<'a> InferenceContext<'a> {
8085
ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
8186

8287
let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
83-
for subpat in subpats {
84-
let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
85-
let expected_ty = matching_field.map_or(self.err_ty(), |field| {
86-
field_tys[field].clone().substitute(Interner, &substs)
87-
});
88+
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
89+
90+
for (name, inner) in subs {
91+
let expected_ty = var_data
92+
.as_ref()
93+
.and_then(|it| it.field(&name))
94+
.map_or(self.err_ty(), |f| field_tys[f].clone().substitute(Interner, &substs));
8895
let expected_ty = self.normalize_associated_types_in(expected_ty);
89-
self.infer_pat(subpat.pat, &expected_ty, default_bm);
96+
97+
T::infer(self, inner, &expected_ty, default_bm);
9098
}
9199

92100
ty
93101
}
94102

103+
/// Infers type for tuple pattern or its corresponding assignee expression.
104+
///
105+
/// Ellipses found in the original pattern or expression must be filtered out.
106+
pub(super) fn infer_tuple_pat_like<T: PatLike>(
107+
&mut self,
108+
expected: &Ty,
109+
default_bm: T::BindingMode,
110+
ellipsis: Option<usize>,
111+
subs: &[T],
112+
) -> Ty {
113+
let expectations = match expected.as_tuple() {
114+
Some(parameters) => &*parameters.as_slice(Interner),
115+
_ => &[],
116+
};
117+
118+
let ((pre, post), n_uncovered_patterns) = match ellipsis {
119+
Some(idx) => (subs.split_at(idx), expectations.len().saturating_sub(subs.len())),
120+
None => ((&subs[..], &[][..]), 0),
121+
};
122+
let mut expectations_iter = expectations
123+
.iter()
124+
.cloned()
125+
.map(|a| a.assert_ty_ref(Interner).clone())
126+
.chain(repeat_with(|| self.table.new_type_var()));
127+
128+
let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + subs.len());
129+
130+
inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns + subs.len()));
131+
132+
// Process pre
133+
for (ty, pat) in inner_tys.iter_mut().zip(pre) {
134+
*ty = T::infer(self, *pat, ty, default_bm);
135+
}
136+
137+
// Process post
138+
for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) {
139+
*ty = T::infer(self, *pat, ty, default_bm);
140+
}
141+
142+
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
143+
.intern(Interner)
144+
}
145+
95146
pub(super) fn infer_pat(
96147
&mut self,
97148
pat: PatId,
@@ -129,42 +180,7 @@ impl<'a> InferenceContext<'a> {
129180

130181
let ty = match &self.body[pat] {
131182
Pat::Tuple { args, ellipsis } => {
132-
let expectations = match expected.as_tuple() {
133-
Some(parameters) => &*parameters.as_slice(Interner),
134-
_ => &[],
135-
};
136-
137-
let ((pre, post), n_uncovered_patterns) = match ellipsis {
138-
Some(idx) => {
139-
(args.split_at(*idx), expectations.len().saturating_sub(args.len()))
140-
}
141-
None => ((&args[..], &[][..]), 0),
142-
};
143-
let mut expectations_iter = expectations
144-
.iter()
145-
.cloned()
146-
.map(|a| a.assert_ty_ref(Interner).clone())
147-
.chain(repeat_with(|| self.table.new_type_var()));
148-
149-
let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len());
150-
151-
inner_tys
152-
.extend(expectations_iter.by_ref().take(n_uncovered_patterns + args.len()));
153-
154-
// Process pre
155-
for (ty, pat) in inner_tys.iter_mut().zip(pre) {
156-
*ty = self.infer_pat(*pat, ty, default_bm);
157-
}
158-
159-
// Process post
160-
for (ty, pat) in
161-
inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post)
162-
{
163-
*ty = self.infer_pat(*pat, ty, default_bm);
164-
}
165-
166-
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
167-
.intern(Interner)
183+
self.infer_tuple_pat_like(&expected, default_bm, *ellipsis, args)
168184
}
169185
Pat::Or(pats) => {
170186
if let Some((first_pat, rest)) = pats.split_first() {
@@ -191,16 +207,18 @@ impl<'a> InferenceContext<'a> {
191207
let subty = self.infer_pat(*pat, &expectation, default_bm);
192208
TyKind::Ref(mutability, static_lifetime(), subty).intern(Interner)
193209
}
194-
Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat(
195-
p.as_deref(),
196-
subpats,
197-
&expected,
198-
default_bm,
199-
pat,
200-
*ellipsis,
201-
),
210+
Pat::TupleStruct { path: p, args: subpats, ellipsis } => self
211+
.infer_tuple_struct_pat_like(
212+
p.as_deref(),
213+
&expected,
214+
default_bm,
215+
pat,
216+
*ellipsis,
217+
subpats,
218+
),
202219
Pat::Record { path: p, args: fields, ellipsis: _ } => {
203-
self.infer_record_pat(p.as_deref(), fields, &expected, default_bm, pat)
220+
let subs = fields.iter().map(|f| (f.name.clone(), f.pat));
221+
self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat.into(), subs)
204222
}
205223
Pat::Path(path) => {
206224
// FIXME use correct resolver for the surrounding expression

0 commit comments

Comments
 (0)