fix: quantified subroutine subtyping bugs

This commit is contained in:
Shunsuke Shibayama 2023-02-22 02:40:51 +09:00
parent 4dcca2b06d
commit aa2cea60dd
28 changed files with 638 additions and 222 deletions

View file

@ -19,7 +19,7 @@ use TyParamOrdering::*;
use Type::*;
use crate::context::cache::{SubtypePair, GLOBAL_TYPE_CACHE};
use crate::context::{Context, TyVarCache, Variance};
use crate::context::{Context, Variance};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Credibility {
@ -144,6 +144,7 @@ impl Context {
/// e.g.
/// Named :> Module
/// => Module.super_types == [Named]
///
/// Seq(T) :> Range(T)
/// => Range(T).super_types == [Eq, Mutate, Seq('T), Output('T)]
pub(crate) fn subtype_of(&self, lhs: &Type, rhs: &Type, allow_cast: bool) -> bool {
@ -218,7 +219,6 @@ impl Context {
(Absolutely, true)
}
(FreeVar(l), FreeVar(r)) => {
log!(err "{l}/{r}/{}", l.structural_eq(r));
if l.structural_eq(r) {
(Absolutely, true)
} else {
@ -376,6 +376,9 @@ impl Context {
match (lhs, rhs) {
// Proc :> Func if params are compatible
(Subr(ls), Subr(rs)) if ls.kind == rs.kind || ls.kind.is_proc() => {
if !allow_cast && ls.kind != rs.kind {
return false;
}
let kw_check = || {
for lpt in ls.default_params.iter() {
if let Some(rpt) = rs
@ -497,7 +500,7 @@ impl Context {
}
true
}
(Type, Record(rec)) => {
(Type, Record(rec)) if allow_cast => {
for (_, t) in rec.iter() {
if !self.supertype_of(&Type, t, allow_cast) {
return false;
@ -574,11 +577,11 @@ impl Context {
}
r_preds_clone.is_empty()
}
(Nat, re @ Refinement(_)) => {
(Nat, re @ Refinement(_)) if allow_cast => {
let nat = Type::Refinement(Nat.into_refinement());
self.structural_supertype_of(&nat, re, allow_cast)
}
(re @ Refinement(_), Nat) => {
(re @ Refinement(_), Nat) if allow_cast => {
let nat = Type::Refinement(Nat.into_refinement());
self.structural_supertype_of(re, &nat, allow_cast)
}
@ -588,7 +591,7 @@ impl Context {
// => Eq(Int) :> Eq({1, 2}) :> {1, 2}
// => true
// Bool :> {1} == true
(l, Refinement(r)) => {
(l, Refinement(r)) if allow_cast => {
if self.supertype_of(l, &r.t, allow_cast) {
return true;
}
@ -600,7 +603,7 @@ impl Context {
self.structural_supertype_of(&l, rhs, allow_cast)
}
// ({I: Int | True} :> Int) == true, ({N: Nat | ...} :> Int) == false, ({I: Int | I >= 0} :> Int) == false
(Refinement(l), r) => {
(Refinement(l), r) if allow_cast => {
if l.preds
.iter()
.any(|p| p.mentions(&l.var) && p.can_be_false())
@ -609,28 +612,19 @@ impl Context {
}
self.supertype_of(&l.t, r, allow_cast)
}
(Quantified(l), Quantified(r)) => self.structural_subtype_of(l, r, allow_cast),
(Quantified(quant), r) => {
if quant.has_uninited_qvars() {
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
let inst = self
.instantiate_t_inner(*quant.clone(), &mut tmp_tv_cache, &())
.unwrap();
self.supertype_of(&inst, r, allow_cast)
} else {
self.supertype_of(quant, r, allow_cast)
}
(Quantified(_), Quantified(_)) => {
let l = self.instantiate_dummy(lhs.clone());
let r = self.instantiate_dummy(rhs.clone());
self.sub_unify(&r, &l, &(), None).is_ok()
}
(l, Quantified(quant)) => {
if quant.has_uninited_qvars() {
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
let inst = self
.instantiate_t_inner(*quant.clone(), &mut tmp_tv_cache, &())
.unwrap();
self.supertype_of(l, &inst, allow_cast)
} else {
self.supertype_of(l, quant, allow_cast)
}
// (|T: Type| T -> T) !<: Obj -> Never
(Quantified(_), r) if allow_cast => {
let inst = self.instantiate_dummy(lhs.clone());
self.sub_unify(r, &inst, &(), None).is_ok()
}
(l, Quantified(_)) if allow_cast => {
let inst = self.instantiate_dummy(rhs.clone());
self.sub_unify(&inst, l, &(), None).is_ok()
}
// Int or Str :> Str or Int == (Int :> Str && Str :> Int) || (Int :> Int && Str :> Str) == true
(Or(l_1, l_2), Or(r_1, r_2)) => {
@ -642,11 +636,11 @@ impl Context {
(Not(l), Not(r)) => self.subtype_of(l, r, allow_cast),
// (Int or Str) :> Nat == Int :> Nat || Str :> Nat == true
// (Num or Show) :> Show == Num :> Show || Show :> Num == true
(Or(l_or, r_or), rhs) => {
(Or(l_or, r_or), rhs) if allow_cast => {
self.supertype_of(l_or, rhs, allow_cast) || self.supertype_of(r_or, rhs, allow_cast)
}
// Int :> (Nat or Str) == Int :> Nat && Int :> Str == false
(lhs, Or(l_or, r_or)) => {
(lhs, Or(l_or, r_or)) if allow_cast => {
self.supertype_of(lhs, l_or, allow_cast) && self.supertype_of(lhs, r_or, allow_cast)
}
(And(l_1, l_2), And(r_1, r_2)) => {
@ -655,12 +649,12 @@ impl Context {
&& self.supertype_of(l_2, r_1, allow_cast))
}
// (Num and Show) :> Show == false
(And(l_and, r_and), rhs) => {
(And(l_and, r_and), rhs) if allow_cast => {
self.supertype_of(l_and, rhs, allow_cast)
&& self.supertype_of(r_and, rhs, allow_cast)
}
// Show :> (Num and Show) == true
(lhs, And(l_and, r_and)) => {
(lhs, And(l_and, r_and)) if allow_cast => {
self.supertype_of(lhs, l_and, allow_cast)
|| self.supertype_of(lhs, r_and, allow_cast)
}
@ -668,8 +662,8 @@ impl Context {
(Ref(l), Ref(r)) => self.supertype_of(l, r, allow_cast),
// TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ
// REVIEW: RefMut is invariant, maybe
(Ref(l), r) => self.supertype_of(l, r, allow_cast),
(RefMut { before: l, .. }, r) => self.supertype_of(l, r, allow_cast),
(Ref(l), r) if allow_cast => self.supertype_of(l, r, allow_cast),
(RefMut { before: l, .. }, r) if allow_cast => self.supertype_of(l, r, allow_cast),
// `Eq(Set(T, N)) :> Set(T, N)` will be false, such cases are judged by nominal_supertype_of
(
Poly {

View file

@ -948,6 +948,7 @@ impl Context {
}
}
/// lhs: mainly class
pub(crate) fn eval_proj(
&self,
lhs: Type,

View file

@ -872,10 +872,14 @@ impl Context {
fn resolve_params_t(&self, params: &mut hir::Params, qnames: &Set<Str>) -> TyCheckResult<()> {
for param in params.non_defaults.iter_mut() {
// generalization should work properly for the subroutine type, but may not work for the parameters' own types
// HACK: so generalize them manually
param.vi.t.generalize();
param.vi.t =
self.deref_tyvar(mem::take(&mut param.vi.t), Contravariant, qnames, param)?;
}
if let Some(var_params) = &mut params.var_params {
var_params.vi.t.generalize();
var_params.vi.t = self.deref_tyvar(
mem::take(&mut var_params.vi.t),
Contravariant,
@ -884,6 +888,7 @@ impl Context {
)?;
}
for param in params.defaults.iter_mut() {
param.sig.vi.t.generalize();
param.sig.vi.t =
self.deref_tyvar(mem::take(&mut param.sig.vi.t), Contravariant, qnames, param)?;
self.resolve_expr_t(&mut param.default_val)?;

View file

@ -29,7 +29,7 @@ use crate::context::instantiate::ConstTemplate;
use crate::context::{
ClassDefType, Context, ContextKind, MethodInfo, ModuleContext, ParamSpec, TraitImpl,
};
use crate::module::{SharedCompilerResource, SharedModuleCache};
use crate::module::SharedCompilerResource;
use crate::ty::free::Constraint;
use crate::ty::value::ValueObj;
use crate::ty::Type;
@ -703,10 +703,10 @@ impl Context {
self.consts
.insert(name.clone(), ValueObj::builtin_t(t.clone()));
for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.qual_name()) {
if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) {
impls.insert(TraitImpl::new(t.clone(), impl_trait.clone()));
} else {
self.trait_impls.insert(
self.trait_impls().register(
impl_trait.qual_name(),
set![TraitImpl::new(t.clone(), impl_trait.clone())],
);
@ -773,10 +773,10 @@ impl Context {
self.consts
.insert(name.clone(), ValueObj::builtin_t(t.clone()));
for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.qual_name()) {
if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) {
impls.insert(TraitImpl::new(t.clone(), impl_trait.clone()));
} else {
self.trait_impls.insert(
self.trait_impls().register(
impl_trait.qual_name(),
set![TraitImpl::new(t.clone(), impl_trait.clone())],
);
@ -837,11 +837,11 @@ impl Context {
}
}
if let ContextKind::GluePatch(tr_inst) = &ctx.kind {
if let Some(impls) = self.trait_impls.get_mut(&tr_inst.sup_trait.qual_name()) {
if let Some(impls) = self.trait_impls().get_mut(&tr_inst.sup_trait.qual_name()) {
impls.insert(tr_inst.clone());
} else {
self.trait_impls
.insert(tr_inst.sup_trait.qual_name(), set![tr_inst.clone()]);
self.trait_impls()
.register(tr_inst.sup_trait.qual_name(), set![tr_inst.clone()]);
}
}
self.patches.insert(name, ctx);
@ -896,8 +896,8 @@ impl Context {
self.register_builtin_py_impl(ELLIPSIS, Ellipsis, Const, Private, Some(ELLIPSIS));
}
pub(crate) fn init_builtins(cfg: ErgConfig, mod_cache: &SharedModuleCache) {
let mut ctx = Context::builtin_module("<builtins>", cfg, 100);
pub(crate) fn init_builtins(cfg: ErgConfig, shared: SharedCompilerResource) {
let mut ctx = Context::builtin_module("<builtins>", cfg, shared.clone(), 100);
ctx.init_builtin_consts();
ctx.init_builtin_funcs();
ctx.init_builtin_const_funcs();
@ -907,7 +907,9 @@ impl Context {
ctx.init_builtin_classes();
ctx.init_builtin_patches();
let module = ModuleContext::new(ctx, dict! {});
mod_cache.register(PathBuf::from("<builtins>"), None, module);
shared
.mod_cache
.register(PathBuf::from("<builtins>"), None, module);
}
pub fn new_module<S: Into<Str>>(

View file

@ -50,8 +50,8 @@ pub enum SubstituteResult {
impl Context {
pub(crate) fn get_ctx_from_path(&self, path: &Path) -> Option<&Context> {
self.mod_cache()
.and_then(|cache| cache.ref_ctx(path))
.or_else(|| self.py_mod_cache().and_then(|cache| cache.ref_ctx(path)))
.ref_ctx(path)
.or_else(|| self.py_mod_cache().ref_ctx(path))
.map(|mod_ctx| &mod_ctx.context)
}
@ -1853,15 +1853,16 @@ impl Context {
.map(|(_, ctx)| ctx.super_traits.clone().into_iter())
}
/// include `typ` itself.
/// if `typ` is a refinement type, include the base type (refine.t)
pub(crate) fn _get_super_classes(&self, typ: &Type) -> Option<impl Iterator<Item = Type>> {
self.get_nominal_type_ctx(typ).map(|(_, ctx)| {
self.get_nominal_type_ctx(typ).map(|(t, ctx)| {
let super_classes = ctx.super_classes.clone();
let derefined = typ.derefine();
if typ != &derefined {
vec![derefined].into_iter().chain(super_classes)
vec![t.clone(), derefined].into_iter().chain(super_classes)
} else {
vec![].into_iter().chain(super_classes)
vec![t.clone()].into_iter().chain(super_classes)
}
})
}
@ -2054,8 +2055,8 @@ impl Context {
None
}
pub(crate) fn get_trait_impls(&self, t: &Type) -> Set<TraitImpl> {
match t {
pub(crate) fn get_trait_impls(&self, trait_: &Type) -> Set<TraitImpl> {
match trait_ {
// And(Add, Sub) == intersection({Int <: Add(Int), Bool <: Add(Bool) ...}, {Int <: Sub(Int), ...})
// == {Int <: Add(Int) and Sub(Int), ...}
Type::And(l, r) => {
@ -2079,18 +2080,18 @@ impl Context {
// FIXME:
l_impls.union(&r_impls)
}
_ => self.get_simple_trait_impls(t),
_ => self.get_simple_trait_impls(trait_),
}
}
pub(crate) fn get_simple_trait_impls(&self, t: &Type) -> Set<TraitImpl> {
let current = if let Some(impls) = self.trait_impls.get(&t.qual_name()) {
pub(crate) fn get_simple_trait_impls(&self, trait_: &Type) -> Set<TraitImpl> {
let current = if let Some(impls) = self.trait_impls().get(&trait_.qual_name()) {
impls.clone()
} else {
set! {}
};
if let Some(outer) = self.get_outer().or_else(|| self.get_builtins()) {
current.union(&outer.get_simple_trait_impls(t))
current.union(&outer.get_simple_trait_impls(trait_))
} else {
current
}
@ -2401,21 +2402,17 @@ impl Context {
}
fn get_proj_candidates(&self, lhs: &Type, rhs: &Str) -> Set<Type> {
let allow_cast = true;
#[allow(clippy::single_match)]
match lhs {
Type::FreeVar(fv) => {
if let Some(sup) = fv.get_super() {
let insts = self.get_trait_impls(&sup);
let candidates = insts.into_iter().filter_map(move |inst| {
if self.supertype_of(&inst.sup_trait, &sup, allow_cast) {
self.eval_t_params(proj(inst.sub_type, rhs), self.level, &())
.ok()
} else {
None
}
});
return candidates.collect();
if self.is_trait(&sup) {
return self.get_trait_proj_candidates(&sup, rhs);
} else {
return self
.eval_proj(sup, rhs.clone(), self.level, &())
.map_or(set! {}, |t| set! {t});
}
}
}
_ => {}
@ -2423,6 +2420,20 @@ impl Context {
set! {}
}
fn get_trait_proj_candidates(&self, trait_: &Type, rhs: &Str) -> Set<Type> {
let allow_cast = true;
let impls = self.get_trait_impls(trait_);
let candidates = impls.into_iter().filter_map(move |inst| {
if self.supertype_of(&inst.sup_trait, trait_, allow_cast) {
self.eval_t_params(proj(inst.sub_type, rhs), self.level, &())
.ok()
} else {
None
}
});
candidates.collect()
}
pub(crate) fn is_class(&self, typ: &Type) -> bool {
match typ {
Type::And(_l, _r) => false,

View file

@ -1497,4 +1497,27 @@ impl Context {
other => Ok(other),
}
}
pub(crate) fn instantiate_dummy(&self, quantified: Type) -> Type {
match quantified {
FreeVar(fv) if fv.is_linked() => self.instantiate_dummy(fv.crack().clone()),
Quantified(quant) => {
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
let ty = self
.instantiate_t_inner(*quant, &mut tmp_tv_cache, &())
.unwrap();
if cfg!(feature = "debug") && ty.has_qvar() {
panic!("{ty} has qvar")
}
ty
}
Refinement(refine) if refine.t.is_quantified_subr() => {
let quant = enum_unwrap!(*refine.t, Type::Quantified);
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
self.instantiate_t_inner(*quant, &mut tmp_tv_cache, &())
.unwrap()
}
other => unreachable!("{other}"),
}
}
}

View file

@ -24,11 +24,10 @@ use erg_common::config::Input;
use erg_common::dict::Dict;
use erg_common::error::Location;
use erg_common::impl_display_from_debug;
use erg_common::set::Set;
use erg_common::traits::{Locational, Stream};
use erg_common::vis::Visibility;
use erg_common::Str;
use erg_common::{fn_name, get_hash, log};
use erg_common::{fmt_option, fn_name, get_hash, log};
use ast::{DefId, DefKind, VarName};
use erg_parser::ast;
@ -217,6 +216,26 @@ impl From<DefKind> for ContextKind {
}
}
impl fmt::Display for ContextKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Func => write!(f, "Func"),
Self::Proc => write!(f, "Proc"),
Self::Class => write!(f, "Class"),
Self::MethodDefs(trait_) => write!(f, "MethodDefs({})", fmt_option!(trait_)),
Self::PatchMethodDefs(type_) => write!(f, "PatchMethodDefs({type_})"),
Self::Trait => write!(f, "Trait"),
Self::StructuralTrait => write!(f, "StructuralTrait"),
Self::Patch(type_) => write!(f, "Patch({type_})"),
Self::StructuralPatch(type_) => write!(f, "StructuralPatch({type_})"),
Self::GluePatch(type_) => write!(f, "GluePatch({type_})"),
Self::Module => write!(f, "Module"),
Self::Instant => write!(f, "Instant"),
Self::Dummy => write!(f, "Dummy"),
}
}
}
impl ContextKind {
pub const fn is_method_def(&self) -> bool {
matches!(self, Self::MethodDefs(_))
@ -314,10 +333,6 @@ pub struct Context {
/// K: メソッド名, V: それを実装するパッチたち
/// 提供メソッドはスコープごとに実装を切り替えることができる
pub(crate) method_impl_patches: Dict<VarName, Vec<VarName>>,
/// K: name of a trait, V: (type, monomorphised trait that the type implements)
/// K: トレイトの名前, V: (型, その型が実装する単相化トレイト)
/// e.g. { "Named": [(Type, Named), (Func, Named), ...], "Add": [(Nat, Add(Nat)), (Int, Add(Int)), ...], ... }
pub(crate) trait_impls: Dict<Str, Set<TraitImpl>>,
/// stores declared names (not initialized)
pub(crate) decls: Dict<VarName, VarInfo>,
/// for error reporting
@ -510,7 +525,6 @@ impl Context {
method_to_traits: Dict::default(),
method_to_classes: Dict::default(),
method_impl_patches: Dict::default(),
trait_impls: Dict::default(),
params: params_,
decls: Dict::default(),
future_defined_locals: Dict::default(),
@ -795,8 +809,13 @@ impl Context {
}
#[inline]
pub fn builtin_module<S: Into<Str>>(name: S, cfg: ErgConfig, capacity: usize) -> Self {
Self::module(name.into(), cfg, None, capacity)
pub fn builtin_module<S: Into<Str>>(
name: S,
cfg: ErgConfig,
shared: SharedCompilerResource,
capacity: usize,
) -> Self {
Self::module(name.into(), cfg, Some(shared), capacity)
}
#[inline]
@ -979,20 +998,24 @@ impl Context {
.collect()
}
pub(crate) fn mod_cache(&self) -> Option<&SharedModuleCache> {
self.shared.as_ref().map(|shared| &shared.mod_cache)
pub(crate) fn mod_cache(&self) -> &SharedModuleCache {
&self.shared().mod_cache
}
pub(crate) fn py_mod_cache(&self) -> Option<&SharedModuleCache> {
self.shared.as_ref().map(|shared| &shared.py_mod_cache)
pub(crate) fn py_mod_cache(&self) -> &SharedModuleCache {
&self.shared().py_mod_cache
}
pub fn index(&self) -> Option<&crate::module::SharedModuleIndex> {
self.shared.as_ref().map(|shared| &shared.index)
pub fn index(&self) -> &crate::module::SharedModuleIndex {
&self.shared().index
}
pub fn shared(&self) -> Option<&SharedCompilerResource> {
self.shared.as_ref()
pub fn trait_impls(&self) -> &crate::module::SharedTraitImpls {
&self.shared().trait_impls
}
pub fn shared(&self) -> &SharedCompilerResource {
self.shared.as_ref().unwrap()
}
}

View file

@ -165,9 +165,7 @@ impl Context {
py_name,
self.absolutize(ident.name.loc()),
);
if let Some(shared) = self.shared() {
shared.index.register(&vi);
}
self.index().register(&vi);
self.future_defined_locals.insert(ident.name.clone(), vi);
Ok(())
}
@ -213,9 +211,7 @@ impl Context {
py_name,
self.absolutize(sig.ident.name.loc()),
);
if let Some(shared) = self.shared() {
shared.index.register(&vi);
}
self.index().register(&vi);
if let Some(_decl) = self.decls.remove(name) {
Err(TyCheckErrors::from(TyCheckError::duplicate_decl_error(
self.cfg.input.clone(),
@ -403,9 +399,7 @@ impl Context {
None,
self.absolutize(name.loc()),
);
if let Some(shared) = self.shared() {
shared.index.register(&vi);
}
self.index().register(&vi);
sig.vi = vi.clone();
self.params.push((Some(name.clone()), vi));
if errs.is_empty() {
@ -1076,9 +1070,7 @@ impl Context {
None,
self.absolutize(ident.name.loc()),
);
if let Some(shared) = self.shared() {
shared.index.register(&vi);
}
self.index().register(&vi);
self.decls.insert(ident.name.clone(), vi);
self.consts.insert(ident.name.clone(), other);
Ok(())
@ -1372,9 +1364,7 @@ impl Context {
None,
self.absolutize(name.loc()),
);
if let Some(shared) = self.shared() {
shared.index.register(&vi);
}
self.index().register(&vi);
self.decls.insert(name.clone(), vi);
self.consts
.insert(name.clone(), ValueObj::Type(TypeObj::Builtin(t)));
@ -1421,17 +1411,15 @@ impl Context {
None,
self.absolutize(name.loc()),
);
if let Some(shared) = self.shared() {
shared.index.register(&vi);
}
self.index().register(&vi);
self.decls.insert(name.clone(), vi);
self.consts
.insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen)));
for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.qual_name()) {
if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) {
impls.insert(TraitImpl::new(t.clone(), impl_trait.clone()));
} else {
self.trait_impls.insert(
self.trait_impls().register(
impl_trait.qual_name(),
set![TraitImpl::new(t.clone(), impl_trait.clone())],
);
@ -1507,10 +1495,10 @@ impl Context {
self.consts
.insert(name.clone(), ValueObj::Type(TypeObj::Generated(gen)));
for impl_trait in ctx.super_traits.iter() {
if let Some(impls) = self.trait_impls.get_mut(&impl_trait.qual_name()) {
if let Some(impls) = self.trait_impls().get_mut(&impl_trait.qual_name()) {
impls.insert(TraitImpl::new(t.clone(), impl_trait.clone()));
} else {
self.trait_impls.insert(
self.trait_impls().register(
impl_trait.qual_name(),
set![TraitImpl::new(t.clone(), impl_trait.clone())],
);
@ -1555,8 +1543,8 @@ impl Context {
fn import_erg_mod(&self, mod_name: &Literal) -> CompileResult<PathBuf> {
let ValueObj::Str(__name__) = mod_name.value.clone() else { todo!("{mod_name}") };
let mod_cache = self.mod_cache().unwrap();
let py_mod_cache = self.py_mod_cache().unwrap();
let mod_cache = self.mod_cache();
let py_mod_cache = self.py_mod_cache();
let path = match Self::resolve_real_path(&self.cfg, Path::new(&__name__[..])) {
Some(path) => path,
None => {
@ -1687,9 +1675,9 @@ impl Context {
mod_name.loc(),
self.caused_by(),
self.similar_builtin_erg_mod_name(&__name__)
.or_else(|| self.mod_cache().unwrap().get_similar_name(&__name__)),
.or_else(|| self.mod_cache().get_similar_name(&__name__)),
self.similar_builtin_py_mod_name(&__name__)
.or_else(|| self.py_mod_cache().unwrap().get_similar_name(&__name__)),
.or_else(|| self.py_mod_cache().get_similar_name(&__name__)),
);
Err(TyCheckErrors::from(err))
}
@ -1725,7 +1713,7 @@ impl Context {
fn import_py_mod(&self, mod_name: &Literal) -> CompileResult<PathBuf> {
let ValueObj::Str(__name__) = mod_name.value.clone() else { todo!("{mod_name}") };
let py_mod_cache = self.py_mod_cache().unwrap();
let py_mod_cache = self.py_mod_cache();
let path = self.get_path(mod_name, __name__)?;
if let Some(referrer) = self.cfg.input.path() {
let graph = &self.shared.as_ref().unwrap().graph;
@ -1888,8 +1876,6 @@ impl Context {
}
pub fn inc_ref<L: Locational>(&self, vi: &VarInfo, name: &L) {
self.index()
.unwrap()
.inc_ref(vi, self.absolutize(name.loc()));
self.index().inc_ref(vi, self.absolutize(name.loc()));
}
}

View file

@ -1,5 +1,6 @@
//! test module for `Context`
use erg_common::set;
use erg_common::traits::StructuralEq;
use erg_common::Str;
use crate::ty::constructors::{func1, mono, mono_q, poly, refinement};
@ -17,7 +18,7 @@ impl Context {
panic!("variable not found: {varname}");
};
println!("{varname}: {}", vi.t);
if self.same_type_of(&vi.t, ty, false) {
if vi.t.structural_eq(ty) {
Ok(())
} else {
println!("{varname} is not the type of {ty}");
@ -34,13 +35,22 @@ impl Context {
Type::Int,
set! { Predicate::eq(var, TyParam::value(1)) },
);
if self.supertype_of(&lhs, &rhs, false) {
if self.supertype_of(&lhs, &rhs, true) {
Ok(())
} else {
Err(())
}
}
pub fn test_quant_subtyping(&self) -> Result<(), ()> {
let t = crate::ty::constructors::type_q("T");
let quant = func1(t.clone(), t).quantify();
let subr = func1(Obj, Never);
assert!(!self.subtype_of(&quant, &subr, true));
assert!(self.subtype_of(&subr, &quant, true));
Ok(())
}
pub fn test_resolve_trait_inner1(&self) -> Result<(), ()> {
let name = Str::ever("Add");
let params = vec![TyParam::t(Nat)];

View file

@ -728,6 +728,20 @@ impl Context {
Ok(())
}
(Type::Subr(lsub), Type::Subr(rsub)) => {
lsub.non_default_params
.iter()
.zip(rsub.non_default_params.iter())
.try_for_each(|(l, r)| {
// contravariant
self.sub_unify(r.typ(), l.typ(), loc, param_name)
})?;
lsub.var_params
.iter()
.zip(rsub.var_params.iter())
.try_for_each(|(l, r)| {
// contravariant
self.sub_unify(r.typ(), l.typ(), loc, param_name)
})?;
for lpt in lsub.default_params.iter() {
if let Some(rpt) = rsub
.default_params
@ -737,16 +751,9 @@ impl Context {
// contravariant
self.sub_unify(rpt.typ(), lpt.typ(), loc, param_name)?;
} else {
todo!()
unreachable!()
}
}
lsub.non_default_params
.iter()
.zip(rsub.non_default_params.iter())
.try_for_each(|(l, r)| {
// contravariant
self.sub_unify(r.typ(), l.typ(), loc, param_name)
})?;
// covariant
self.sub_unify(&lsub.return_t, &rsub.return_t, loc, param_name)?;
Ok(())
@ -781,9 +788,7 @@ impl Context {
}
})?;
// covariant
if !lsub.return_t.is_generalized() {
self.sub_unify(&lsub.return_t, &rsub.return_t, loc, param_name)?;
}
self.sub_unify(&lsub.return_t, &rsub.return_t, loc, param_name)?;
Ok(())
}
(Type::Subr(lsub), Type::Quantified(rsub)) => {
@ -815,9 +820,7 @@ impl Context {
}
})?;
// covariant
if !rsub.return_t.is_generalized() {
self.sub_unify(&lsub.return_t, &rsub.return_t, loc, param_name)?;
}
self.sub_unify(&lsub.return_t, &rsub.return_t, loc, param_name)?;
Ok(())
}
(