Skip to content

Commit 666b716

Browse files
committed
Move tuple/record handling into separate functions
1 parent 6469e4a commit 666b716

File tree

2 files changed

+91
-50
lines changed

2 files changed

+91
-50
lines changed

fathom/src/surface/elaboration.rs

Lines changed: 79 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1046,19 +1046,12 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
10461046
let (synth_term, synth_type) = self.synth_and_insert_implicit_apps(surface_term);
10471047
self.coerce(surface_range, synth_term, &synth_type, &expected_type)
10481048
}
1049-
(Term::RecordLiteral(_, expr_fields), Value::RecordType(labels, types)) => {
1049+
(Term::RecordLiteral(range, expr_fields), Value::RecordType(labels, types)) => {
10501050
// TODO: improve handling of duplicate labels
1051-
if expr_fields.len() != labels.len()
1052-
|| Iterator::zip(expr_fields.iter(), labels.iter())
1053-
.any(|(expr_field, type_label)| expr_field.label.1 != *type_label)
1051+
if self
1052+
.check_record_fields(*range, expr_fields, |field| field.label, labels)
1053+
.is_err()
10541054
{
1055-
self.push_message(Message::MismatchedFieldLabels {
1056-
range: file_range,
1057-
expr_labels: (expr_fields.iter())
1058-
.map(|ExprField { label, .. }| (self.file_range(label.0), label.1))
1059-
.collect(),
1060-
type_labels: labels.to_vec(),
1061-
});
10621055
return core::Term::Prim(file_range.into(), Prim::ReportedError);
10631056
}
10641057

@@ -1121,33 +1114,11 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
11211114
core::Term::FormatRecord(file_range.into(), labels, formats)
11221115
})
11231116
}
1124-
(Term::Tuple(_, elem_exprs), Value::RecordType(labels, types)) => {
1125-
if elem_exprs.len() != labels.len() {
1126-
let mut expr_labels = Vec::with_capacity(elem_exprs.len());
1127-
let mut elem_exprs = elem_exprs.iter().enumerate().peekable();
1128-
let mut label_iter = labels.iter();
1129-
1130-
// use the label names from the expected type
1131-
while let Some(((_, elem_expr), label)) =
1132-
Option::zip(elem_exprs.peek(), label_iter.next())
1133-
{
1134-
expr_labels.push((self.file_range(elem_expr.range()), *label));
1135-
elem_exprs.next();
1136-
}
1137-
1138-
// use numeric labels for excess elems
1139-
for (index, elem_expr) in elem_exprs {
1140-
expr_labels.push((
1141-
self.file_range(elem_expr.range()),
1142-
self.interner.borrow_mut().get_tuple_label(index),
1143-
));
1144-
}
1145-
1146-
self.push_message(Message::MismatchedFieldLabels {
1147-
range: file_range,
1148-
expr_labels,
1149-
type_labels: labels.to_vec(),
1150-
});
1117+
(Term::Tuple(range, elem_exprs), Value::RecordType(labels, types)) => {
1118+
if self
1119+
.check_tuple_fields(*range, elem_exprs, |term| term.range(), labels)
1120+
.is_err()
1121+
{
11511122
return core::Term::Prim(file_range.into(), Prim::ReportedError);
11521123
}
11531124

@@ -2218,6 +2189,76 @@ impl<'interner, 'arena> Context<'interner, 'arena> {
22182189
(labels, formats.into())
22192190
}
22202191

2192+
fn check_tuple_fields<F>(
2193+
&mut self,
2194+
range: ByteRange,
2195+
fields: &[F],
2196+
get_range: fn(&F) -> ByteRange,
2197+
expected_labels: &[StringId],
2198+
) -> Result<(), ()> {
2199+
if fields.len() == expected_labels.len() {
2200+
return Ok(());
2201+
}
2202+
2203+
let mut found_labels = Vec::with_capacity(fields.len());
2204+
let mut fields_iter = fields.iter().enumerate().peekable();
2205+
let mut expected_labels_iter = expected_labels.iter();
2206+
2207+
// use the label names from the expected labels
2208+
while let Some(((_, field), label)) =
2209+
Option::zip(fields_iter.peek(), expected_labels_iter.next())
2210+
{
2211+
found_labels.push((self.file_range(get_range(field)), *label));
2212+
fields_iter.next();
2213+
}
2214+
2215+
// use numeric labels for excess fields
2216+
for (index, field) in fields_iter {
2217+
found_labels.push((
2218+
self.file_range(get_range(field)),
2219+
self.interner.borrow_mut().get_tuple_label(index),
2220+
));
2221+
}
2222+
2223+
self.push_message(Message::MismatchedFieldLabels {
2224+
range: self.file_range(range),
2225+
found_labels,
2226+
expected_labels: expected_labels.to_vec(),
2227+
});
2228+
Err(())
2229+
}
2230+
2231+
fn check_record_fields<F>(
2232+
&mut self,
2233+
range: ByteRange,
2234+
fields: &[F],
2235+
get_label: impl Fn(&F) -> (ByteRange, StringId),
2236+
labels: &'arena [StringId],
2237+
) -> Result<(), ()> {
2238+
if fields.len() == labels.len()
2239+
&& fields
2240+
.iter()
2241+
.zip(labels.iter())
2242+
.all(|(field, type_label)| get_label(field).1 == *type_label)
2243+
{
2244+
return Ok(());
2245+
}
2246+
2247+
// TODO: improve handling of duplicate labels
2248+
self.push_message(Message::MismatchedFieldLabels {
2249+
range: self.file_range(range),
2250+
found_labels: fields
2251+
.iter()
2252+
.map(|field| {
2253+
let (range, label) = get_label(field);
2254+
(self.file_range(range), label)
2255+
})
2256+
.collect(),
2257+
expected_labels: labels.to_vec(),
2258+
});
2259+
Err(())
2260+
}
2261+
22212262
/// Elaborate a match expression in checking mode
22222263
fn check_match(
22232264
&mut self,

fathom/src/surface/elaboration/reporting.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@ pub enum Message {
5252
},
5353
MismatchedFieldLabels {
5454
range: FileRange,
55-
expr_labels: Vec<(FileRange, StringId)>,
56-
type_labels: Vec<StringId>,
55+
found_labels: Vec<(FileRange, StringId)>,
56+
expected_labels: Vec<StringId>,
5757
// TODO: add expected type
5858
// expected_type: Doc<_>,
5959
},
@@ -243,17 +243,17 @@ impl Message {
243243
}
244244
Message::MismatchedFieldLabels {
245245
range,
246-
expr_labels,
247-
type_labels,
246+
found_labels,
247+
expected_labels,
248248
} => {
249249
let interner = interner.borrow();
250-
let mut diagnostic_labels = Vec::with_capacity(expr_labels.len());
250+
let mut diagnostic_labels = Vec::with_capacity(found_labels.len());
251251
{
252-
let mut type_labels = type_labels.iter().peekable();
252+
let mut expected_labels = expected_labels.iter().peekable();
253253

254-
'expr_labels: for (range, expr_label) in expr_labels.iter() {
254+
'expr_labels: for (range, expr_label) in found_labels.iter() {
255255
'type_labels: loop {
256-
match type_labels.next() {
256+
match expected_labels.next() {
257257
None => {
258258
let expr_label = interner.resolve(*expr_label).unwrap();
259259
diagnostic_labels.push(
@@ -279,10 +279,10 @@ impl Message {
279279
}
280280
}
281281

282-
if type_labels.peek().is_some() {
282+
if expected_labels.peek().is_some() {
283283
diagnostic_labels.push(primary_label(range).with_message(format!(
284284
"missing fields {}",
285-
type_labels
285+
expected_labels
286286
.map(|label| interner.resolve(*label).unwrap())
287287
.format_with(", ", |label, f| f(&format_args!("`{label}`"))),
288288
)));
@@ -292,10 +292,10 @@ impl Message {
292292
}
293293
}
294294

295-
let found_labels = (expr_labels.iter())
295+
let found_labels = (found_labels.iter())
296296
.map(|(_, label)| interner.resolve(*label).unwrap())
297297
.format_with(", ", |label, f| f(&format_args!("`{label}`")));
298-
let expected_labels = (type_labels.iter())
298+
let expected_labels = (expected_labels.iter())
299299
.map(|label| interner.resolve(*label).unwrap())
300300
.format_with(", ", |label, f| f(&format_args!("`{label}`")));
301301

0 commit comments

Comments
 (0)