nac3core: add fields initialization check for parent class #310

Open
z78078 wants to merge 1 commits from issue-136 into master
1 changed files with 35 additions and 4 deletions

View File

@ -1509,6 +1509,7 @@ impl TopLevelComposer {
}
let mut errors = HashSet::new();
let mut inited_fields_cache: HashMap<DefinitionId, Vec<StrRef>> = HashMap::new();
let mut analyze = |i, def: &Arc<RwLock<TopLevelDef>>, ast: &Option<Stmt>| {
let class_def = def.read();
if let TopLevelDef::Class {
@ -1617,12 +1618,42 @@ impl TopLevelComposer {
if *name != init_str_id {
unreachable!("must be init function here")
}
let all_inited = Self::get_all_assigned_field(body.as_slice())?;
for (f, _, _) in fields {
if !all_inited.contains(f) {
let locally_inited_fields = Self::get_all_assigned_field(body.as_slice())?;
for field in locally_inited_fields.iter() {
inited_fields_cache
.entry(*object_id)
.and_modify(|v| v.push(*field))
.or_insert(vec![*field]);
}
let not_locally_inited_fields = fields
.iter()
.filter_map(|(field, _, _)| if !locally_inited_fields.contains(field) { Some(*field) } else { None } );
let mut ancestors_id = ancestors
.iter()
.skip(1)
.filter_map(|ancestor| {
match ancestor {
TypeAnnotation::CustomClass { id, .. } => Some(*id),
_ => None
}
});
for field in not_locally_inited_fields {
let ancestor_inited = ancestors_id.any(|id| {
if let Some(ancestor_inited_fields) = inited_fields_cache.get(&id) {
ancestor_inited_fields.contains(&field)
} else {
false
}
});
if !ancestor_inited {
return Err(format!(
"fields `{}` of class `{}` not fully initialized in the initializer (at {})",
f,
field,
class_name,
body[0].location,
));