Trigger warning when destructuring records using unnamed fields

Comes with a helpful hint and a LSP quickfix, so that it's most
  convenient.
This commit is contained in:
KtorZ
2025-01-22 18:57:22 +01:00
committed by Lucas
parent b25afa2d0d
commit 05264bc423
3 changed files with 103 additions and 0 deletions

View File

@@ -1823,6 +1823,16 @@ pub enum Warning {
location: Span,
value: String,
},
#[error("I tripped over a confusing constructor destructuring")]
#[diagnostic(help("Try instead: \n\n{}", format_pattern_suggestion(suggestion)))]
#[diagnostic(code("syntax::unused_record_fields"))]
#[diagnostic(url("https://aiken-lang.org/language-tour/custom-types#destructuring"))]
UnusedRecordFields {
#[label("prefer destructuring with named fields")]
location: Span,
suggestion: UntypedPattern,
},
}
impl ExtraData for Warning {
@@ -1850,6 +1860,10 @@ impl ExtraData for Warning {
Warning::UnusedImportedValueOrType { location, .. } => {
Some(format!("{},{}", true, location.start))
}
Warning::UnusedRecordFields { suggestion, .. } => {
Some(Formatter::new().pattern(suggestion).to_pretty_string(80))
}
}
}
}
@@ -1893,3 +1907,20 @@ pub fn format_suggestion(sample: &UntypedExpr) -> String {
.collect::<Vec<_>>()
.join("\n")
}
pub fn format_pattern_suggestion(sample: &UntypedPattern) -> String {
Formatter::new()
.pattern(sample)
.to_pretty_string(70)
.lines()
.enumerate()
.map(|(ix, line)| {
if ix == 0 {
format!("╰─▶ {line}")
} else {
format!(" {line}")
}
})
.collect::<Vec<_>>()
.join("\n")
}

View File

@@ -462,6 +462,50 @@ impl<'a, 'b> PatternTyper<'a, 'b> {
}
};
if let Some(field_map) = cons.field_map() {
if !is_record {
let arguments = field_map
.fields
.iter()
.sorted_by(|(a, _), (b, _)| a.cmp(b))
.zip(pattern_args.iter())
.filter_map(|((field, (_, _)), arg)| {
if arg.value.is_discard() {
None
} else {
Some(CallArg {
label: Some(field.clone()),
..arg.clone()
})
}
})
.collect::<Vec<_>>();
let spread_location = if arguments.len() == field_map.fields.len() {
None
} else {
Some(Span {
start: location.end - 3,
end: location.end - 1,
})
};
self.environment.warnings.push(Warning::UnusedRecordFields {
location,
suggestion: Pattern::Constructor {
is_record: true,
location,
name: name.clone(),
arguments,
module: module.clone(),
constructor: (),
spread_location,
tipo: (),
},
});
}
}
let instantiated_constructor_type = self.environment.instantiate(
constructor_typ,
&mut HashMap::new(),