Fix subtyping bugs

This commit is contained in:
Shunsuke Shibayama 2022-10-05 11:53:29 +09:00
parent 4d7181f2f0
commit 85c6057d7c
15 changed files with 224 additions and 152 deletions

View file

@ -829,7 +829,7 @@ impl Context {
/// returns union of two types (A or B)
pub(crate) fn union(&self, lhs: &Type, rhs: &Type) -> Type {
// ?T or ?U will not be unified
if !lhs.is_unbound_var() && !rhs.is_unbound_var() {
if lhs.has_no_unbound_var() && rhs.has_no_unbound_var() {
match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) {
(true, true) => return lhs.clone(), // lhs = rhs
(true, false) => return lhs.clone(), // lhs :> rhs
@ -1035,7 +1035,7 @@ impl Context {
}
}
pub(crate) fn max<'t>(&self, lhs: &'t Type, rhs: &'t Type) -> Option<&'t Type> {
pub(crate) fn _max<'t>(&self, lhs: &'t Type, rhs: &'t Type) -> Option<&'t Type> {
// 同じならどちらを返しても良い
match (self.supertype_of(lhs, rhs), self.subtype_of(lhs, rhs)) {
(true, true) | (true, false) => Some(lhs),

View file

@ -2,6 +2,7 @@ use std::fmt;
use std::mem;
use erg_common::dict::Dict;
use erg_common::enum_unwrap;
use erg_common::error::Location;
use erg_common::set::Set;
use erg_common::shared::Shared;
@ -828,6 +829,22 @@ impl Context {
}
}
}
if lhs.is_unbound_var() {
let (sub, sup) = enum_unwrap!(lhs.as_ref(), Type::FreeVar)
.get_bound_types()
.unwrap();
if self.is_trait(&sup) && !self.trait_impl_exists(&sub, &sup) {
return Err(EvalErrors::from(EvalError::no_trait_impl_error(
self.cfg.input.clone(),
line!() as usize,
&sub,
&sup,
t_loc,
self.caused_by(),
None,
)));
}
}
// if the target can't be found in the supertype, the type will be dereferenced.
// In many cases, it is still better to determine the type variable than if the target is not found.
let coerced = self.deref_tyvar(*lhs.clone(), Variance::Covariant, t_loc)?;

View file

@ -348,12 +348,13 @@ impl Context {
sig: &ast::SubrSignature,
id: DefId,
body_t: &Type,
) -> TyCheckResult<()> {
) -> TyCheckResult<Type> {
// already defined as const
if sig.is_const() {
let vi = self.decls.remove(sig.ident.inspect()).unwrap();
let t = vi.t.clone();
self.locals.insert(sig.ident.name.clone(), vi);
return Ok(());
return Ok(t);
}
let muty = if sig.ident.is_const() {
Mutability::Const
@ -443,9 +444,10 @@ impl Context {
VarKind::Defined(id),
Some(comptime_decos),
);
log!(info "Registered {}::{name}: {}", self.name, &vi.t);
let t = vi.t.clone();
log!(info "Registered {}::{name}: {}", self.name, t);
self.locals.insert(name.clone(), vi);
Ok(())
Ok(t)
}
pub(crate) fn fake_subr_assign(&mut self, sig: &ast::SubrSignature, failure_t: Type) {

View file

@ -125,6 +125,9 @@ impl Context {
if l == r {
fv.forced_link(&l.clone());
FreeVar(fv.clone())
} else if r != &Obj && self.is_class(r) {
// x: T <: Bool ==> x: Bool
r.clone()
} else {
let name = format!("%{id}");
self.generalize_constraint(&name, constraint, bounds, lazy_inits);
@ -346,7 +349,7 @@ impl Context {
self.check_trait_exists(sub_t, loc)?;
}*/
if self.is_trait(super_t) {
self.check_trait_exists(sub_t, super_t, loc)?;
self.check_trait_impl(sub_t, super_t, loc)?;
}
// REVIEW: Even if type constraints can be satisfied, implementation may not exist
if self.subtype_of(sub_t, super_t) {
@ -508,20 +511,26 @@ impl Context {
}
}
fn check_trait_exists(
pub(crate) fn trait_impl_exists(&self, class: &Type, trait_: &Type) -> bool {
let mut super_exists = false;
for inst in self.get_trait_impls(trait_).into_iter() {
if self.supertype_of(&inst.sub_type, class)
&& self.supertype_of(&inst.sup_trait, trait_)
{
super_exists = true;
break;
}
}
super_exists
}
fn check_trait_impl(
&self,
class: &Type,
trait_: &Type,
loc: Location,
) -> SingleTyCheckResult<()> {
let mut super_exists = false;
for inst in self.get_trait_impls(trait_).into_iter() {
if self.supertype_of(&inst.sup_trait, trait_) {
super_exists = true;
break;
}
}
if !super_exists {
if !self.trait_impl_exists(class, trait_) {
Err(TyCheckError::no_trait_impl_error(
self.cfg.input.clone(),
line!() as usize,
@ -675,17 +684,23 @@ impl Context {
Ok(())
}
hir::Expr::Def(def) => {
match &mut def.sig {
hir::Signature::Var(var) => {
var.t = self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?;
// It is not possible to further dereference the quantified type.
// TODO: However, it is possible that there are external type variables within the quantified type.
if !def.sig.ref_t().is_quantified() {
match &mut def.sig {
hir::Signature::Var(var) => {
var.t =
self.deref_tyvar(mem::take(&mut var.t), Covariant, var.loc())?;
}
hir::Signature::Subr(subr) => {
subr.t =
self.deref_tyvar(mem::take(&mut subr.t), Covariant, subr.loc())?;
}
}
hir::Signature::Subr(subr) => {
subr.t = self.deref_tyvar(mem::take(&mut subr.t), Covariant, subr.loc())?;
for chunk in def.body.block.iter_mut() {
self.resolve_expr_t(chunk)?;
}
}
for chunk in def.body.block.iter_mut() {
self.resolve_expr_t(chunk)?;
}
Ok(())
}
hir::Expr::Lambda(lambda) => {
@ -1231,29 +1246,15 @@ impl Context {
// * sub_unify(Str, ?T(:> Int, <: Obj)): (?T(:> Str or Int, <: Obj))
// * sub_unify({0}, ?T(:> {1}, <: Nat)): (?T(:> {0, 1}, <: Nat))
Constraint::Sandwiched { sub, sup, cyclicity } => {
/*let judge = match cyclicity {
Cyclicity::Super => self.cyclic_supertype_of(rfv, maybe_sub),
Cyclicity::Not => self.supertype_of(sup, maybe_sub),
_ => todo!(),
};
if !judge {
return Err(TyCheckErrors::from(TyCheckError::subtyping_error(
self.cfg.input.clone(),
line!() as usize,
maybe_sub,
sup, // TODO: this?
sub_loc,
sup_loc,
self.caused_by(),
)));
}*/
if let Some(new_sub) = self.max(maybe_sub, sub) {
/*if let Some(new_sub) = self.max(maybe_sub, sub) {
*constraint =
Constraint::new_sandwiched(new_sub.clone(), mem::take(sup), *cyclicity);
} else {
let new_sub = self.union(maybe_sub, sub);
*constraint = Constraint::new_sandwiched(new_sub, mem::take(sup), *cyclicity);
}
} else {*/
erg_common::log!(err "{maybe_sub}, {sub}");
let new_sub = self.union(maybe_sub, sub);
erg_common::log!(err "{new_sub}");
*constraint = Constraint::new_sandwiched(new_sub, mem::take(sup), *cyclicity);
// }
}
// sub_unify(Nat, ?T(: Type)): (/* ?T(:> Nat) */)
Constraint::TypeOf(ty) => {
@ -1285,18 +1286,7 @@ impl Context {
// sup = union(sup, r) if min does not exist
// * sub_unify(?T(:> Never, <: {1}), {0}): (?T(:> Never, <: {0, 1}))
Constraint::Sandwiched { sub, sup, cyclicity } => {
// maybe_sup: Ref(Obj), sub: Never, sup: Show and Obj
/*if !self.subtype_of(sub, maybe_sup) || !self.supertype_of(sup, maybe_sup) {
return Err(TyCheckErrors::from(TyCheckError::subtyping_error(
self.cfg.input.clone(),
line!() as usize,
sub,
maybe_sup,
sub_loc,
sup_loc,
self.caused_by(),
)));
}*/
// REVIEW: correct?
if let Some(new_sup) = self.min(sup, maybe_sup) {
*constraint =
Constraint::new_sandwiched(mem::take(sub), new_sup.clone(), *cyclicity);
@ -1411,6 +1401,13 @@ impl Context {
self.sub_unify(r, maybe_sup, loc, param_name)?;
Ok(())
}
(_, Type::And(l, r))
| (_, Type::Or(l, r))
| (_, Type::Not(l, r)) => {
self.sub_unify(maybe_sub, l, loc, param_name)?;
self.sub_unify(maybe_sub, r, loc, param_name)?;
Ok(())
}
(_, Type::Ref(t)) => {
self.sub_unify(maybe_sub, t, loc, param_name)?;
Ok(())

View file

@ -722,13 +722,14 @@ impl ASTLowerer {
}
}
let id = body.id;
self.ctx
let t = self
.ctx
.outer
.as_mut()
.unwrap()
.assign_subr(&sig, id, found_body_t)?;
let ident = hir::Identifier::bare(sig.ident.dot, sig.ident.name);
let sig = hir::SubrSignature::new(ident, sig.params, Type::Subr(t));
let sig = hir::SubrSignature::new(ident, sig.params, t);
let body = hir::DefBody::new(body.op, block, body.id);
Ok(hir::Def::new(hir::Signature::Subr(sig), body))
}