mirror of
https://github.com/erg-lang/erg.git
synced 2025-10-01 05:11:09 +00:00
Fix trait implementation check
This commit is contained in:
parent
3d35db4e3b
commit
968d3b5d2c
8 changed files with 147 additions and 67 deletions
|
@ -175,27 +175,7 @@ impl Context {
|
|||
| (Float | Ratio, Ratio)
|
||||
| (Float, Float) => (Absolutely, true),
|
||||
(Type, ClassType | TraitType) => (Absolutely, true),
|
||||
(Type, Record(rec)) => (
|
||||
Absolutely,
|
||||
rec.iter().all(|(_, attr)| self.supertype_of(&Type, attr)),
|
||||
),
|
||||
(Type::Uninited, _) | (_, Type::Uninited) => panic!("used an uninited type variable"),
|
||||
(Type, Subr(subr)) => (
|
||||
Absolutely,
|
||||
subr.non_default_params
|
||||
.iter()
|
||||
.all(|pt| self.supertype_of(&Type, pt.typ()))
|
||||
&& subr
|
||||
.default_params
|
||||
.iter()
|
||||
.all(|pt| self.supertype_of(&Type, pt.typ()))
|
||||
&& subr
|
||||
.var_params
|
||||
.as_ref()
|
||||
.map(|va| self.supertype_of(&Type, va.typ()))
|
||||
.unwrap_or(true)
|
||||
&& self.supertype_of(&Type, &subr.return_t),
|
||||
),
|
||||
(
|
||||
Type::Mono(n),
|
||||
Subr(SubrType {
|
||||
|
@ -461,6 +441,7 @@ impl Context {
|
|||
}
|
||||
true
|
||||
}
|
||||
(Type, Subr(subr)) => self.supertype_of(&Type, &subr.return_t),
|
||||
(Type, Poly { name, params }) | (Poly { name, params }, Type)
|
||||
if &name[..] == "Array" || &name[..] == "Set" =>
|
||||
{
|
||||
|
|
|
@ -259,7 +259,8 @@ impl Context {
|
|||
Signature::Var(_) => None,
|
||||
};
|
||||
// TODO: set params
|
||||
self.grow(__name__, ContextKind::Instant, vis, tv_cache);
|
||||
let kind = ContextKind::from(def.def_kind());
|
||||
self.grow(__name__, kind, vis, tv_cache);
|
||||
let obj = self.eval_const_block(&def.body.block).map_err(|e| {
|
||||
self.pop();
|
||||
e
|
||||
|
|
|
@ -1827,18 +1827,19 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
/// FIXME: if trait, returns a freevar
|
||||
// TODO: poly type
|
||||
pub(crate) fn rec_get_self_t(&self) -> Option<Type> {
|
||||
if self.kind.is_method_def() || self.kind.is_type() {
|
||||
// TODO: poly type
|
||||
let name = self.name.split(&[':', '.']).last().unwrap();
|
||||
// let mono_t = mono(self.path(), Str::rc(name));
|
||||
if let Some((t, _)) = self.rec_get_type(name) {
|
||||
// let name = self.name.split(&[':', '.']).last().unwrap();
|
||||
/*if let Some((t, _)) = self.rec_get_type(name) {
|
||||
log!("{t}");
|
||||
Some(t.clone())
|
||||
} else {
|
||||
log!("none");
|
||||
None
|
||||
}
|
||||
} else if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
|
||||
}*/
|
||||
Some(mono(self.name.clone()))
|
||||
} else if let Some(outer) = self.get_outer() {
|
||||
outer.rec_get_self_t()
|
||||
} else {
|
||||
None
|
||||
|
|
|
@ -412,6 +412,13 @@ impl Context {
|
|||
let t = self.instantiate_const_expr_as_type(&first.expr, None, tmp_tv_cache)?;
|
||||
Ok(ref_mut(t, None))
|
||||
}
|
||||
"Self" => self.rec_get_self_t().ok_or_else(|| {
|
||||
TyCheckErrors::from(TyCheckError::unreachable(
|
||||
self.cfg.input.clone(),
|
||||
erg_common::fn_name_full!(),
|
||||
line!(),
|
||||
))
|
||||
}),
|
||||
other if simple.args.is_empty() => {
|
||||
if let Some(t) = tmp_tv_cache.get_tyvar(other) {
|
||||
return Ok(t.clone());
|
||||
|
|
|
@ -582,7 +582,8 @@ impl Context {
|
|||
}
|
||||
}
|
||||
ast::Signature::Var(sig) if sig.is_const() => {
|
||||
self.grow(__name__, ContextKind::Instant, sig.vis(), None);
|
||||
let kind = ContextKind::from(def.def_kind());
|
||||
self.grow(__name__, kind, sig.vis(), None);
|
||||
let (obj, const_t) = match self.eval_const_block(&def.body.block) {
|
||||
Ok(obj) => (obj.clone(), v_enum(set! {obj})),
|
||||
Err(e) => {
|
||||
|
|
|
@ -1065,6 +1065,10 @@ impl ASTLowerer {
|
|||
None,
|
||||
),
|
||||
};
|
||||
// assume the class has implemented the trait, regardless of whether the implementation is correct
|
||||
if let Some((trait_, trait_loc)) = &impl_trait {
|
||||
self.register_trait_impl(&class, trait_, *trait_loc)?;
|
||||
}
|
||||
if let Some(class_root) = self.ctx.get_nominal_type_ctx(&class) {
|
||||
if !class_root.kind.is_class() {
|
||||
return Err(LowerErrors::from(LowerError::method_definition_error(
|
||||
|
@ -1114,7 +1118,6 @@ impl ASTLowerer {
|
|||
}
|
||||
if let Some((trait_, _)) = &impl_trait {
|
||||
self.check_override(&class, Some(trait_));
|
||||
self.register_trait_impl(&class, trait_);
|
||||
} else {
|
||||
self.check_override(&class, None);
|
||||
}
|
||||
|
@ -1151,6 +1154,42 @@ impl ASTLowerer {
|
|||
))
|
||||
}
|
||||
|
||||
fn register_trait_impl(
|
||||
&mut self,
|
||||
class: &Type,
|
||||
trait_: &Type,
|
||||
trait_loc: Location,
|
||||
) -> LowerResult<()> {
|
||||
// TODO: polymorphic trait
|
||||
if let Some(impls) = self.ctx.trait_impls.get_mut(&trait_.qual_name()) {
|
||||
impls.insert(TypeRelationInstance::new(class.clone(), trait_.clone()));
|
||||
} else {
|
||||
self.ctx.trait_impls.insert(
|
||||
trait_.qual_name(),
|
||||
set! {TypeRelationInstance::new(class.clone(), trait_.clone())},
|
||||
);
|
||||
}
|
||||
let trait_ctx = if let Some(trait_ctx) = self.ctx.get_nominal_type_ctx(trait_) {
|
||||
trait_ctx.clone()
|
||||
} else {
|
||||
// TODO: maybe parameters are wrong
|
||||
return Err(LowerErrors::from(LowerError::no_var_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
trait_loc,
|
||||
self.ctx.caused_by(),
|
||||
&trait_.local_name(),
|
||||
None,
|
||||
)));
|
||||
};
|
||||
let (_, class_ctx) = self
|
||||
.ctx
|
||||
.get_mut_nominal_type_ctx(class)
|
||||
.unwrap_or_else(|| todo!("{class} not found"));
|
||||
class_ctx.register_supertrait(trait_.clone(), &trait_ctx);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// HACK: Cannot be methodized this because `&self` has been taken immediately before.
|
||||
fn check_inheritable(
|
||||
cfg: &ErgConfig,
|
||||
|
@ -1224,35 +1263,22 @@ impl ASTLowerer {
|
|||
class: &Type,
|
||||
) -> SingleLowerResult<()> {
|
||||
if let Some((impl_trait, loc)) = impl_trait {
|
||||
// assume the class has implemented the trait, regardless of whether the implementation is correct
|
||||
let trait_ctx = if let Some(trait_ctx) = self.ctx.get_nominal_type_ctx(&impl_trait) {
|
||||
trait_ctx.clone()
|
||||
} else {
|
||||
// TODO: maybe parameters are wrong
|
||||
return Err(LowerError::no_var_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
loc,
|
||||
self.ctx.caused_by(),
|
||||
&impl_trait.local_name(),
|
||||
None,
|
||||
));
|
||||
};
|
||||
let (_, class_ctx) = self
|
||||
.ctx
|
||||
.get_mut_nominal_type_ctx(class)
|
||||
.unwrap_or_else(|| todo!("{class} not found"));
|
||||
class_ctx.register_supertrait(impl_trait.clone(), &trait_ctx);
|
||||
let mut unverified_names = self.ctx.locals.keys().collect::<Set<_>>();
|
||||
if let Some(trait_obj) = self.ctx.rec_get_const_obj(&impl_trait.local_name()) {
|
||||
if let ValueObj::Type(typ) = trait_obj {
|
||||
match typ {
|
||||
TypeObj::Generated(gen) => match gen.require_or_sup().unwrap().typ() {
|
||||
Type::Record(attrs) => {
|
||||
for (field, field_typ) in attrs.iter() {
|
||||
for (field, decl_t) in attrs.iter() {
|
||||
if let Some((name, vi)) = self.ctx.get_local_kv(&field.symbol) {
|
||||
let def_t = &vi.t;
|
||||
// A(<: Add(R)), R -> A.Output
|
||||
// => A(<: Int), R -> A.Output
|
||||
let replaced_decl_t =
|
||||
decl_t.clone().replace(&impl_trait, class);
|
||||
unverified_names.remove(name);
|
||||
if !self.ctx.supertype_of(field_typ, &vi.t) {
|
||||
// def_t must be subtype of decl_t
|
||||
if !self.ctx.supertype_of(&replaced_decl_t, def_t) {
|
||||
self.errs.push(LowerError::trait_member_type_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
|
@ -1260,7 +1286,7 @@ impl ASTLowerer {
|
|||
self.ctx.caused_by(),
|
||||
name.inspect(),
|
||||
&impl_trait,
|
||||
field_typ,
|
||||
decl_t,
|
||||
&vi.t,
|
||||
None,
|
||||
));
|
||||
|
@ -1285,8 +1311,11 @@ impl ASTLowerer {
|
|||
for (decl_name, decl_vi) in ctx.decls.iter() {
|
||||
if let Some((name, vi)) = self.ctx.get_local_kv(decl_name.inspect())
|
||||
{
|
||||
let def_t = &vi.t;
|
||||
let replaced_decl_t =
|
||||
decl_vi.t.clone().replace(&impl_trait, class);
|
||||
unverified_names.remove(name);
|
||||
if !self.ctx.supertype_of(&decl_vi.t, &vi.t) {
|
||||
if !self.ctx.supertype_of(&replaced_decl_t, def_t) {
|
||||
self.errs.push(LowerError::trait_member_type_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
|
@ -1351,19 +1380,6 @@ impl ASTLowerer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn register_trait_impl(&mut self, class: &Type, trait_: &Type) {
|
||||
let trait_impls = &mut self.ctx.outer.as_mut().unwrap().trait_impls;
|
||||
// TODO: polymorphic trait
|
||||
if let Some(impls) = trait_impls.get_mut(&trait_.qual_name()) {
|
||||
impls.insert(TypeRelationInstance::new(class.clone(), trait_.clone()));
|
||||
} else {
|
||||
trait_impls.insert(
|
||||
trait_.qual_name(),
|
||||
set! {TypeRelationInstance::new(class.clone(), trait_.clone())},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn check_collision_and_push(&mut self, class: Type) {
|
||||
let methods = self.ctx.pop();
|
||||
let (_, class_root) = self
|
||||
|
|
|
@ -2167,6 +2167,79 @@ impl Type {
|
|||
other => other.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn replace(self, target: &Type, to: &Type) -> Type {
|
||||
if &self == target {
|
||||
return to.clone();
|
||||
}
|
||||
match self {
|
||||
Self::FreeVar(fv) if fv.is_linked() => fv.crack().clone().replace(target, to),
|
||||
Self::Refinement(mut refine) => {
|
||||
refine.t = Box::new(refine.t.replace(target, to));
|
||||
Self::Refinement(refine)
|
||||
}
|
||||
Self::Record(mut rec) => {
|
||||
for v in rec.values_mut() {
|
||||
*v = std::mem::take(v).replace(target, to);
|
||||
}
|
||||
Self::Record(rec)
|
||||
}
|
||||
Self::Subr(mut subr) => {
|
||||
for nd in subr.non_default_params.iter_mut() {
|
||||
*nd.typ_mut() = std::mem::take(nd.typ_mut()).replace(target, to);
|
||||
}
|
||||
if let Some(var) = subr.var_params.as_mut() {
|
||||
*var.as_mut().typ_mut() =
|
||||
std::mem::take(var.as_mut().typ_mut()).replace(target, to);
|
||||
}
|
||||
for d in subr.default_params.iter_mut() {
|
||||
*d.typ_mut() = std::mem::take(d.typ_mut()).replace(target, to);
|
||||
}
|
||||
subr.return_t = Box::new(subr.return_t.replace(target, to));
|
||||
Self::Subr(subr)
|
||||
}
|
||||
Self::Callable { param_ts, return_t } => {
|
||||
let param_ts = param_ts
|
||||
.into_iter()
|
||||
.map(|t| t.replace(target, to))
|
||||
.collect();
|
||||
let return_t = Box::new(return_t.replace(target, to));
|
||||
Self::Callable { param_ts, return_t }
|
||||
}
|
||||
Self::Quantified(quant) => quant.replace(target, to).quantify(),
|
||||
Self::Poly { name, params } => {
|
||||
let params = params
|
||||
.into_iter()
|
||||
.map(|tp| match tp {
|
||||
TyParam::Type(t) => TyParam::t(t.replace(target, to)),
|
||||
other => other,
|
||||
})
|
||||
.collect();
|
||||
Self::Poly { name, params }
|
||||
}
|
||||
Self::Ref(t) => Self::Ref(Box::new(t.replace(target, to))),
|
||||
Self::RefMut { before, after } => Self::RefMut {
|
||||
before: Box::new(before.replace(target, to)),
|
||||
after: after.map(|t| Box::new(t.replace(target, to))),
|
||||
},
|
||||
Self::And(l, r) => {
|
||||
let l = l.replace(target, to);
|
||||
let r = r.replace(target, to);
|
||||
Self::And(Box::new(l), Box::new(r))
|
||||
}
|
||||
Self::Or(l, r) => {
|
||||
let l = l.replace(target, to);
|
||||
let r = r.replace(target, to);
|
||||
Self::Or(Box::new(l), Box::new(r))
|
||||
}
|
||||
Self::Not(l, r) => {
|
||||
let l = l.replace(target, to);
|
||||
let r = r.replace(target, to);
|
||||
Self::Not(Box::new(l), Box::new(r))
|
||||
}
|
||||
other => other,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// バイトコード命令で、in-place型付けをするオブジェクト
|
||||
|
|
|
@ -2832,7 +2832,7 @@ impl Parser {
|
|||
) -> ParseResult<LambdaSignature> {
|
||||
debug_call_info!(self);
|
||||
let sig = self
|
||||
.convert_rhs_to_param(*tasc.expr, true)
|
||||
.convert_rhs_to_param(Expr::TypeAsc(tasc), true)
|
||||
.map_err(|_| self.stack_dec())?;
|
||||
self.level -= 1;
|
||||
Ok(LambdaSignature::new(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue