mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-03 18:29:00 +00:00
chore: add TyParam::DataClass
This commit is contained in:
parent
e61c0c485e
commit
28d173758f
5 changed files with 166 additions and 9 deletions
|
@ -1831,6 +1831,20 @@ impl Context {
|
|||
}
|
||||
Ok(TyParam::Record(new_rec))
|
||||
}
|
||||
ValueObj::DataClass { name, fields } => {
|
||||
let mut new_fields = dict! {};
|
||||
for (k, v) in fields.into_iter() {
|
||||
let v = match Self::convert_value_into_tp(v) {
|
||||
Ok(tp) => tp,
|
||||
Err(tp) => tp,
|
||||
};
|
||||
new_fields.insert(k, v);
|
||||
}
|
||||
Ok(TyParam::DataClass {
|
||||
name,
|
||||
fields: new_fields,
|
||||
})
|
||||
}
|
||||
_ => Err(TyParam::Value(value)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,13 @@ impl Generalizer {
|
|||
.map(|(field, tp)| (field, self.generalize_tp(tp, uninit)))
|
||||
.collect(),
|
||||
),
|
||||
TyParam::DataClass { name, fields } => {
|
||||
let fields = fields
|
||||
.into_iter()
|
||||
.map(|(field, tp)| (field, self.generalize_tp(tp, uninit)))
|
||||
.collect();
|
||||
TyParam::DataClass { name, fields }
|
||||
}
|
||||
TyParam::Lambda(lambda) => {
|
||||
let nd_params = lambda
|
||||
.nd_params
|
||||
|
@ -449,6 +456,16 @@ impl<'c, 'q, 'l, L: Locational> Dereferencer<'c, 'q, 'l, L> {
|
|||
}
|
||||
Ok(TyParam::Record(new_rec))
|
||||
}
|
||||
TyParam::DataClass { name, fields } => {
|
||||
let mut new_fields = dict! {};
|
||||
for (field, tp) in fields.into_iter() {
|
||||
new_fields.insert(field, self.deref_tp(tp)?);
|
||||
}
|
||||
Ok(TyParam::DataClass {
|
||||
name,
|
||||
fields: new_fields,
|
||||
})
|
||||
}
|
||||
TyParam::Lambda(lambda) => {
|
||||
let nd_params = lambda
|
||||
.nd_params
|
||||
|
|
|
@ -411,6 +411,16 @@ impl Context {
|
|||
.collect::<TyCheckResult<_>>()?;
|
||||
Ok(TyParam::Record(rec))
|
||||
}
|
||||
TyParam::DataClass { name, fields } => {
|
||||
let fields = fields
|
||||
.into_iter()
|
||||
.map(|(k, v)| {
|
||||
let v = self.instantiate_tp(v, tmp_tv_cache, loc)?;
|
||||
Ok((k, v))
|
||||
})
|
||||
.collect::<TyCheckResult<_>>()?;
|
||||
Ok(TyParam::DataClass { name, fields })
|
||||
}
|
||||
TyParam::Lambda(lambda) => {
|
||||
let nd_params = lambda
|
||||
.nd_params
|
||||
|
|
|
@ -207,6 +207,10 @@ pub enum TyParam {
|
|||
Set(Set<TyParam>),
|
||||
Dict(Dict<TyParam, TyParam>),
|
||||
Record(Dict<Field, TyParam>),
|
||||
DataClass {
|
||||
name: Str,
|
||||
fields: Dict<Field, TyParam>,
|
||||
},
|
||||
Lambda(TyParamLambda),
|
||||
Mono(Str),
|
||||
Proj {
|
||||
|
@ -245,6 +249,16 @@ impl PartialEq for TyParam {
|
|||
(Self::Tuple(l), Self::Tuple(r)) => l == r,
|
||||
(Self::Dict(l), Self::Dict(r)) => l == r,
|
||||
(Self::Record(l), Self::Record(r)) => l == r,
|
||||
(
|
||||
Self::DataClass {
|
||||
name: ln,
|
||||
fields: lfs,
|
||||
},
|
||||
Self::DataClass {
|
||||
name: rn,
|
||||
fields: rfs,
|
||||
},
|
||||
) => ln == rn && lfs == rfs,
|
||||
(Self::Set(l), Self::Set(r)) => l == r,
|
||||
(Self::Lambda(l), Self::Lambda(r)) => l == r,
|
||||
(Self::Mono(l), Self::Mono(r)) => l == r,
|
||||
|
@ -423,6 +437,22 @@ impl LimitedDisplay for TyParam {
|
|||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Self::DataClass { name, fields } => {
|
||||
write!(f, "{name} {{")?;
|
||||
for (i, (field, v)) in fields.iter().enumerate() {
|
||||
if i > 0 {
|
||||
write!(f, "; ")?;
|
||||
}
|
||||
if limit.is_positive() && i >= CONTAINER_OMIT_THRESHOLD {
|
||||
write!(f, "...")?;
|
||||
break;
|
||||
}
|
||||
write!(f, "{field} = ")?;
|
||||
v.limited_fmt(f, limit - 1)?;
|
||||
}
|
||||
write!(f, "}}")?;
|
||||
Ok(())
|
||||
}
|
||||
Self::Lambda(lambda) => write!(f, "{lambda}"),
|
||||
Self::Tuple(tuple) => {
|
||||
write!(f, "(")?;
|
||||
|
@ -618,6 +648,13 @@ impl TryFrom<TyParam> for ValueObj {
|
|||
}
|
||||
Ok(ValueObj::Record(vals))
|
||||
}
|
||||
TyParam::DataClass { name, fields } => {
|
||||
let mut vals = dict! {};
|
||||
for (k, v) in fields {
|
||||
vals.insert(k, ValueObj::try_from(v)?);
|
||||
}
|
||||
Ok(ValueObj::DataClass { name, fields: vals })
|
||||
}
|
||||
TyParam::Lambda(lambda) => {
|
||||
// TODO: sig_t
|
||||
let lambda = UserConstSubr::new(
|
||||
|
@ -701,7 +738,7 @@ impl HasLevel for TyParam {
|
|||
.min(v.level().unwrap_or(GENERIC_LEVEL))
|
||||
})
|
||||
.min(),
|
||||
Self::Record(rec) => rec
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => rec
|
||||
.iter()
|
||||
.map(|(_, v)| v.level().unwrap_or(GENERIC_LEVEL))
|
||||
.min(),
|
||||
|
@ -726,7 +763,7 @@ impl HasLevel for TyParam {
|
|||
v.set_level(level);
|
||||
}
|
||||
}
|
||||
Self::Record(rec) => {
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
|
||||
for (_, v) in rec.iter() {
|
||||
v.set_level(level);
|
||||
}
|
||||
|
@ -773,6 +810,9 @@ impl StructuralEq for TyParam {
|
|||
(Self::Array(l), Self::Array(r)) => l.iter().zip(r).all(|(l, r)| l.structural_eq(r)),
|
||||
(Self::Tuple(l), Self::Tuple(r)) => l.iter().zip(r).all(|(l, r)| l.structural_eq(r)),
|
||||
(Self::Dict(l), Self::Dict(r)) => {
|
||||
if l.len() != r.len() {
|
||||
return false;
|
||||
}
|
||||
for (key, val) in l.iter() {
|
||||
if let Some(r_val) = r.get_by(key, |l, r| l.structural_eq(r)) {
|
||||
if !val.structural_eq(r_val) {
|
||||
|
@ -785,6 +825,9 @@ impl StructuralEq for TyParam {
|
|||
true
|
||||
}
|
||||
(Self::Record(l), Self::Record(r)) => {
|
||||
if l.len() != r.len() {
|
||||
return false;
|
||||
}
|
||||
for (l_field, l_val) in l.iter() {
|
||||
if let Some((r_field, r_val)) = r.get_key_value(l_field) {
|
||||
if l_field.vis != r_field.vis || !l_val.structural_eq(r_val) {
|
||||
|
@ -796,6 +839,27 @@ impl StructuralEq for TyParam {
|
|||
}
|
||||
true
|
||||
}
|
||||
(
|
||||
Self::DataClass { name, fields },
|
||||
Self::DataClass {
|
||||
name: r_name,
|
||||
fields: r_fields,
|
||||
},
|
||||
) => {
|
||||
if name != r_name || fields.len() != r_fields.len() {
|
||||
return false;
|
||||
}
|
||||
for (l_field, l_val) in fields.iter() {
|
||||
if let Some((r_field, r_val)) = r_fields.get_key_value(l_field) {
|
||||
if l_field.vis != r_field.vis || !l_val.structural_eq(r_val) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
(Self::Set(l), Self::Set(r)) => {
|
||||
if l.len() != r.len() {
|
||||
return false;
|
||||
|
@ -880,6 +944,17 @@ impl TyParam {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn range(start: Self, end: Self) -> Self {
|
||||
Self::DataClass {
|
||||
name: "Range".into(),
|
||||
fields: dict! {
|
||||
Field::private("start".into()) => start,
|
||||
Field::private("end".into()) => end,
|
||||
Field::private("step".into()) => ValueObj::None.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn free_instance(level: usize, t: Type) -> Self {
|
||||
let constraint = Constraint::new_type_of(t);
|
||||
Self::FreeVar(FreeTyParam::new_unbound(level, constraint))
|
||||
|
@ -1014,7 +1089,7 @@ impl TyParam {
|
|||
Self::Dict(ts) => ts.iter().fold(set! {}, |acc, (k, v)| {
|
||||
acc.concat(k.qvars().concat(v.qvars()))
|
||||
}),
|
||||
Self::Record(rec) => rec
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => rec
|
||||
.iter()
|
||||
.fold(set! {}, |acc, (_, v)| acc.concat(v.qvars())),
|
||||
Self::Lambda(lambda) => lambda
|
||||
|
@ -1039,7 +1114,9 @@ impl TyParam {
|
|||
Self::Array(tps) | Self::Tuple(tps) => tps.iter().any(|tp| tp.has_qvar()),
|
||||
Self::Set(tps) => tps.iter().any(|tp| tp.has_qvar()),
|
||||
Self::Dict(tps) => tps.iter().any(|(k, v)| k.has_qvar() || v.has_qvar()),
|
||||
Self::Record(rec) => rec.iter().any(|(_, tp)| tp.has_qvar()),
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
|
||||
rec.iter().any(|(_, tp)| tp.has_qvar())
|
||||
}
|
||||
Self::Lambda(lambda) => lambda.body.iter().any(|tp| tp.has_qvar()),
|
||||
Self::UnaryOp { val, .. } => val.has_qvar(),
|
||||
Self::BinOp { lhs, rhs, .. } => lhs.has_qvar() || rhs.has_qvar(),
|
||||
|
@ -1061,7 +1138,9 @@ impl TyParam {
|
|||
Self::Dict(ts) => ts
|
||||
.iter()
|
||||
.any(|(k, v)| k.contains_tvar(target) || v.contains_tvar(target)),
|
||||
Self::Record(rec) => rec.iter().any(|(_, tp)| tp.contains_tvar(target)),
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
|
||||
rec.iter().any(|(_, tp)| tp.contains_tvar(target))
|
||||
}
|
||||
Self::Lambda(lambda) => lambda.body.iter().any(|tp| tp.contains_tvar(target)),
|
||||
Self::UnaryOp { val, .. } => val.contains_tvar(target),
|
||||
Self::BinOp { lhs, rhs, .. } => lhs.contains_tvar(target) || rhs.contains_tvar(target),
|
||||
|
@ -1082,7 +1161,9 @@ impl TyParam {
|
|||
Self::Dict(ts) => ts
|
||||
.iter()
|
||||
.any(|(k, v)| k.contains_type(target) || v.contains_type(target)),
|
||||
Self::Record(rec) => rec.iter().any(|(_, tp)| tp.contains_type(target)),
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
|
||||
rec.iter().any(|(_, tp)| tp.contains_type(target))
|
||||
}
|
||||
Self::Lambda(lambda) => lambda.body.iter().any(|tp| tp.contains_type(target)),
|
||||
Self::UnaryOp { val, .. } => val.contains_type(target),
|
||||
Self::BinOp { lhs, rhs, .. } => lhs.contains_type(target) || rhs.contains_type(target),
|
||||
|
@ -1141,7 +1222,9 @@ impl TyParam {
|
|||
Self::Dict(kv) => kv
|
||||
.iter()
|
||||
.any(|(k, v)| k.has_unbound_var() || v.has_unbound_var()),
|
||||
Self::Record(rec) => rec.iter().any(|(_, v)| v.has_unbound_var()),
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
|
||||
rec.iter().any(|(_, v)| v.has_unbound_var())
|
||||
}
|
||||
Self::Lambda(lambda) => lambda.body.iter().any(|t| t.has_unbound_var()),
|
||||
Self::UnaryOp { val, .. } => val.has_unbound_var(),
|
||||
Self::BinOp { lhs, rhs, .. } => lhs.has_unbound_var() || rhs.has_unbound_var(),
|
||||
|
@ -1166,7 +1249,9 @@ impl TyParam {
|
|||
Self::Dict(kv) => kv
|
||||
.iter()
|
||||
.any(|(k, v)| k.has_undoable_linked_var() || v.has_undoable_linked_var()),
|
||||
Self::Record(rec) => rec.iter().any(|(_, v)| v.has_undoable_linked_var()),
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
|
||||
rec.iter().any(|(_, v)| v.has_undoable_linked_var())
|
||||
}
|
||||
Self::Lambda(lambda) => lambda.body.iter().any(|t| t.has_undoable_linked_var()),
|
||||
Self::UnaryOp { val, .. } => val.has_undoable_linked_var(),
|
||||
Self::BinOp { lhs, rhs, .. } => {
|
||||
|
@ -1193,7 +1278,9 @@ impl TyParam {
|
|||
.map(|(k, v)| k.union_size().max(v.union_size()))
|
||||
.max()
|
||||
.unwrap_or(1),
|
||||
Self::Record(rec) => rec.iter().map(|(_, v)| v.union_size()).max().unwrap_or(1),
|
||||
Self::Record(rec) | Self::DataClass { fields: rec, .. } => {
|
||||
rec.iter().map(|(_, v)| v.union_size()).max().unwrap_or(1)
|
||||
}
|
||||
Self::Lambda(lambda) => lambda
|
||||
.body
|
||||
.iter()
|
||||
|
|
|
@ -678,6 +678,24 @@ impl LimitedDisplay for ValueObj {
|
|||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Self::DataClass { name, fields } => {
|
||||
write!(f, "{name} {{")?;
|
||||
for (i, (field, v)) in fields.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, "; ")?;
|
||||
}
|
||||
if limit.is_positive() && i >= CONTAINER_OMIT_THRESHOLD {
|
||||
write!(f, "...")?;
|
||||
break;
|
||||
}
|
||||
write!(f, "{field} = ")?;
|
||||
v.limited_fmt(f, limit - 1)?;
|
||||
}
|
||||
if fields.is_empty() {
|
||||
write!(f, "=")?;
|
||||
}
|
||||
write!(f, "}}")
|
||||
}
|
||||
Self::Type(typ) => typ.limited_fmt(f, limit),
|
||||
_ => write!(f, "{self}"),
|
||||
}
|
||||
|
@ -906,6 +924,17 @@ impl ValueObj {
|
|||
ValueObj::Type(TypeObj::Generated(gen))
|
||||
}
|
||||
|
||||
pub fn range(start: Self, end: Self) -> Self {
|
||||
Self::DataClass {
|
||||
name: "Range".into(),
|
||||
fields: dict! {
|
||||
Field::private("start".into()) => start,
|
||||
Field::private("end".into()) => end,
|
||||
Field::private("step".into()) => Self::None,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: add Complex
|
||||
pub const fn is_num(&self) -> bool {
|
||||
matches!(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue