fix(check): record field access properly restricted to single constr types
This commit is contained in:
parent
ba4635a8b0
commit
553eb88d3d
|
@ -9,6 +9,7 @@
|
|||
### Changed
|
||||
|
||||
- **aiken-lang**: block `Data` and `String` from unifying when casting
|
||||
- **aiken-lang**: remove ability for a type with many variants with matching field labels and types to support field access
|
||||
- **aiken-project**: tests filtering with `-m` during check now happens in `Project::collect_tests`
|
||||
|
||||
## [v0.0.29] - 2023-MM-DD
|
||||
|
|
|
@ -177,6 +177,7 @@ impl<'a> Environment<'a> {
|
|||
},
|
||||
);
|
||||
}
|
||||
|
||||
Ok(Some(fields))
|
||||
}
|
||||
|
||||
|
@ -1780,44 +1781,22 @@ fn get_compatible_record_fields<A>(
|
|||
) -> Vec<(usize, &str, &Annotation)> {
|
||||
let mut compatible = vec![];
|
||||
|
||||
if constructors.len() > 1 {
|
||||
return compatible;
|
||||
}
|
||||
|
||||
let first = match constructors.get(0) {
|
||||
Some(first) => first,
|
||||
None => return compatible,
|
||||
};
|
||||
|
||||
'next_argument: for (index, first_argument) in first.arguments.iter().enumerate() {
|
||||
for (index, first_argument) in first.arguments.iter().enumerate() {
|
||||
// Fields without labels do not have accessors
|
||||
let label = match first_argument.label.as_ref() {
|
||||
Some(label) => label.as_str(),
|
||||
None => continue 'next_argument,
|
||||
None => continue,
|
||||
};
|
||||
|
||||
// Check each variant to see if they have an field in the same position
|
||||
// with the same label and the same type
|
||||
for constructor in constructors.iter().skip(1) {
|
||||
// The field must exist in all variants
|
||||
let argument = match constructor.arguments.get(index) {
|
||||
Some(argument) => argument,
|
||||
None => continue 'next_argument,
|
||||
};
|
||||
|
||||
// The labels must be the same
|
||||
if argument.label != first_argument.label {
|
||||
continue 'next_argument;
|
||||
}
|
||||
|
||||
// The types must be the same
|
||||
if !argument
|
||||
.annotation
|
||||
.is_logically_equal(&first_argument.annotation)
|
||||
{
|
||||
continue 'next_argument;
|
||||
}
|
||||
}
|
||||
|
||||
// The previous loop did not find any incompatible fields in the other
|
||||
// variants so this field is compatible across variants and we should
|
||||
// generate an accessor for it.
|
||||
compatible.push((index, label, &first_argument.annotation))
|
||||
}
|
||||
|
||||
|
|
|
@ -745,7 +745,7 @@ Perhaps, try the following:
|
|||
#[diagnostic(code("unknown::record_field"))]
|
||||
#[diagnostic(help(
|
||||
"{}",
|
||||
suggest_neighbor(label, fields.iter(), "Did you forget to make it public?")
|
||||
suggest_neighbor(label, fields.iter(), "Did you forget to make it public?\n\nAlso record access is only supported on types with one constructor.")
|
||||
))]
|
||||
UnknownRecordField {
|
||||
#[label]
|
||||
|
|
Loading…
Reference in New Issue