Skip to content

Commit

Permalink
feat: impl type widening for ReDef / Structural
Browse files Browse the repository at this point in the history
  • Loading branch information
mtshiba committed Dec 23, 2024
1 parent cd0b54d commit 5e9cab7
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 37 deletions.
88 changes: 84 additions & 4 deletions crates/erg_compiler/context/inquire.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1135,7 +1135,7 @@ impl Context {
&self,
obj: &hir::Expr,
attr_name: &Option<Identifier>,
pos_args: &[hir::PosArg],
pos_args: &mut [hir::PosArg],
kw_args: &[hir::KwArg],
(var_args, kw_var_args): (Option<&hir::PosArg>, Option<&hir::PosArg>),
input: &Input,
Expand Down Expand Up @@ -1760,7 +1760,7 @@ impl Context {
pub(crate) fn get_binop_t(
&self,
op: &Token,
args: &[hir::PosArg],
args: &mut [hir::PosArg],
input: &Input,
namespace: &Context,
) -> TyCheckResult<VarInfo> {
Expand Down Expand Up @@ -1815,7 +1815,7 @@ impl Context {
pub(crate) fn get_unaryop_t(
&self,
op: &Token,
args: &[hir::PosArg],
args: &mut [hir::PosArg],
input: &Input,
namespace: &Context,
) -> TyCheckResult<VarInfo> {
Expand Down Expand Up @@ -2775,7 +2775,7 @@ impl Context {
&self,
obj: &hir::Expr,
attr_name: &Option<Identifier>,
pos_args: &[hir::PosArg],
pos_args: &mut [hir::PosArg],
kw_args: &[hir::KwArg],
(var_args, kw_var_args): (Option<&hir::PosArg>, Option<&hir::PosArg>),
input: &Input,
Expand Down Expand Up @@ -2831,6 +2831,20 @@ impl Context {
(var_args, kw_var_args),
namespace,
)
.or_else(|errs| {
if let Some(res) = self.widen_call_type(
obj,
&found.t,
attr_name,
pos_args,
kw_args,
(var_args, kw_var_args),
) {
Ok(res)
} else {
Err(errs)
}
})
.map_err(|errs| {
(
Some(VarInfo {
Expand Down Expand Up @@ -2862,6 +2876,53 @@ impl Context {
Ok(res)
}

// e.g.
// ```
// found_t: (Structural({ .__sub__ = (self: L, other: R) -> O }), R) -> O
// pos_args [100, 1.0]
// 100: Nat ==> Float
// => Coerced((Float, Float) -> Float) # not (Nat, Nat) -> Nat
// ```
fn widen_call_type(
&self,
obj: &hir::Expr,
found_t: &Type,
attr_name: &Option<Identifier>,
pos_args: &mut [hir::PosArg],
kw_args: &[hir::KwArg],
(var_args, kw_var_args): (Option<&hir::PosArg>, Option<&hir::PosArg>),
) -> Option<SubstituteResult> {
let found = <&SubrType>::try_from(found_t).ok()?;
if found.has_type_satisfies(|t| t.is_structural()) {
let idx_structural = found
.non_default_params
.iter()
.position(|pt| pt.typ().is_structural())?;
pos_args.get(idx_structural)?;
let old_type = pos_args[idx_structural].expr.t();
for sub in self.get_super_classes_or_self(&old_type).skip(1) {
let Ok(Type::Subr(subr)) = self.instantiate(found_t.clone(), obj) else {
return None;
};
let pos_arg = pos_args.get_mut(idx_structural)?;
*pos_arg.expr.ref_mut_t()? = sub.clone();
let res = self.substitute_subr_call(
obj,
attr_name,
&subr,
pos_args,
kw_args,
(var_args, kw_var_args),
);
if res.is_ok() {
return Some(SubstituteResult::Coerced(Type::Subr(subr)));
}
}
*pos_args[idx_structural].expr.ref_mut_t()? = old_type;
}
None
}

pub(crate) fn get_const_local(
&self,
name: &Token,
Expand Down Expand Up @@ -3253,6 +3314,25 @@ impl Context {
})
}

pub(crate) fn get_super_classes_or_self(
&self,
typ: &Type,
) -> impl Iterator<Item = Type> + Clone {
self.get_nominal_type_ctx(typ)
.map(|ctx| {
let super_classes = ctx.super_classes.clone();
let derefined = typ.derefine();
if typ != &derefined {
vec![ctx.typ.clone(), derefined]
.into_iter()
.chain(super_classes)
} else {
vec![ctx.typ.clone()].into_iter().chain(super_classes)
}
})
.unwrap_or(vec![typ.clone()].into_iter().chain(vec![]))
}

/// include `typ` itself.
pub(crate) fn get_super_types(&self, typ: &Type) -> Option<impl Iterator<Item = Type> + Clone> {
self.get_nominal_type_ctx(typ).map(|ctx| {
Expand Down
75 changes: 42 additions & 33 deletions crates/erg_compiler/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1301,11 +1301,11 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
expr.unwrap_or(hir::Expr::Dummy(hir::Dummy::new(vec![])))
});
let rhs = hir::PosArg::new(rhs);
let args = [lhs, rhs];
let mut args = [lhs, rhs];
let mut vi = self
.module
.context
.get_binop_t(&bin.op, &args, &self.cfg.input, &self.module.context)
.get_binop_t(&bin.op, &mut args, &self.cfg.input, &self.module.context)
.unwrap_or_else(|errs| {
errors.extend(errs);
VarInfo::ILLEGAL
Expand Down Expand Up @@ -1359,11 +1359,11 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
errors.extend(errs);
expr.unwrap_or(hir::Expr::Dummy(hir::Dummy::new(vec![])))
});
let args = [hir::PosArg::new(arg)];
let mut args = [hir::PosArg::new(arg)];
let vi = self
.module
.context
.get_unaryop_t(&unary.op, &args, &self.cfg.input, &self.module.context)
.get_unaryop_t(&unary.op, &mut args, &self.cfg.input, &self.module.context)
.unwrap_or_else(|errs| {
errors.extend(errs);
VarInfo::ILLEGAL
Expand Down Expand Up @@ -1572,11 +1572,11 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
// self.errs.extend(errs);
}
}
let hir_args = self.lower_args(call.args, expect_subr, &mut errs);
let mut hir_args = self.lower_args(call.args, expect_subr, &mut errs);
let mut vi = match self.module.context.get_call_t(
&obj,
&call.attr_name,
&hir_args.pos_args,
&mut hir_args.pos_args,
&hir_args.kw_args,
(hir_args.var_args.as_deref(), hir_args.kw_var.as_deref()),
&self.cfg.input,
Expand Down Expand Up @@ -1728,7 +1728,7 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
args
}
};
let args = vec![hir::PosArg::new(hir::Expr::Record(args))];
let mut args = vec![hir::PosArg::new(hir::Expr::Record(args))];
let attr_name = ast::Identifier::new(
VisModifierSpec::Public(
Token::new(
Expand All @@ -1749,7 +1749,7 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
let vi = match self.module.context.get_call_t(
&class,
&Some(attr_name.clone()),
&args,
&mut args,
&[],
(None, None),
&self.cfg.input,
Expand Down Expand Up @@ -3029,31 +3029,8 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
self.var_result_t_check(&attr, &Str::from(attr.show()), attr.ref_t(), expr.ref_t())
{
if PYTHON_MODE {
let mut derefined = attr.ref_t().derefine();
if derefined == Type::Nat {
derefined = Type::Int;
}
match self.var_result_t_check(
&attr,
&Str::from(attr.show()),
&derefined,
expr.ref_t(),
) {
Err(err) => errors.push(err),
Ok(_) => {
if let Some(attr_t) = attr.ref_mut_t() {
*attr_t = derefined.clone();
}
if let hir::Accessor::Ident(ident) = &attr {
if let Some(vi) = self
.module
.context
.rec_get_mut_var_info(&ident.raw, AccessKind::Name)
{
vi.t = derefined;
}
}
}
if !self.widen_type(&mut attr, &expr) {
errors.push(err);
}
} else {
errors.push(err);
Expand All @@ -3067,6 +3044,38 @@ impl<A: ASTBuildable> GenericASTLowerer<A> {
}
}

fn widen_type(&mut self, attr: &mut hir::Accessor, expr: &hir::Expr) -> bool {
for sup in self
.module
.context
.get_super_classes_or_self(attr.ref_t())
.skip(1)
{
if sup == Type::Obj {
break;
}
if self
.var_result_t_check(attr, &Str::from(attr.show()), &sup, expr.ref_t())
.is_ok()
{
if let Some(attr_t) = attr.ref_mut_t() {
*attr_t = sup.clone();
}
if let hir::Accessor::Ident(ident) = &attr {
if let Some(vi) = self
.module
.context
.rec_get_mut_var_info(&ident.raw, AccessKind::Name)
{
vi.t = sup;
}
}
return true;
}
}
false
}

fn check_inheritable(
&self,
type_obj: &GenTypeObj,
Expand Down

0 comments on commit 5e9cab7

Please sign in to comment.