[core] add module type
This commit is contained in:
parent
f15a64cc1b
commit
ce40a46f8a
@ -205,6 +205,19 @@ impl ConcreteTypeStore {
|
|||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
},
|
},
|
||||||
|
TypeEnum::TModule { module_id, attributes } => ConcreteTypeEnum::TModule {
|
||||||
|
module_id: *module_id,
|
||||||
|
methods: attributes
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(name, ty)| match &*unifier.get_ty(ty.0) {
|
||||||
|
TypeEnum::TFunc(..) | TypeEnum::TObj { .. } => None,
|
||||||
|
_ => Some((
|
||||||
|
*name,
|
||||||
|
(self.from_unifier_type(unifier, primitives, ty.0, cache), ty.1),
|
||||||
|
)),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
},
|
||||||
TypeEnum::TVirtual { ty } => ConcreteTypeEnum::TVirtual {
|
TypeEnum::TVirtual { ty } => ConcreteTypeEnum::TVirtual {
|
||||||
ty: self.from_unifier_type(unifier, primitives, *ty, cache),
|
ty: self.from_unifier_type(unifier, primitives, *ty, cache),
|
||||||
},
|
},
|
||||||
|
@ -2008,72 +2008,90 @@ impl Inferencer<'_> {
|
|||||||
ctx: ExprContext,
|
ctx: ExprContext,
|
||||||
) -> InferenceResult {
|
) -> InferenceResult {
|
||||||
let ty = value.custom.unwrap();
|
let ty = value.custom.unwrap();
|
||||||
if let TypeEnum::TObj { obj_id, fields, .. } = &*self.unifier.get_ty(ty) {
|
match &*self.unifier.get_ty(ty) {
|
||||||
// just a fast path
|
TypeEnum::TObj { obj_id, fields, .. } => {
|
||||||
match (fields.get(&attr), ctx == ExprContext::Store) {
|
// just a fast path
|
||||||
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
|
match (fields.get(&attr), ctx == ExprContext::Store) {
|
||||||
(Some((ty, false)), true) => report_type_error(
|
(Some((ty, true)), _) | (Some((ty, false)), false) => Ok(*ty),
|
||||||
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
(Some((ty, false)), true) => report_type_error(
|
||||||
Some(value.location),
|
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
||||||
self.unifier,
|
Some(value.location),
|
||||||
),
|
self.unifier,
|
||||||
(None, mutable) => {
|
),
|
||||||
// Check whether it is a class attribute
|
(None, mutable) => {
|
||||||
let defs = self.top_level.definitions.read();
|
// Check whether it is a class attribute
|
||||||
let result = {
|
let defs = self.top_level.definitions.read();
|
||||||
if let TopLevelDef::Class { attributes, .. } = &*defs[obj_id.0].read() {
|
let result = {
|
||||||
attributes.iter().find_map(|f| {
|
if let TopLevelDef::Class { attributes, .. } = &*defs[obj_id.0].read() {
|
||||||
if f.0 == attr {
|
attributes.iter().find_map(|f| {
|
||||||
return Some(f.1);
|
|
||||||
}
|
|
||||||
None
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
match result {
|
|
||||||
Some(res) if !mutable => Ok(res),
|
|
||||||
Some(_) => report_error(
|
|
||||||
&format!("Class Attribute `{attr}` is immutable"),
|
|
||||||
value.location,
|
|
||||||
),
|
|
||||||
None => report_type_error(
|
|
||||||
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
|
||||||
Some(value.location),
|
|
||||||
self.unifier,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if let TypeEnum::TFunc(sign) = &*self.unifier.get_ty(ty) {
|
|
||||||
// Access Class Attributes of classes with __init__ function using Class names e.g. Foo.ATTR1
|
|
||||||
let result = {
|
|
||||||
self.top_level.definitions.read().iter().find_map(|def| {
|
|
||||||
if let Some(rear_guard) = def.try_read() {
|
|
||||||
if let TopLevelDef::Class { name, attributes, .. } = &*rear_guard {
|
|
||||||
if name.to_string() == self.unifier.stringify(sign.ret) {
|
|
||||||
return attributes.iter().find_map(|f| {
|
|
||||||
if f.0 == attr {
|
if f.0 == attr {
|
||||||
return Some(f.clone().1);
|
return Some(f.1);
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
});
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
match result {
|
||||||
|
Some(res) if !mutable => Ok(res),
|
||||||
|
Some(_) => report_error(
|
||||||
|
&format!("Class Attribute `{attr}` is immutable"),
|
||||||
|
value.location,
|
||||||
|
),
|
||||||
|
None => report_type_error(
|
||||||
|
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
||||||
|
Some(value.location),
|
||||||
|
self.unifier,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None
|
|
||||||
})
|
|
||||||
};
|
|
||||||
match result {
|
|
||||||
Some(f) if ctx != ExprContext::Store => Ok(f),
|
|
||||||
Some(_) => {
|
|
||||||
report_error(&format!("Class Attribute `{attr}` is immutable"), value.location)
|
|
||||||
}
|
}
|
||||||
None => self.infer_general_attribute(value, attr, ctx),
|
|
||||||
}
|
}
|
||||||
} else {
|
TypeEnum::TFunc(sign) => {
|
||||||
self.infer_general_attribute(value, attr, ctx)
|
// Access Class Attributes of classes with __init__ function using Class names e.g. Foo.ATTR1
|
||||||
|
let result = {
|
||||||
|
self.top_level.definitions.read().iter().find_map(|def| {
|
||||||
|
if let Some(rear_guard) = def.try_read() {
|
||||||
|
if let TopLevelDef::Class { name, attributes, .. } = &*rear_guard {
|
||||||
|
if name.to_string() == self.unifier.stringify(sign.ret) {
|
||||||
|
return attributes.iter().find_map(|f| {
|
||||||
|
if f.0 == attr {
|
||||||
|
return Some(f.clone().1);
|
||||||
|
}
|
||||||
|
None
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
})
|
||||||
|
};
|
||||||
|
match result {
|
||||||
|
Some(f) if ctx != ExprContext::Store => Ok(f),
|
||||||
|
Some(_) => report_error(
|
||||||
|
&format!("Class Attribute `{attr}` is immutable"),
|
||||||
|
value.location,
|
||||||
|
),
|
||||||
|
None => self.infer_general_attribute(value, attr, ctx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
TypeEnum::TModule { attributes, .. } => {
|
||||||
|
match (attributes.get(&attr), ctx == ExprContext::Load) {
|
||||||
|
(Some((ty, _)), true) | (Some((ty, false)), false) => Ok(*ty),
|
||||||
|
(Some((ty, true)), false) => report_type_error(
|
||||||
|
TypeErrorKind::MutationError(RecordKey::Str(attr), *ty),
|
||||||
|
Some(value.location),
|
||||||
|
self.unifier,
|
||||||
|
),
|
||||||
|
(None, _) => report_type_error(
|
||||||
|
TypeErrorKind::NoSuchField(RecordKey::Str(attr), ty),
|
||||||
|
Some(value.location),
|
||||||
|
self.unifier,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => self.infer_general_attribute(value, attr, ctx),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2734,8 +2752,7 @@ impl Inferencer<'_> {
|
|||||||
.read()
|
.read()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|def| match *def.read() {
|
.map(|def| match *def.read() {
|
||||||
TopLevelDef::Class { name, .. }
|
TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. } => (name, false),
|
||||||
| TopLevelDef::Module { name, .. } => (name, false),
|
|
||||||
TopLevelDef::Function { simple_name, .. } => (simple_name, false),
|
TopLevelDef::Function { simple_name, .. } => (simple_name, false),
|
||||||
TopLevelDef::Variable { simple_name, .. } => (simple_name, true),
|
TopLevelDef::Variable { simple_name, .. } => (simple_name, true),
|
||||||
})
|
})
|
||||||
|
@ -270,6 +270,19 @@ pub enum TypeEnum {
|
|||||||
|
|
||||||
/// A function type.
|
/// A function type.
|
||||||
TFunc(FunSignature),
|
TFunc(FunSignature),
|
||||||
|
|
||||||
|
/// Module Type
|
||||||
|
TModule {
|
||||||
|
/// The [`DefinitionId`] of this object type.
|
||||||
|
module_id: DefinitionId,
|
||||||
|
|
||||||
|
/// The attributes present in this object type.
|
||||||
|
///
|
||||||
|
/// The key of the [Mapping] is the identifier of the field, while the value is a tuple
|
||||||
|
/// containing the [Type] of the field, and a `bool` indicating whether the field is a
|
||||||
|
/// variable (as opposed to a function).
|
||||||
|
attributes: Mapping<StrRef, (Type, bool)>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TypeEnum {
|
impl TypeEnum {
|
||||||
@ -284,6 +297,7 @@ impl TypeEnum {
|
|||||||
TypeEnum::TVirtual { .. } => "TVirtual",
|
TypeEnum::TVirtual { .. } => "TVirtual",
|
||||||
TypeEnum::TCall { .. } => "TCall",
|
TypeEnum::TCall { .. } => "TCall",
|
||||||
TypeEnum::TFunc { .. } => "TFunc",
|
TypeEnum::TFunc { .. } => "TFunc",
|
||||||
|
TypeEnum::TModule { .. } => "TModule",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -593,7 +607,8 @@ impl Unifier {
|
|||||||
| TLiteral { .. }
|
| TLiteral { .. }
|
||||||
// functions are instantiated for each call sites, so the function type can contain
|
// functions are instantiated for each call sites, so the function type can contain
|
||||||
// type variables.
|
// type variables.
|
||||||
| TFunc { .. } => true,
|
| TFunc { .. }
|
||||||
|
| TModule { .. } => true,
|
||||||
|
|
||||||
TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)),
|
TVar { .. } => allowed_typevars.iter().any(|b| self.unification_table.unioned(a, *b)),
|
||||||
TCall { .. } => false,
|
TCall { .. } => false,
|
||||||
@ -1315,10 +1330,12 @@ impl Unifier {
|
|||||||
|| format!("{id}"),
|
|| format!("{id}"),
|
||||||
|top_level| {
|
|top_level| {
|
||||||
let top_level_def = &top_level.definitions.read()[id];
|
let top_level_def = &top_level.definitions.read()[id];
|
||||||
let TopLevelDef::Class { name, .. } = &*top_level_def.read() else {
|
let top_level_def = top_level_def.read();
|
||||||
unreachable!("expected class definition")
|
let (TopLevelDef::Class { name, .. } | TopLevelDef::Module { name, .. }) =
|
||||||
|
&*top_level_def
|
||||||
|
else {
|
||||||
|
unreachable!("expected module/class definition")
|
||||||
};
|
};
|
||||||
|
|
||||||
name.to_string()
|
name.to_string()
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@ -1446,6 +1463,10 @@ impl Unifier {
|
|||||||
let ret = self.internal_stringify(signature.ret, obj_to_name, var_to_name, notes);
|
let ret = self.internal_stringify(signature.ret, obj_to_name, var_to_name, notes);
|
||||||
format!("fn[[{params}], {ret}]")
|
format!("fn[[{params}], {ret}]")
|
||||||
}
|
}
|
||||||
|
TypeEnum::TModule { module_id, .. } => {
|
||||||
|
let name = obj_to_name(module_id.0);
|
||||||
|
name.to_string()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1521,7 +1542,9 @@ impl Unifier {
|
|||||||
// variables, i.e. things like TRecord, TCall should not occur, and we
|
// variables, i.e. things like TRecord, TCall should not occur, and we
|
||||||
// should be safe to not implement the substitution for those variants.
|
// should be safe to not implement the substitution for those variants.
|
||||||
match &*ty {
|
match &*ty {
|
||||||
TypeEnum::TRigidVar { .. } | TypeEnum::TLiteral { .. } => None,
|
TypeEnum::TRigidVar { .. } | TypeEnum::TLiteral { .. } | TypeEnum::TModule { .. } => {
|
||||||
|
None
|
||||||
|
}
|
||||||
TypeEnum::TVar { id, .. } => mapping.get(id).copied(),
|
TypeEnum::TVar { id, .. } => mapping.get(id).copied(),
|
||||||
TypeEnum::TTuple { ty, is_vararg_ctx } => {
|
TypeEnum::TTuple { ty, is_vararg_ctx } => {
|
||||||
let mut new_ty = Cow::from(ty);
|
let mut new_ty = Cow::from(ty);
|
||||||
|
Loading…
Reference in New Issue
Block a user