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
|
### Changed
|
||||||
|
|
||||||
- **aiken-lang**: block `Data` and `String` from unifying when casting
|
- **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`
|
- **aiken-project**: tests filtering with `-m` during check now happens in `Project::collect_tests`
|
||||||
|
|
||||||
## [v0.0.29] - 2023-MM-DD
|
## [v0.0.29] - 2023-MM-DD
|
||||||
|
|
|
@ -177,6 +177,7 @@ impl<'a> Environment<'a> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Some(fields))
|
Ok(Some(fields))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1780,44 +1781,22 @@ fn get_compatible_record_fields<A>(
|
||||||
) -> Vec<(usize, &str, &Annotation)> {
|
) -> Vec<(usize, &str, &Annotation)> {
|
||||||
let mut compatible = vec![];
|
let mut compatible = vec![];
|
||||||
|
|
||||||
|
if constructors.len() > 1 {
|
||||||
|
return compatible;
|
||||||
|
}
|
||||||
|
|
||||||
let first = match constructors.get(0) {
|
let first = match constructors.get(0) {
|
||||||
Some(first) => first,
|
Some(first) => first,
|
||||||
None => return compatible,
|
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
|
// Fields without labels do not have accessors
|
||||||
let label = match first_argument.label.as_ref() {
|
let label = match first_argument.label.as_ref() {
|
||||||
Some(label) => label.as_str(),
|
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))
|
compatible.push((index, label, &first_argument.annotation))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -745,7 +745,7 @@ Perhaps, try the following:
|
||||||
#[diagnostic(code("unknown::record_field"))]
|
#[diagnostic(code("unknown::record_field"))]
|
||||||
#[diagnostic(help(
|
#[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 {
|
UnknownRecordField {
|
||||||
#[label]
|
#[label]
|
||||||
|
|
Loading…
Reference in New Issue