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:
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user