From c39973f536ac0b6007b4bffd678f31270a06552c Mon Sep 17 00:00:00 2001 From: Shunsuke Shibayama Date: Fri, 21 Oct 2022 20:04:14 +0900 Subject: [PATCH] Fix subtyping bug --- compiler/erg_common/vis.rs | 8 ++++ compiler/erg_compiler/context/compare.rs | 7 ++++ .../context/initialize/const_func.rs | 26 ++++++++++++ .../erg_compiler/context/initialize/mod.rs | 10 +++++ compiler/erg_compiler/context/tyvar.rs | 19 +++++++++ .../erg_compiler/lib/std/_erg_std_prelude.py | 40 ++++++++++--------- compiler/erg_compiler/ty/value.rs | 19 +++++++++ 7 files changed, 110 insertions(+), 19 deletions(-) diff --git a/compiler/erg_common/vis.rs b/compiler/erg_common/vis.rs index 8eb621de..f0d90a0e 100644 --- a/compiler/erg_common/vis.rs +++ b/compiler/erg_common/vis.rs @@ -55,6 +55,14 @@ impl Field { Field { vis, symbol } } + pub const fn private(symbol: Str) -> Self { + Field::new(Visibility::Private, symbol) + } + + pub const fn public(symbol: Str) -> Self { + Field::new(Visibility::Public, symbol) + } + pub fn is_const(&self) -> bool { self.symbol.starts_with(char::is_uppercase) } diff --git a/compiler/erg_compiler/context/compare.rs b/compiler/erg_compiler/context/compare.rs index 2164d627..83ecd4dd 100644 --- a/compiler/erg_compiler/context/compare.rs +++ b/compiler/erg_compiler/context/compare.rs @@ -784,6 +784,13 @@ impl Context { (_, TyParam::FreeVar(fv), _) if fv.is_linked() => { self.supertype_of_tp(lp, &fv.crack(), variance) } + // _: Type :> T == true + (TyParam::Erased(t), TyParam::Type(_), _) + | (TyParam::Type(_), TyParam::Erased(t), _) + if t.as_ref() == &Type => + { + true + } (TyParam::Type(l), TyParam::Type(r), Variance::Contravariant) => self.subtype_of(l, r), (TyParam::Type(l), TyParam::Type(r), Variance::Covariant) => { // if matches!(r.as_ref(), &Type::Refinement(_)) { log!(info "{l}, {r}, {}", self.structural_supertype_of(l, r, bounds, Some(lhs_variance))); } diff --git a/compiler/erg_compiler/context/initialize/const_func.rs b/compiler/erg_compiler/context/initialize/const_func.rs index f7f9dc0b..3fa9c272 100644 --- a/compiler/erg_compiler/context/initialize/const_func.rs +++ b/compiler/erg_compiler/context/initialize/const_func.rs @@ -9,6 +9,8 @@ use crate::ty::ValueArgs; use erg_common::astr::AtomicStr; use erg_common::color::{RED, RESET, YELLOW}; use erg_common::error::{ErrorCore, ErrorKind, Location}; +use erg_common::str::Str; +use erg_common::vis::Field; /// Requirement: Type, Impl := Type -> ClassType pub fn class_func(mut args: ValueArgs, ctx: &Context) -> EvalValueResult { @@ -231,3 +233,27 @@ pub fn __dict_getitem__(mut args: ValueArgs, ctx: &Context) -> EvalValueResult EvalValueResult { + let (_name, fields) = enum_unwrap!( + args.remove_left_or_key("Self").unwrap(), + ValueObj::DataClass { name, fields } + ); + let index = enum_unwrap!(args.remove_left_or_key("Index").unwrap(), ValueObj::Nat); + let start = fields.get(&Field::private(Str::ever("start"))).unwrap(); + let start = *enum_unwrap!(start, ValueObj::Nat); + let end = fields.get(&Field::private(Str::ever("end"))).unwrap(); + let end = *enum_unwrap!(end, ValueObj::Nat); + // FIXME <= if inclusive + if start + index < end { + Ok(ValueObj::Nat(start + index)) + } else { + Err(ErrorCore::new( + line!() as usize, + ErrorKind::IndexError, + Location::Unknown, + AtomicStr::from(format!("Index out of range: {}", index)), + None, + )) + } +} diff --git a/compiler/erg_compiler/context/initialize/mod.rs b/compiler/erg_compiler/context/initialize/mod.rs index 22698bec..e96417e3 100644 --- a/compiler/erg_compiler/context/initialize/mod.rs +++ b/compiler/erg_compiler/context/initialize/mod.rs @@ -1534,6 +1534,7 @@ impl Context { // range.register_superclass(Obj, &obj); range.register_superclass(Type, &type_); range.register_marker_trait(poly("Output", vec![ty_tp(mono_q("T"))])); + range.register_marker_trait(poly("Seq", vec![ty_tp(mono_q("T"))])); let mut range_eq = Self::builtin_methods(Some(poly("Eq", vec![ty_tp(range_t.clone())])), 2); range_eq.register_builtin_impl( "__eq__", @@ -1551,6 +1552,15 @@ impl Context { Public, ); range.register_trait(range_t.clone(), range_iterable); + let range_getitem_t = fn1_kw_met(range_t.clone(), anon(mono_q("T")), mono_q("T")); + let range_getitem_t = quant(range_getitem_t, set! { static_instance("T", Type) }); + let get_item = ValueObj::Subr(ConstSubr::Builtin(BuiltinConstSubr::new( + "__getitem__", + __range_getitem__, + range_getitem_t, + None, + ))); + range.register_builtin_const("__getitem__", Public, get_item); /* Proc */ let mut proc = Self::builtin_mono_class("Proc", 2); proc.register_superclass(Obj, &obj); diff --git a/compiler/erg_compiler/context/tyvar.rs b/compiler/erg_compiler/context/tyvar.rs index 27be5a55..1a4026bf 100644 --- a/compiler/erg_compiler/context/tyvar.rs +++ b/compiler/erg_compiler/context/tyvar.rs @@ -1104,6 +1104,21 @@ impl Context { self.sub_unify_tp(lhs, lhs2, variance, loc, allow_divergence)?; self.sub_unify_tp(rhs, rhs2, variance, loc, allow_divergence) } + (l, TyParam::Erased(t)) => { + let sub_t = self.get_tp_t(l)?; + if self.subtype_of(&sub_t, t) { + Ok(()) + } else { + Err(TyCheckErrors::from(TyCheckError::subtyping_error( + self.cfg.input.clone(), + line!() as usize, + &sub_t, + t, + loc, + self.caused_by(), + ))) + } + } (l, r) => panic!("type-parameter unification failed:\nl:{l}\nr: {r}"), } } @@ -1123,6 +1138,10 @@ impl Context { *l.borrow_mut() = r.clone(); Ok(()) } + /*(TyParam::Value(ValueObj::Mut(l)), TyParam::Erased(_)) => { + *l.borrow_mut() = after.clone(); + Ok(()) + }*/ (TyParam::Type(l), TyParam::Type(r)) => self.reunify(l, r, loc), (TyParam::UnaryOp { op: lop, val: lval }, TyParam::UnaryOp { op: rop, val: rval }) if lop == rop => diff --git a/compiler/erg_compiler/lib/std/_erg_std_prelude.py b/compiler/erg_compiler/lib/std/_erg_std_prelude.py index 249b383e..4490f35b 100644 --- a/compiler/erg_compiler/lib/std/_erg_std_prelude.py +++ b/compiler/erg_compiler/lib/std/_erg_std_prelude.py @@ -26,7 +26,8 @@ def in_operator(x, y): return True # TODO: trait check return False - elif (type(y) == list or type(y) == set) and type(y[0]) == type: + elif (type(y) == list or type(y) == set) \ + and (type(y[0]) == type or issubclass(type(y[0]), Range)): # FIXME: type_check = in_operator(x[0], y[0]) len_check = len(x) == len(y) @@ -82,9 +83,26 @@ class Range: def __contains__(self, item): pass def __getitem__(self, item): - pass + res = self.start + item + if res in self: + return res + else: + raise IndexError("Index out of range") def __len__(self): - pass + if self.start in self: + if self.end in self: + # len(1..4) == 4 + return self.end - self.start + 1 + else: + # len(1..<4) == 3 + return self.end - self.start + else: + if self.end in self: + # len(1<..4) == 3 + return self.end - self.start + else: + # len(1<..<4) == 2 + return self.end - self.start - 2 def __iter__(self): return RangeIterator(rng=self) @@ -96,37 +114,21 @@ Iterable.register(Range) class LeftOpenRange(Range): def __contains__(self, item): return self.start < item <= self.end - def __getitem__(self, item): - return NotImplemented - def __len__(self): - return NotImplemented # represents `start..), Tuple(Rc<[ValueObj]>), Record(Dict), + DataClass { + name: Str, + fields: Dict, + }, Code(Box), Subr(ConstSubr), Type(TypeObj), @@ -199,6 +203,16 @@ impl fmt::Debug for ValueObj { } write!(f, "}}") } + Self::DataClass { name, fields } => { + write!(f, "{name} {{")?; + for (i, (k, v)) in fields.iter().enumerate() { + if i != 0 { + write!(f, "; ")?; + } + write!(f, "{k} = {v}")?; + } + write!(f, "}}") + } Self::Subr(subr) => write!(f, "{subr}"), Self::Type(t) => write!(f, "{t}"), Self::None => write!(f, "None"), @@ -247,6 +261,10 @@ impl Hash for ValueObj { Self::Set(st) => st.hash(state), Self::Code(code) => code.hash(state), Self::Record(rec) => rec.hash(state), + Self::DataClass { name, fields } => { + name.hash(state); + fields.hash(state); + } Self::Subr(subr) => subr.hash(state), Self::Type(t) => t.hash(state), Self::None => { @@ -538,6 +556,7 @@ impl ValueObj { Self::Record(rec) => { Type::Record(rec.iter().map(|(k, v)| (k.clone(), v.class())).collect()) } + Self::DataClass { name, .. } => Type::Mono(name.clone()), Self::Subr(subr) => subr.sig_t().clone(), Self::Type(t_obj) => match t_obj { // TODO: builtin