forked from M-Labs/nac3
Compare commits
1 Commits
Author | SHA1 | Date |
---|---|---|
z78078 | 74b9416174 |
|
@ -66,7 +66,6 @@ pub fn get_exn_constructor(
|
||||||
object_id: DefinitionId(class_id),
|
object_id: DefinitionId(class_id),
|
||||||
type_vars: Default::default(),
|
type_vars: Default::default(),
|
||||||
fields: exception_fields,
|
fields: exception_fields,
|
||||||
static_fields: Default::default(),
|
|
||||||
methods: vec![("__init__".into(), signature, DefinitionId(cons_id))],
|
methods: vec![("__init__".into(), signature, DefinitionId(cons_id))],
|
||||||
ancestors: vec![
|
ancestors: vec![
|
||||||
TypeAnnotation::CustomClass { id: DefinitionId(class_id), params: Default::default() },
|
TypeAnnotation::CustomClass { id: DefinitionId(class_id), params: Default::default() },
|
||||||
|
@ -176,7 +175,6 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
type_vars: Default::default(),
|
type_vars: Default::default(),
|
||||||
fields: exception_fields,
|
fields: exception_fields,
|
||||||
methods: Default::default(),
|
methods: Default::default(),
|
||||||
static_fields: Default::default(),
|
|
||||||
ancestors: vec![],
|
ancestors: vec![],
|
||||||
constructor: None,
|
constructor: None,
|
||||||
resolver: None,
|
resolver: None,
|
||||||
|
@ -202,7 +200,6 @@ pub fn get_builtins(primitives: &mut (PrimitiveStore, Unifier)) -> BuiltinInfo {
|
||||||
object_id: DefinitionId(10),
|
object_id: DefinitionId(10),
|
||||||
type_vars: vec![option_ty_var],
|
type_vars: vec![option_ty_var],
|
||||||
fields: vec![],
|
fields: vec![],
|
||||||
static_fields: vec![],
|
|
||||||
methods: vec![
|
methods: vec![
|
||||||
("is_some".into(), is_some_ty.0, DefinitionId(11)),
|
("is_some".into(), is_some_ty.0, DefinitionId(11)),
|
||||||
("is_none".into(), is_some_ty.0, DefinitionId(12)),
|
("is_none".into(), is_some_ty.0, DefinitionId(12)),
|
||||||
|
|
|
@ -1040,7 +1040,6 @@ impl TopLevelComposer {
|
||||||
class_body_ast,
|
class_body_ast,
|
||||||
_class_ancestor_def,
|
_class_ancestor_def,
|
||||||
class_fields_def,
|
class_fields_def,
|
||||||
class_static_fields_def,
|
|
||||||
class_methods_def,
|
class_methods_def,
|
||||||
class_type_vars_def,
|
class_type_vars_def,
|
||||||
class_resolver,
|
class_resolver,
|
||||||
|
@ -1048,7 +1047,6 @@ impl TopLevelComposer {
|
||||||
object_id,
|
object_id,
|
||||||
ancestors,
|
ancestors,
|
||||||
fields,
|
fields,
|
||||||
static_fields,
|
|
||||||
methods,
|
methods,
|
||||||
resolver,
|
resolver,
|
||||||
type_vars,
|
type_vars,
|
||||||
|
@ -1056,7 +1054,7 @@ impl TopLevelComposer {
|
||||||
} = &mut *class_def
|
} = &mut *class_def
|
||||||
{
|
{
|
||||||
if let ast::StmtKind::ClassDef { name, bases, body, .. } = &class_ast {
|
if let ast::StmtKind::ClassDef { name, bases, body, .. } = &class_ast {
|
||||||
(*object_id, *name, bases, body, ancestors, fields, static_fields, methods, type_vars, resolver)
|
(*object_id, *name, bases, body, ancestors, fields, methods, type_vars, resolver)
|
||||||
} else {
|
} else {
|
||||||
unreachable!("here must be class def ast");
|
unreachable!("here must be class def ast");
|
||||||
}
|
}
|
||||||
|
@ -1270,7 +1268,7 @@ impl TopLevelComposer {
|
||||||
.unify(method_dummy_ty, method_type)
|
.unify(method_dummy_ty, method_type)
|
||||||
.map_err(|e| e.to_display(unifier).to_string())?;
|
.map_err(|e| e.to_display(unifier).to_string())?;
|
||||||
}
|
}
|
||||||
ast::StmtKind::AnnAssign { target, annotation, value, .. } => {
|
ast::StmtKind::AnnAssign { target, annotation, value: None, .. } => {
|
||||||
if let ast::ExprKind::Name { id: attr, .. } = &target.node {
|
if let ast::ExprKind::Name { id: attr, .. } = &target.node {
|
||||||
if defined_fields.insert(attr.to_string()) {
|
if defined_fields.insert(attr.to_string()) {
|
||||||
let dummy_field_type = unifier.get_dummy_var().0;
|
let dummy_field_type = unifier.get_dummy_var().0;
|
||||||
|
@ -1296,9 +1294,6 @@ impl TopLevelComposer {
|
||||||
_ if core_config.kernel_ann.is_none() => (annotation, true),
|
_ if core_config.kernel_ann.is_none() => (annotation, true),
|
||||||
_ => continue, // ignore fields annotated otherwise
|
_ => continue, // ignore fields annotated otherwise
|
||||||
};
|
};
|
||||||
if let Option::Some(..) = &value{
|
|
||||||
class_static_fields_def.push((*attr, dummy_field_type, mutable));
|
|
||||||
}
|
|
||||||
class_fields_def.push((*attr, dummy_field_type, mutable));
|
class_fields_def.push((*attr, dummy_field_type, mutable));
|
||||||
|
|
||||||
let parsed_annotation = parse_ast_to_type_annotation_kinds(
|
let parsed_annotation = parse_ast_to_type_annotation_kinds(
|
||||||
|
@ -1329,7 +1324,7 @@ impl TopLevelComposer {
|
||||||
type_var_to_concrete_def.insert(dummy_field_type, parsed_annotation);
|
type_var_to_concrete_def.insert(dummy_field_type, parsed_annotation);
|
||||||
} else {
|
} else {
|
||||||
return Err(format!(
|
return Err(format!(
|
||||||
"same class field `{}` defined twice (at {})",
|
"same class fields `{}` defined twice (at {})",
|
||||||
attr, target.location
|
attr, target.location
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
@ -1340,27 +1335,7 @@ impl TopLevelComposer {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast::StmtKind::Assign { targets, value, .. } => {
|
ast::StmtKind::Assign { .. } => {}, // we don't class attributes
|
||||||
for target in targets {
|
|
||||||
if let ast::ExprKind::Name { id: attr, .. } = &target.node {
|
|
||||||
if defined_fields.insert(attr.to_string()) {
|
|
||||||
let dummy_field_type = unifier.get_dummy_var().0;
|
|
||||||
class_static_fields_def.push((*attr, dummy_field_type, true));
|
|
||||||
class_fields_def.push((*attr, dummy_field_type, true));
|
|
||||||
} else {
|
|
||||||
return Err(format!(
|
|
||||||
"same class field `{}` defined twice (at {})",
|
|
||||||
attr, target.location
|
|
||||||
));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(format!(
|
|
||||||
"unsupported statement type in class definition body (at {})",
|
|
||||||
target.location
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ast::StmtKind::Pass { .. } => {}
|
ast::StmtKind::Pass { .. } => {}
|
||||||
ast::StmtKind::Expr { value: _, .. } => {} // typically a docstring; ignoring all expressions matches CPython behavior
|
ast::StmtKind::Expr { value: _, .. } => {} // typically a docstring; ignoring all expressions matches CPython behavior
|
||||||
_ => {
|
_ => {
|
||||||
|
@ -1534,6 +1509,7 @@ impl TopLevelComposer {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut errors = HashSet::new();
|
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 mut analyze = |i, def: &Arc<RwLock<TopLevelDef>>, ast: &Option<Stmt>| {
|
||||||
let class_def = def.read();
|
let class_def = def.read();
|
||||||
if let TopLevelDef::Class {
|
if let TopLevelDef::Class {
|
||||||
|
@ -1541,7 +1517,6 @@ impl TopLevelComposer {
|
||||||
ancestors,
|
ancestors,
|
||||||
methods,
|
methods,
|
||||||
fields,
|
fields,
|
||||||
static_fields,
|
|
||||||
type_vars,
|
type_vars,
|
||||||
name: class_name,
|
name: class_name,
|
||||||
object_id,
|
object_id,
|
||||||
|
@ -1643,12 +1618,42 @@ impl TopLevelComposer {
|
||||||
if *name != init_str_id {
|
if *name != init_str_id {
|
||||||
unreachable!("must be init function here")
|
unreachable!("must be init function here")
|
||||||
}
|
}
|
||||||
let all_inited = Self::get_all_assigned_field(body.as_slice())?;
|
|
||||||
for f in fields {
|
let locally_inited_fields = Self::get_all_assigned_field(body.as_slice())?;
|
||||||
if !all_inited.contains(&f.0) && !static_fields.contains(&f) {
|
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!(
|
return Err(format!(
|
||||||
"fields `{}` of class `{}` not fully initialized in the initializer (at {})",
|
"fields `{}` of class `{}` not fully initialized in the initializer (at {})",
|
||||||
&f.0,
|
field,
|
||||||
class_name,
|
class_name,
|
||||||
body[0].location,
|
body[0].location,
|
||||||
));
|
));
|
||||||
|
|
|
@ -162,7 +162,6 @@ impl TopLevelComposer {
|
||||||
object_id: DefinitionId(index),
|
object_id: DefinitionId(index),
|
||||||
type_vars: Default::default(),
|
type_vars: Default::default(),
|
||||||
fields: Default::default(),
|
fields: Default::default(),
|
||||||
static_fields: Default::default(),
|
|
||||||
methods: Default::default(),
|
methods: Default::default(),
|
||||||
ancestors: Default::default(),
|
ancestors: Default::default(),
|
||||||
constructor,
|
constructor,
|
||||||
|
|
|
@ -91,8 +91,6 @@ pub enum TopLevelDef {
|
||||||
// class fields
|
// class fields
|
||||||
// name, type, is mutable
|
// name, type, is mutable
|
||||||
fields: Vec<(StrRef, Type, bool)>,
|
fields: Vec<(StrRef, Type, bool)>,
|
||||||
// list of static data members
|
|
||||||
static_fields: Vec<(StrRef, Type, bool)>,
|
|
||||||
// class methods, pointing to the corresponding function definition.
|
// class methods, pointing to the corresponding function definition.
|
||||||
methods: Vec<(StrRef, Type, DefinitionId)>,
|
methods: Vec<(StrRef, Type, DefinitionId)>,
|
||||||
// ancestor classes, including itself.
|
// ancestor classes, including itself.
|
||||||
|
|
Loading…
Reference in New Issue