This commit is contained in:
Shunsuke Shibayama 2023-08-17 16:43:26 +09:00
parent ea0089f7df
commit 9454896d5a
8 changed files with 177 additions and 12 deletions

View file

@ -525,6 +525,7 @@ impl Context {
true
}
(Bool, Guard { .. }) => true,
(Mono(n), NamedTuple(_)) => &n[..] == "GenericNamedTuple" || &n[..] == "GenericTuple",
(Type, Subr(subr)) => self.supertype_of(&Type, &subr.return_t),
(Type, Poly { name, params }) if &name[..] == "Array" || &name[..] == "Set" => {
let elem_t = self.convert_tp_into_type(params[0].clone()).unwrap();

View file

@ -1688,9 +1688,71 @@ impl Context {
/* record */
let mut record = Self::builtin_mono_class(RECORD, 2);
record.register_superclass(Obj, &obj);
/* NamedTuple */
let mut named_tuple = Self::builtin_mono_class(NAMED_TUPLE, 2);
named_tuple.register_superclass(mono(GENERIC_TUPLE), &generic_tuple);
/* GenericNamedTuple */
let mut generic_named_tuple = Self::builtin_mono_class(GENERIC_NAMED_TUPLE, 2);
generic_named_tuple.register_superclass(mono(GENERIC_TUPLE), &generic_tuple);
let Slf = mono("Self");
let input_t = tp_enum(Nat, set! {N.clone()});
let return_t = proj_call(ty_tp(Slf.clone()), FUNDAMENTAL_GETITEM, vec![N.clone()]);
let named_tuple_getitem =
fn1_met(Slf.clone(), input_t.clone(), return_t.clone()).quantify();
let mut named_tuple_indexable = Self::builtin_methods(
Some(poly(INDEXABLE, vec![ty_tp(input_t), ty_tp(return_t)])),
2,
);
named_tuple_indexable.register_builtin_py_impl(
FUNDAMENTAL_TUPLE_GETITEM,
named_tuple_getitem.clone(),
Const,
Visibility::BUILTIN_PUBLIC,
Some(FUNDAMENTAL_GETITEM),
);
generic_named_tuple.register_trait(mono(GENERIC_NAMED_TUPLE), named_tuple_indexable);
let get_item = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNDAMENTAL_GETITEM,
__named_tuple_getitem__,
named_tuple_getitem,
None,
)));
generic_named_tuple.register_builtin_const(
FUNDAMENTAL_GETITEM,
Visibility::BUILTIN_PUBLIC,
get_item,
);
let mut named_tuple_iterable = Self::builtin_methods(
Some(poly(
ITERABLE,
vec![ty_tp(proj_call(ty_tp(Slf.clone()), FUNC_UNION, vec![]))],
)),
2,
);
let named_tuple_iterator = poly(
TUPLE_ITERATOR,
vec![ty_tp(proj_call(ty_tp(Slf.clone()), FUNC_UNION, vec![]))],
);
let t = fn0_met(Slf.clone(), named_tuple_iterator.clone()).quantify();
named_tuple_iterable.register_builtin_py_impl(
FUNC_ITER,
t,
Immutable,
Visibility::BUILTIN_PUBLIC,
Some(FUNDAMENTAL_ITER),
);
named_tuple_iterable.register_builtin_const(
ITERATOR,
vis.clone(),
ValueObj::builtin_class(named_tuple_iterator),
);
generic_named_tuple.register_trait(mono(GENERIC_NAMED_TUPLE), named_tuple_iterable);
// union: (self: NamedTuple({...})) -> Type
let named_tuple_union_t = fn0_met(Slf, Type).quantify();
let union = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new(
FUNC_UNION,
named_tuple_union,
named_tuple_union_t,
None,
)));
generic_named_tuple.register_builtin_const(FUNC_UNION, Visibility::BUILTIN_PUBLIC, union);
/* Or (true or type) */
let or_t = poly(OR, vec![ty_tp(L), ty_tp(R)]);
let mut or = Self::builtin_poly_class(OR, vec![PS::t_nd(TY_L), PS::t_nd(TY_R)], 2);
@ -2472,11 +2534,11 @@ impl Context {
self.register_builtin_type(_tuple_t, tuple_, vis.clone(), Const, Some(FUNC_TUPLE));
self.register_builtin_type(mono(RECORD), record, vis.clone(), Const, Some(RECORD));
self.register_builtin_type(
mono(NAMED_TUPLE),
named_tuple,
mono(GENERIC_NAMED_TUPLE),
generic_named_tuple,
vis.clone(),
Const,
Some(NAMED_TUPLE),
Some(GENERIC_NAMED_TUPLE),
);
self.register_builtin_type(or_t, or, vis.clone(), Const, Some(UNION));
self.register_builtin_type(

View file

@ -450,3 +450,52 @@ pub(crate) fn __range_getitem__(mut args: ValueArgs, _ctx: &Context) -> EvalValu
.into())
}
}
pub(crate) fn __named_tuple_getitem__(
mut args: ValueArgs,
ctx: &Context,
) -> EvalValueResult<TyParam> {
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let fields = match ctx.convert_value_into_type(slf) {
Ok(Type::NamedTuple(fields)) => fields,
Ok(other) => {
return Err(type_mismatch("NamedTuple", other, "Self"));
}
Err(val) => {
return Err(type_mismatch("NamedTuple", val, "Self"));
}
};
let index = args
.remove_left_or_key("Index")
.ok_or_else(|| not_passed("Index"))?;
let Ok(index) = usize::try_from(&index) else {
return Err(type_mismatch("Nat", index, "Index"));
};
if let Some((_, t)) = fields.get(index) {
Ok(TyParam::t(t.clone()))
} else {
Err(no_key(Type::NamedTuple(fields), index))
}
}
/// `NamedTuple({ .x = Int; .y = Str }).union() == Int or Str`
pub(crate) fn named_tuple_union(mut args: ValueArgs, ctx: &Context) -> EvalValueResult<TyParam> {
let slf = args
.remove_left_or_key("Self")
.ok_or_else(|| not_passed("Self"))?;
let fields = match ctx.convert_value_into_type(slf) {
Ok(Type::NamedTuple(fields)) => fields,
Ok(other) => {
return Err(type_mismatch("NamedTuple", other, "Self"));
}
Err(val) => {
return Err(type_mismatch("NamedTuple", val, "Self"));
}
};
let union = fields
.iter()
.fold(Type::Never, |union, (_, t)| ctx.union(&union, t));
Ok(ValueObj::builtin_type(union).into())
}

View file

@ -229,7 +229,7 @@ const GENERIC_TUPLE: &str = "GenericTuple";
const TUPLE: &str = "Tuple";
const TUPLE_ITERATOR: &str = "TupleIterator";
const RECORD: &str = "Record";
const NAMED_TUPLE: &str = "NamedTuple";
const GENERIC_NAMED_TUPLE: &str = "GenericNamedTuple";
const OR: &str = "Or";
const RANGE_ITERATOR: &str = "RangeIterator";
const ENUMERATE: &str = "Enumerate";

View file

@ -2422,7 +2422,7 @@ impl Context {
return self
.get_builtins()
.unwrap_or(self)
.rec_local_get_mono_type("NamedTuple");
.rec_local_get_mono_type("GenericNamedTuple");
}
Type::Or(_l, _r) => {
if let Some(ctx) = self.get_nominal_type_ctx(&poly("Or", vec![])) {
@ -3103,10 +3103,13 @@ impl Context {
}
// TODO:
/// ```erg
/// Int.meta_type() == ClassType (<: Type)
/// Show.meta_type() == TraitType (<: Type)
/// [Int; 3].meta_type() == [ClassType; 3] (<: Type)
/// Indexable(T).meta_type() == TraitType (<: Type)
/// NamedTuple({ .x = Int; .y = Str }).meta_type() == NamedTuple({ .x = ClassType; .y = ClassType })
/// ```
pub fn meta_type(&self, typ: &Type) -> Type {
match typ {
Type::Poly { name, params } if &name[..] == "Array" || &name[..] == "Set" => poly(
@ -3122,6 +3125,12 @@ impl Context {
})
.collect(),
),
NamedTuple(tuple) => NamedTuple(
tuple
.iter()
.map(|(name, tp)| (name.clone(), self.meta_type(tp)))
.collect(),
),
_ => Type,
}
}

View file

@ -11,7 +11,7 @@ use ast::{
TypeBoundSpecs, TypeSpec,
};
use erg_parser::ast::{
self, ConstArray, ConstSet, Identifier, VarName, VisModifierSpec, VisRestriction,
self, ConstArray, ConstExpr, ConstSet, Identifier, VarName, VisModifierSpec, VisRestriction,
};
use erg_parser::token::TokenKind;
use erg_parser::Parser;
@ -671,6 +671,50 @@ impl Context {
)?;
Ok(t.structuralize())
}
"NamedTuple" => {
let mut args = poly_spec.args.pos_args();
let Some(first) = args.next() else {
return Err(TyCheckErrors::from(TyCheckError::args_missing_error(
self.cfg.input.clone(),
line!() as usize,
poly_spec.args.loc(),
"NamedTuple",
self.caused_by(),
vec![Str::from("Fields")],
)));
};
let ConstExpr::Record(fields) = &first.expr else {
return Err(TyCheckErrors::from(TyCheckError::type_mismatch_error(
self.cfg.input.clone(),
line!() as usize,
first.expr.loc(),
self.caused_by(),
"NamedTuple",
None,
&mono("Record"),
&self.instantiate_const_expr_as_type(
&first.expr,
None,
tmp_tv_cache,
not_found_is_qvar,
)?,
None,
None,
)));
};
let mut ts = vec![];
for def in fields.attrs.iter() {
let t = self.instantiate_const_expr_as_type(
&def.body.block[0],
None,
tmp_tv_cache,
not_found_is_qvar,
)?;
let vis = self.instantiate_vis_modifier(&def.ident.vis)?;
ts.push((Field::new(vis, def.ident.inspect().clone()), t));
}
Ok(Type::NamedTuple(ts))
}
other => {
let Some((typ, ctx)) = self.get_type(&Str::rc(other)) else {
return Err(TyCheckErrors::from(TyCheckError::no_type_error(

View file

@ -3,7 +3,7 @@
.copyfile!: (src: PathLike, dst: PathLike,) => NoneType
.copy!: (src: PathLike, dst: PathLike,) => NoneType
.copytree!: (src: PathLike, dst: PathLike,) => NoneType
.disk_usage!: (path: PathLike,) => {
.disk_usage!: (path: PathLike,) => NamedTuple {
.total = Nat
.used = Nat
.free = Nat

View file

@ -1115,7 +1115,7 @@ impl LimitedDisplay for Type {
write!(f, "}}")
}
Self::NamedTuple(attrs) => {
write!(f, "NamedTuple {{")?;
write!(f, "NamedTuple({{")?;
for (i, (field, t)) in attrs.iter().enumerate() {
if i > 0 {
write!(f, "; ")?;
@ -1130,7 +1130,7 @@ impl LimitedDisplay for Type {
if attrs.is_empty() {
write!(f, "=")?;
}
write!(f, "}}")
write!(f, "}})")
}
Self::Subr(sub) => sub.limited_fmt(f, limit),
Self::Refinement(refinement) => refinement.limited_fmt(f, limit),