Improve error message indication for op calls

This commit is contained in:
Shunsuke Shibayama 2022-08-23 22:48:06 +09:00
parent 9f6a4a43fc
commit 00db622f2b
3 changed files with 120 additions and 147 deletions

View file

@ -7,6 +7,7 @@ use std::option::Option; // conflicting to Type::Option
use erg_common::dict::Dict; use erg_common::dict::Dict;
use erg_common::error::{ErrorCore, Location}; use erg_common::error::{ErrorCore, Location};
use erg_common::impl_display_from_debug;
use erg_common::levenshtein::levenshtein; use erg_common::levenshtein::levenshtein;
use erg_common::set::Set; use erg_common::set::Set;
use erg_common::traits::{HasType, Locational, Stream}; use erg_common::traits::{HasType, Locational, Stream};
@ -114,6 +115,8 @@ pub enum DefaultInfo {
WithDefault, WithDefault,
} }
impl_display_from_debug!(DefaultInfo);
impl DefaultInfo { impl DefaultInfo {
pub const fn has_default(&self) -> bool { pub const fn has_default(&self) -> bool {
matches!(self, DefaultInfo::WithDefault) matches!(self, DefaultInfo::WithDefault)
@ -130,6 +133,8 @@ pub enum Variance {
Invariant, // 不変 Invariant, // 不変
} }
impl_display_from_debug!(Variance);
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ParamSpec { pub struct ParamSpec {
pub(crate) name: Option<&'static str>, // TODO: nested pub(crate) name: Option<&'static str>, // TODO: nested
@ -1571,7 +1576,7 @@ impl Context {
for (param_ty, pos_arg) in params.clone().zip(pos_args) { for (param_ty, pos_arg) in params.clone().zip(pos_args) {
let arg_t = pos_arg.expr.ref_t(); let arg_t = pos_arg.expr.ref_t();
let param_t = &param_ty.ty; let param_t = &param_ty.ty;
self.sub_unify(arg_t, param_t, None, Some(pos_arg.loc())) self.sub_unify(arg_t, param_t, Some(pos_arg.loc()), None)
.map_err(|e| { .map_err(|e| {
// REVIEW: // REVIEW:
let name = callee.var_full_name().unwrap_or_else(|| "".to_string()); let name = callee.var_full_name().unwrap_or_else(|| "".to_string());
@ -1616,7 +1621,7 @@ impl Context {
}; };
for kw_arg in kw_args.iter() { for kw_arg in kw_args.iter() {
if let Some(param_ty) = param_ts.get(kw_arg.keyword.inspect()) { if let Some(param_ty) = param_ts.get(kw_arg.keyword.inspect()) {
self.sub_unify(kw_arg.expr.ref_t(), param_ty, None, Some(kw_arg.loc()))?; self.sub_unify(kw_arg.expr.ref_t(), param_ty, Some(kw_arg.loc()), None)?;
} else { } else {
return Err(TyCheckError::unexpected_kw_arg_error( return Err(TyCheckError::unexpected_kw_arg_error(
line!() as usize, line!() as usize,
@ -1917,15 +1922,17 @@ impl Context {
/// instantiate_trait(Array(Int, 2)) => Err(Array(Int, 2)) /// instantiate_trait(Array(Int, 2)) => Err(Array(Int, 2))
/// instantiate_trait(Int) => Err(Int) /// instantiate_trait(Int) => Err(Int)
/// ``` /// ```
fn instantiate_trait(&self, generic: Type) -> Result<Type, Type> { fn instantiate_trait(&self, maybe_trait: Type) -> Result<Type, Type> {
match generic { match maybe_trait {
Type::Poly { name, params } => { Type::Poly { name, params } => {
let t_name = name.clone(); let t_name = name.clone();
let t_params = params.clone(); let t_params = params.clone();
let t = Type::Poly { name, params }; let maybe_trait = Type::Poly { name, params };
let mut min = Type::Never; let mut min = Type::Never;
for (concrete_t, concrete_trait) in self.rec_get_poly_trait_impls(&t_name) { for (concrete_t, concrete_trait) in self.rec_get_poly_trait_impls(&t_name) {
if self.rec_supertype_of(&concrete_trait, &t) { log!("{concrete_t}, {concrete_trait}, {maybe_trait}");
if self.rec_supertype_of(&concrete_trait, &maybe_trait) {
log!("super");
min = self.rec_min(&min, &concrete_t).unwrap_or(&min).clone(); min = self.rec_min(&min, &concrete_t).unwrap_or(&min).clone();
} }
} }
@ -1952,7 +1959,7 @@ impl Context {
if instantiated { if instantiated {
Ok(Type::poly(t_name, new_params)) Ok(Type::poly(t_name, new_params))
} else { } else {
Err(t) Err(maybe_trait)
} }
} else { } else {
Ok(min) Ok(min)
@ -2060,8 +2067,8 @@ impl Context {
} }
Ok(()) Ok(())
} else if allow_divergence } else if allow_divergence
&& (self.eq_tp(tp, &TyParam::value(Inf), None, None) && (self.eq_tp(tp, &TyParam::value(Inf), None)
|| self.eq_tp(tp, &TyParam::value(NegInf), None, None)) || self.eq_tp(tp, &TyParam::value(NegInf), None))
&& self.rec_subtype_of(&fv_t, &Type::mono("Num")) && self.rec_subtype_of(&fv_t, &Type::mono("Num"))
{ {
fv.link(tp); fv.link(tp);
@ -2095,7 +2102,6 @@ impl Context {
before: &TyParam, before: &TyParam,
after: &TyParam, after: &TyParam,
bounds: Option<&Set<TyBound>>, bounds: Option<&Set<TyBound>>,
lhs_variance: Option<&Vec<Variance>>,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
match (before, after) { match (before, after) {
(TyParam::Value(ValueObj::Mut(l)), TyParam::Value(ValueObj::Mut(r))) => { (TyParam::Value(ValueObj::Mut(l)), TyParam::Value(ValueObj::Mut(r))) => {
@ -2110,7 +2116,7 @@ impl Context {
(TyParam::UnaryOp { op: lop, val: lval }, TyParam::UnaryOp { op: rop, val: rval }) (TyParam::UnaryOp { op: lop, val: lval }, TyParam::UnaryOp { op: rop, val: rval })
if lop == rop => if lop == rop =>
{ {
self.reunify_tp(lval, rval, bounds, lhs_variance) self.reunify_tp(lval, rval, bounds)
} }
( (
TyParam::BinOp { op: lop, lhs, rhs }, TyParam::BinOp { op: lop, lhs, rhs },
@ -2120,10 +2126,10 @@ impl Context {
rhs: rhs2, rhs: rhs2,
}, },
) if lop == rop => { ) if lop == rop => {
self.reunify_tp(lhs, lhs2, bounds, lhs_variance)?; self.reunify_tp(lhs, lhs2, bounds)?;
self.reunify_tp(rhs, rhs2, bounds, lhs_variance) self.reunify_tp(rhs, rhs2, bounds)
} }
(l, r) if self.eq_tp(l, r, bounds, lhs_variance) => Ok(()), (l, r) if self.eq_tp(l, r, bounds) => Ok(()),
(l, r) => panic!("type-parameter re-unification failed:\nl: {l}\nr: {r}"), (l, r) => panic!("type-parameter re-unification failed:\nl: {l}\nr: {r}"),
} }
} }
@ -2279,8 +2285,8 @@ impl Context {
Ok(()) Ok(())
} }
(Type::Refinement(l), Type::Refinement(r)) => { (Type::Refinement(l), Type::Refinement(r)) => {
if !self.structural_supertype_of(&l.t, &r.t, None, None) if !self.structural_supertype_of(&l.t, &r.t, None)
&& !self.structural_supertype_of(&r.t, &l.t, None, None) && !self.structural_supertype_of(&r.t, &l.t, None)
{ {
return Err(TyCheckError::unification_error( return Err(TyCheckError::unification_error(
line!() as usize, line!() as usize,
@ -2410,11 +2416,11 @@ impl Context {
)); ));
} }
for (l, r) in lps.iter().zip(rps.iter()) { for (l, r) in lps.iter().zip(rps.iter()) {
self.reunify_tp(l, r, None, None)?; self.reunify_tp(l, r, None)?;
} }
Ok(()) Ok(())
} }
(l, r) if self.structural_same_type_of(l, r, None, None) => Ok(()), (l, r) if self.structural_same_type_of(l, r, None) => Ok(()),
(l, r) => Err(TyCheckError::re_unification_error( (l, r) => Err(TyCheckError::re_unification_error(
line!() as usize, line!() as usize,
l, l,
@ -2564,14 +2570,11 @@ impl Context {
let mut opt_smallest = None; let mut opt_smallest = None;
for ctx in self.rec_sorted_sup_type_ctxs(maybe_sub) { for ctx in self.rec_sorted_sup_type_ctxs(maybe_sub) {
let bounds = ctx.type_params_bounds(); let bounds = ctx.type_params_bounds();
let variance = ctx.type_params_variance();
let instances = ctx let instances = ctx
.super_classes .super_classes
.iter() .iter()
.chain(ctx.super_traits.iter()) .chain(ctx.super_traits.iter())
.filter(|t| { .filter(|t| self.structural_supertype_of(maybe_sup, t, Some(&bounds)));
self.structural_supertype_of(maybe_sup, t, Some(&bounds), Some(&variance))
});
// instanceが複数ある場合、経験的に最も小さい型を選ぶのが良い // instanceが複数ある場合、経験的に最も小さい型を選ぶのが良い
// これでうまくいかない場合は型指定してもらう(REVIEW: もっと良い方法があるか?) // これでうまくいかない場合は型指定してもらう(REVIEW: もっと良い方法があるか?)
if let Some(t) = self.smallest_ref_t(instances) { if let Some(t) = self.smallest_ref_t(instances) {
@ -2588,9 +2591,8 @@ impl Context {
.filter_map(|(patch_name, l, r)| { .filter_map(|(patch_name, l, r)| {
let patch = self.rec_get_patch(patch_name).unwrap(); let patch = self.rec_get_patch(patch_name).unwrap();
let bounds = patch.type_params_bounds(); let bounds = patch.type_params_bounds();
let variance = patch.type_params_variance(); if self.structural_supertype_of(l, maybe_sub, Some(&bounds))
if self.structural_supertype_of(l, maybe_sub, Some(&bounds), Some(&variance)) && self.structural_supertype_of(r, maybe_sup, Some(&bounds))
&& self.structural_supertype_of(r, maybe_sup, Some(&bounds), Some(&variance))
{ {
let tv_ctx = TyVarContext::new(self.level, bounds, &self); let tv_ctx = TyVarContext::new(self.level, bounds, &self);
let (l, _) = Self::instantiate_t(l.clone(), tv_ctx.clone()); let (l, _) = Self::instantiate_t(l.clone(), tv_ctx.clone());
@ -3169,7 +3171,6 @@ impl Context {
namespace: &Str, namespace: &Str,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
if let Some(method_name) = method_name.as_ref() { if let Some(method_name) = method_name.as_ref() {
erg_common::fmt_dbg!(obj, obj.ref_t());
for ctx in self.rec_sorted_sup_type_ctxs(obj.ref_t()) { for ctx in self.rec_sorted_sup_type_ctxs(obj.ref_t()) {
if let Some(vi) = ctx.locals.get(method_name.inspect()) { if let Some(vi) = ctx.locals.get(method_name.inspect()) {
return Ok(vi.t()); return Ok(vi.t());
@ -3197,16 +3198,21 @@ impl Context {
namespace: &Str, namespace: &Str,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
erg_common::debug_power_assert!(args.len() == 2); erg_common::debug_power_assert!(args.len() == 2);
let symbol = Token::symbol(binop_to_dname(op.inspect())); let cont = binop_to_dname(op.inspect());
let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin);
let t = self.rec_get_var_t(&symbol, Private, namespace)?; let t = self.rec_get_var_t(&symbol, Private, namespace)?;
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t)); let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t));
self.get_call_t(&op, &None, args, &[], namespace) self.get_call_t(&op, &None, args, &[], namespace)
.map_err(|e| { .map_err(|e| {
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Local:(_)));
let lhs = args[0].expr.clone();
let rhs = args[1].expr.clone();
let bin = hir::BinOp::new(op.name, lhs, rhs, op.t);
// HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする // HACK: dname.loc()はダミーLocationしか返さないので、エラーならop.loc()で上書きする
let core = ErrorCore::new( let core = ErrorCore::new(
e.core.errno, e.core.errno,
e.core.kind, e.core.kind,
op.loc(), bin.loc(),
e.core.desc, e.core.desc,
e.core.hint, e.core.hint,
); );
@ -3221,15 +3227,19 @@ impl Context {
namespace: &Str, namespace: &Str,
) -> TyCheckResult<Type> { ) -> TyCheckResult<Type> {
erg_common::debug_power_assert!(args.len() == 1); erg_common::debug_power_assert!(args.len() == 1);
let symbol = Token::symbol(unaryop_to_dname(op.inspect())); let cont = unaryop_to_dname(op.inspect());
let symbol = Token::new(op.kind, Str::rc(cont), op.lineno, op.col_begin);
let t = self.rec_get_var_t(&symbol, Private, namespace)?; let t = self.rec_get_var_t(&symbol, Private, namespace)?;
let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t)); let op = hir::Expr::Accessor(hir::Accessor::local(symbol, t));
self.get_call_t(&op, &None, args, &[], namespace) self.get_call_t(&op, &None, args, &[], namespace)
.map_err(|e| { .map_err(|e| {
let op = enum_unwrap!(op, hir::Expr::Accessor:(hir::Accessor::Local:(_)));
let expr = args[0].expr.clone();
let unary = hir::UnaryOp::new(op.name, expr, op.t);
let core = ErrorCore::new( let core = ErrorCore::new(
e.core.errno, e.core.errno,
e.core.kind, e.core.kind,
op.loc(), unary.loc(),
e.core.desc, e.core.desc,
e.core.hint, e.core.hint,
); );
@ -3264,50 +3274,39 @@ impl Context {
); );
self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?; self.substitute_call(obj, method_name, &instance, pos_args, kw_args)?;
log!("Substituted:\ninstance: {instance}"); log!("Substituted:\ninstance: {instance}");
let res = match self.instantiate_trait(instance) { let res = self.eval.eval_t_params(instance, &self, self.level)?;
Ok(t) => t,
Err(e) => e,
};
log!("Trait instantiated:\nres: {res}\n");
let res = self.eval.eval_t_params(res, &self, self.level)?;
log!("Params Evaluated:\nres: {res}\n"); log!("Params Evaluated:\nres: {res}\n");
let res = self.deref_tyvar(res)?; let res = self.deref_tyvar(res)?;
log!("Derefed:\nres: {res}\n"); log!("Derefed:\nres: {res}\n");
self.propagate(&res, obj)?; self.propagate(&res, obj)?;
log!("Propagated:\nres: {res}\n"); log!("Propagated:\nres: {res}\n");
let res = match self.instantiate_trait(res) {
Ok(t) => t,
Err(e) => e,
};
log!("Trait instantiated:\nres: {res}\n");
Ok(res) Ok(res)
} }
fn eq_tp( fn eq_tp(&self, lhs: &TyParam, rhs: &TyParam, bounds: Option<&Set<TyBound>>) -> bool {
&self,
lhs: &TyParam,
rhs: &TyParam,
bounds: Option<&Set<TyBound>>,
lhs_variance: Option<&Vec<Variance>>,
) -> bool {
match (lhs, rhs) { match (lhs, rhs) {
(TyParam::Type(lhs), TyParam::Type(rhs)) => { (TyParam::Type(lhs), TyParam::Type(rhs)) => {
return self.structural_same_type_of(lhs, rhs, bounds, lhs_variance) return self.structural_same_type_of(lhs, rhs, bounds)
} }
(TyParam::Mono(l), TyParam::Mono(r)) => { (TyParam::Mono(l), TyParam::Mono(r)) => {
if let (Some((l, _)), Some((r, _))) = ( if let (Some((l, _)), Some((r, _))) = (
self.types.iter().find(|(t, _)| t.name() == &l[..]), self.types.iter().find(|(t, _)| t.name() == &l[..]),
self.types.iter().find(|(t, _)| t.name() == &r[..]), self.types.iter().find(|(t, _)| t.name() == &r[..]),
) { ) {
return self.structural_supertype_of(l, r, bounds, None) return self.structural_supertype_of(l, r, bounds)
|| self.structural_subtype_of(l, r, bounds, lhs_variance); || self.structural_subtype_of(l, r, bounds);
} }
} }
(TyParam::MonoQVar(name), other) | (other, TyParam::MonoQVar(name)) => { (TyParam::MonoQVar(name), other) | (other, TyParam::MonoQVar(name)) => {
if let Some(bs) = bounds { if let Some(bs) = bounds {
if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(name)) { if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(name)) {
let other_t = self.type_of(other, bounds); let other_t = self.type_of(other, bounds);
return self.structural_supertype_of( return self.structural_supertype_of(bound.t(), &other_t, bounds);
bound.t(),
&other_t,
bounds,
lhs_variance,
);
} else { } else {
todo!() todo!()
} // subtyping } // subtyping
@ -3328,15 +3327,15 @@ impl Context {
&& largs && largs
.iter() .iter()
.zip(rargs.iter()) .zip(rargs.iter())
.all(|(l, r)| self.eq_tp(l, r, bounds, lhs_variance)) .all(|(l, r)| self.eq_tp(l, r, bounds))
} }
(TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv)) => match &*fv.borrow() { (TyParam::FreeVar(fv), other) | (other, TyParam::FreeVar(fv)) => match &*fv.borrow() {
FreeKind::Linked(tp) => return self.eq_tp(tp, other, bounds, lhs_variance), FreeKind::Linked(tp) => return self.eq_tp(tp, other, bounds),
FreeKind::Unbound { constraint, .. } FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } => { | FreeKind::NamedUnbound { constraint, .. } => {
let t = constraint.typ().unwrap(); let t = constraint.typ().unwrap();
let other_t = self.type_of(other, bounds); let other_t = self.type_of(other, bounds);
return self.structural_supertype_of(t, &other_t, bounds, lhs_variance); return self.structural_supertype_of(t, &other_t, bounds);
} }
}, },
(l, r) if l == r => return true, (l, r) if l == r => return true,
@ -3379,11 +3378,11 @@ impl Context {
} }
fn supertype_of(&self, lhs: &Type, rhs: &Type) -> bool { fn supertype_of(&self, lhs: &Type, rhs: &Type) -> bool {
self.structural_supertype_of(lhs, rhs, None, None) || self.nominal_supertype_of(lhs, rhs) self.structural_supertype_of(lhs, rhs, None) || self.nominal_supertype_of(lhs, rhs)
} }
fn subtype_of(&self, lhs: &Type, rhs: &Type) -> bool { fn subtype_of(&self, lhs: &Type, rhs: &Type) -> bool {
self.structural_subtype_of(lhs, rhs, None, None) || self.nominal_subtype_of(lhs, rhs) self.structural_subtype_of(lhs, rhs, None) || self.nominal_subtype_of(lhs, rhs)
} }
/// make judgments that include supertypes in the same namespace & take into account glue patches /// make judgments that include supertypes in the same namespace & take into account glue patches
@ -3400,12 +3399,11 @@ impl Context {
r_bounds r_bounds
} }
}; };
let variance = rhs_ctx.type_params_variance();
if rhs_ctx if rhs_ctx
.super_classes .super_classes
.iter() .iter()
.chain(rhs_ctx.super_traits.iter()) .chain(rhs_ctx.super_traits.iter())
.any(|sup| self.structural_supertype_of(lhs, sup, Some(&bounds), Some(&variance))) .any(|sup| self.structural_supertype_of(lhs, sup, Some(&bounds)))
{ {
return true; return true;
} }
@ -3415,13 +3413,12 @@ impl Context {
.rec_get_patch(patch_name) .rec_get_patch(patch_name)
.unwrap_or_else(|| panic!("{patch_name} not found")); .unwrap_or_else(|| panic!("{patch_name} not found"));
let bounds = patch.type_params_bounds(); let bounds = patch.type_params_bounds();
let variance = patch.type_params_variance();
// e.g. // e.g.
// P = Patch X, Impl: Ord // P = Patch X, Impl: Ord
// Rhs <: X => Rhs <: Ord // Rhs <: X => Rhs <: Ord
// Ord <: Lhs => Rhs <: Ord <: Lhs // Ord <: Lhs => Rhs <: Ord <: Lhs
if self.structural_supertype_of(sub_type, rhs, Some(&bounds), Some(&variance)) if self.structural_supertype_of(sub_type, rhs, Some(&bounds))
&& self.structural_subtype_of(sup_trait, lhs, Some(&bounds), Some(&variance)) && self.structural_subtype_of(sup_trait, lhs, Some(&bounds))
{ {
return true; return true;
} }
@ -3447,7 +3444,6 @@ impl Context {
lhs: &Type, lhs: &Type,
rhs: &Type, rhs: &Type,
bounds: Option<&Set<TyBound>>, bounds: Option<&Set<TyBound>>,
lhs_variance: Option<&Vec<Variance>>,
) -> bool { ) -> bool {
if lhs.rec_eq(rhs) { if lhs.rec_eq(rhs) {
return true; return true;
@ -3517,26 +3513,24 @@ impl Context {
// (Object) -> Int <: (Int) -> Int <: (Never) -> Int // (Object) -> Int <: (Int) -> Int <: (Never) -> Int
ls.non_default_params.len() == rs.non_default_params.len() ls.non_default_params.len() == rs.non_default_params.len()
&& ls.default_params.len() == rs.default_params.len() && ls.default_params.len() == rs.default_params.len()
&& self.structural_supertype_of(&ls.return_t, &rs.return_t, bounds, lhs_variance) // covariant && self.structural_supertype_of(&ls.return_t, &rs.return_t, bounds) // covariant
&& ls.non_default_params.iter() && ls.non_default_params.iter()
.zip(rs.non_default_params.iter()) .zip(rs.non_default_params.iter())
.all(|(l, r)| self.structural_subtype_of(&l.ty, &r.ty, bounds, lhs_variance)) .all(|(l, r)| self.structural_subtype_of(&l.ty, &r.ty, bounds))
&& ls.default_params.iter() && ls.default_params.iter()
.zip(rs.default_params.iter()) .zip(rs.default_params.iter())
.all(|(l, r)| self.structural_subtype_of(&l.ty, &r.ty, bounds, lhs_variance)) .all(|(l, r)| self.structural_subtype_of(&l.ty, &r.ty, bounds))
// contravariant // contravariant
} }
// RefMut, OptionMut are invariant // RefMut, OptionMut are invariant
(Ref(lhs), Ref(rhs)) | (VarArgs(lhs), VarArgs(rhs)) => { (Ref(lhs), Ref(rhs)) | (VarArgs(lhs), VarArgs(rhs)) => {
self.structural_supertype_of(lhs, rhs, bounds, lhs_variance) self.structural_supertype_of(lhs, rhs, bounds)
} }
// true if it can be a supertype, false if it cannot (due to type constraints) // true if it can be a supertype, false if it cannot (due to type constraints)
// No type constraints are imposed here, as subsequent type decisions are made according to the possibilities // No type constraints are imposed here, as subsequent type decisions are made according to the possibilities
(FreeVar(v), rhs) => { (FreeVar(v), rhs) => {
match &*v.borrow() { match &*v.borrow() {
FreeKind::Linked(t) => { FreeKind::Linked(t) => self.structural_supertype_of(t, rhs, bounds),
self.structural_supertype_of(t, rhs, bounds, lhs_variance)
}
FreeKind::Unbound { constraint, .. } FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } => match constraint { | FreeKind::NamedUnbound { constraint, .. } => match constraint {
// `(?T <: Int) :> Nat` can be true, `(?T <: Nat) :> Int` is false // `(?T <: Int) :> Nat` can be true, `(?T <: Nat) :> Int` is false
@ -3544,13 +3538,13 @@ impl Context {
// `(?T :> Str) :> Int` is true (?T :> Str or Int) // `(?T :> Str) :> Int` is true (?T :> Str or Int)
// `(Nat <: ?T <: Ratio) :> Nat` can be true // `(Nat <: ?T <: Ratio) :> Nat` can be true
Constraint::Sandwiched { sup, .. } => { Constraint::Sandwiched { sup, .. } => {
self.structural_supertype_of(sup, rhs, bounds, lhs_variance) self.structural_supertype_of(sup, rhs, bounds)
} }
// (?v: Type, rhs): OK // (?v: Type, rhs): OK
// (?v: Nat, rhs): Something wrong // (?v: Nat, rhs): Something wrong
// Class <: Type, but Nat <!: Type (Nat: Type) // Class <: Type, but Nat <!: Type (Nat: Type)
Constraint::TypeOf(t) => { Constraint::TypeOf(t) => {
if self.structural_supertype_of(&Type, t, bounds, lhs_variance) { if self.structural_supertype_of(&Type, t, bounds) {
true true
} else { } else {
panic!() panic!()
@ -3562,9 +3556,7 @@ impl Context {
} }
(lhs, FreeVar(fv)) => { (lhs, FreeVar(fv)) => {
match &*fv.borrow() { match &*fv.borrow() {
FreeKind::Linked(t) => { FreeKind::Linked(t) => self.structural_supertype_of(lhs, t, bounds),
self.structural_supertype_of(lhs, t, bounds, lhs_variance)
}
FreeKind::Unbound { constraint, .. } FreeKind::Unbound { constraint, .. }
| FreeKind::NamedUnbound { constraint, .. } => match constraint { | FreeKind::NamedUnbound { constraint, .. } => match constraint {
// ?T cannot be `Never` // ?T cannot be `Never`
@ -3574,10 +3566,10 @@ impl Context {
// `Int :> (?T :> Nat)` can be true, `Nat :> (?T :> Int)` is false // `Int :> (?T :> Nat)` can be true, `Nat :> (?T :> Int)` is false
// `Int :> (Nat <: ?T <: Ratio)` can be true, `Nat :> (Int <: ?T <: Ratio)` is false // `Int :> (Nat <: ?T <: Ratio)` can be true, `Nat :> (Int <: ?T <: Ratio)` is false
Constraint::Sandwiched { sub, sup: _ } => { Constraint::Sandwiched { sub, sup: _ } => {
self.structural_supertype_of(lhs, sub, bounds, lhs_variance) self.structural_supertype_of(lhs, sub, bounds)
} }
Constraint::TypeOf(t) => { Constraint::TypeOf(t) => {
if self.structural_supertype_of(&Type, t, bounds, lhs_variance) { if self.structural_supertype_of(&Type, t, bounds) {
true true
} else { } else {
panic!() panic!()
@ -3589,7 +3581,7 @@ impl Context {
} }
(Type, Record(rec)) => { (Type, Record(rec)) => {
for (_, t) in rec.iter() { for (_, t) in rec.iter() {
if !self.structural_supertype_of(&Type, t, bounds, lhs_variance) { if !self.structural_supertype_of(&Type, t, bounds) {
return false; return false;
} }
} }
@ -3602,7 +3594,7 @@ impl Context {
// ({I: Int | I >= 0} :> {N: Nat | N >= 1}) == true, // ({I: Int | I >= 0} :> {N: Nat | N >= 1}) == true,
// ({I: Int | I > 1 or I < -1} :> {I: Int | I >= 0}) == false, // ({I: Int | I > 1 or I < -1} :> {I: Int | I >= 0}) == false,
(Refinement(l), Refinement(r)) => { (Refinement(l), Refinement(r)) => {
if !self.structural_supertype_of(&l.t, &r.t, bounds, lhs_variance) { if !self.structural_supertype_of(&l.t, &r.t, bounds) {
return false; return false;
} }
let mut r_preds_clone = r.preds.clone(); let mut r_preds_clone = r.preds.clone();
@ -3620,16 +3612,16 @@ impl Context {
} }
(Nat, re @ Refinement(_)) => { (Nat, re @ Refinement(_)) => {
let nat = Type::Refinement(self.into_refinement(Nat)); let nat = Type::Refinement(self.into_refinement(Nat));
self.structural_supertype_of(&nat, re, bounds, lhs_variance) self.structural_supertype_of(&nat, re, bounds)
} }
(re @ Refinement(_), Nat) => { (re @ Refinement(_), Nat) => {
let nat = Type::Refinement(self.into_refinement(Nat)); let nat = Type::Refinement(self.into_refinement(Nat));
self.structural_supertype_of(re, &nat, bounds, lhs_variance) self.structural_supertype_of(re, &nat, bounds)
} }
// Int :> {I: Int | ...} == true // Int :> {I: Int | ...} == true
// Real :> {I: Int | ...} == false // Real :> {I: Int | ...} == false
// Int :> {I: Str| ...} == false // Int :> {I: Str| ...} == false
(l, Refinement(r)) => self.structural_supertype_of(l, &r.t, bounds, lhs_variance), (l, Refinement(r)) => self.structural_supertype_of(l, &r.t, bounds),
// ({I: Int | True} :> Int) == true, ({N: Nat | ...} :> Int) == false, ({I: Int | I >= 0} :> Int) == false // ({I: Int | True} :> Int) == true, ({N: Nat | ...} :> Int) == false, ({I: Int | I >= 0} :> Int) == false
(Refinement(l), r) => { (Refinement(l), r) => {
if l.preds if l.preds
@ -3638,7 +3630,7 @@ impl Context {
{ {
return false; return false;
} }
self.structural_supertype_of(&l.t, r, bounds, lhs_variance) self.structural_supertype_of(&l.t, r, bounds)
} }
(Quantified(l), Quantified(r)) => { (Quantified(l), Quantified(r)) => {
// REVIEW: maybe this should be `unreachable` // REVIEW: maybe this should be `unreachable`
@ -3650,7 +3642,6 @@ impl Context {
l.unbound_callable.as_ref(), l.unbound_callable.as_ref(),
r.unbound_callable.as_ref(), r.unbound_callable.as_ref(),
Some(&l.bounds), Some(&l.bounds),
lhs_variance,
) )
} }
} }
@ -3659,25 +3650,18 @@ impl Context {
if bounds.is_some() { if bounds.is_some() {
panic!("Nested quantification") panic!("Nested quantification")
} else { } else {
self.structural_supertype_of( self.structural_supertype_of(q.unbound_callable.as_ref(), r, Some(&q.bounds))
q.unbound_callable.as_ref(),
r,
Some(&q.bounds),
lhs_variance,
)
} }
} }
(lhs, Or(tys)) => tys (lhs, Or(tys)) => tys
.iter() .iter()
.all(|t| self.structural_supertype_of(lhs, t, bounds, lhs_variance)), .all(|t| self.structural_supertype_of(lhs, t, bounds)),
(And(tys), rhs) => tys (And(tys), rhs) => tys
.iter() .iter()
.all(|t| self.structural_supertype_of(t, rhs, bounds, lhs_variance)), .all(|t| self.structural_supertype_of(t, rhs, bounds)),
(VarArgs(lhs), rhs) => self.structural_supertype_of(lhs, rhs, bounds, lhs_variance), (VarArgs(lhs), rhs) => self.structural_supertype_of(lhs, rhs, bounds),
// TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ // TはすべてのRef(T)のメソッドを持つので、Ref(T)のサブタイプ
(Ref(lhs), rhs) | (RefMut(lhs), rhs) => { (Ref(lhs), rhs) | (RefMut(lhs), rhs) => self.structural_supertype_of(lhs, rhs, bounds),
self.structural_supertype_of(lhs, rhs, bounds, lhs_variance)
}
( (
Poly { Poly {
name: ln, name: ln,
@ -3688,42 +3672,35 @@ impl Context {
params: rps, params: rps,
}, },
) => { ) => {
if let Some(lhs_variance) = lhs_variance { if ln != rn || lps.len() != rps.len() {
ln == rn return false;
&& lps.len() == rps.len() }
&& lps.iter().zip(rps.iter()).zip(lhs_variance.iter()).all( let variances = self
|((lp, rp), variance)| match (lp, rp, variance) { .rec_type_ctx_by_name(ln)
.unwrap_or_else(|| panic!("{ln} is not found"))
.type_params_variance();
debug_assert_eq!(lps.len(), variances.len());
lps.iter()
.zip(rps.iter())
.zip(variances.iter())
.all(|((lp, rp), variance)| match (lp, rp, variance) {
(TyParam::Type(l), TyParam::Type(r), Variance::Contravariant) => { (TyParam::Type(l), TyParam::Type(r), Variance::Contravariant) => {
self.structural_subtype_of(l, r, bounds, Some(lhs_variance)) self.structural_subtype_of(l, r, bounds)
} }
(TyParam::Type(l), TyParam::Type(r), Variance::Covariant) => { (TyParam::Type(l), TyParam::Type(r), Variance::Covariant) => {
log!("{l}, {r}"); // if matches!(r.as_ref(), &Type::Refinement(_)) { log!("{l}, {r}, {}", self.structural_supertype_of(l, r, bounds, Some(lhs_variance))); }
self.structural_supertype_of(l, r, bounds, Some(lhs_variance)) self.structural_supertype_of(l, r, bounds)
} }
// Invariant // Invariant
_ => self.eq_tp(lp, rp, bounds, Some(lhs_variance)), _ => self.eq_tp(lp, rp, bounds),
}, })
)
} else {
ln == rn
&& lps.len() == rps.len()
&& lps
.iter()
.zip(rps.iter())
.all(|(l, r)| self.eq_tp(l, r, bounds, None))
}
} }
(MonoQVar(name), r) => { (MonoQVar(name), r) => {
if let Some(bs) = bounds { if let Some(bs) = bounds {
if let Some(bound) = bs.iter().find(|b| b.mentions_as_subtype(name)) { if let Some(bound) = bs.iter().find(|b| b.mentions_as_subtype(name)) {
self.structural_supertype_of(bound.t(), r, bounds, lhs_variance) self.structural_supertype_of(bound.t(), r, bounds)
} else if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(name)) { } else if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(name)) {
if self.structural_same_type_of( if self.structural_same_type_of(bound.t(), &Type::Type, bounds) {
bound.t(),
&Type::Type,
bounds,
lhs_variance,
) {
true true
} else { } else {
todo!() todo!()
@ -3739,14 +3716,9 @@ impl Context {
(l, MonoQVar(name)) => { (l, MonoQVar(name)) => {
if let Some(bs) = bounds { if let Some(bs) = bounds {
if let Some(bound) = bs.iter().find(|b| b.mentions_as_subtype(name)) { if let Some(bound) = bs.iter().find(|b| b.mentions_as_subtype(name)) {
self.structural_supertype_of(l, bound.t(), bounds, lhs_variance) self.structural_supertype_of(l, bound.t(), bounds)
} else if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(name)) { } else if let Some(bound) = bs.iter().find(|b| b.mentions_as_instance(name)) {
if self.structural_same_type_of( if self.structural_same_type_of(bound.t(), &Type::Type, bounds) {
bound.t(),
&Type::Type,
bounds,
lhs_variance,
) {
true true
} else { } else {
todo!() todo!()
@ -3771,9 +3743,8 @@ impl Context {
lhs: &Type, lhs: &Type,
rhs: &Type, rhs: &Type,
bounds: Option<&Set<TyBound>>, bounds: Option<&Set<TyBound>>,
lhs_variance: Option<&Vec<Variance>>,
) -> bool { ) -> bool {
self.structural_supertype_of(rhs, lhs, bounds, lhs_variance) self.structural_supertype_of(rhs, lhs, bounds)
} }
pub(crate) fn structural_same_type_of( pub(crate) fn structural_same_type_of(
@ -3781,10 +3752,9 @@ impl Context {
lhs: &Type, lhs: &Type,
rhs: &Type, rhs: &Type,
bounds: Option<&Set<TyBound>>, bounds: Option<&Set<TyBound>>,
lhs_variance: Option<&Vec<Variance>>,
) -> bool { ) -> bool {
self.structural_supertype_of(lhs, rhs, bounds, lhs_variance) self.structural_supertype_of(lhs, rhs, bounds)
&& self.structural_subtype_of(lhs, rhs, bounds, lhs_variance) && self.structural_subtype_of(lhs, rhs, bounds)
} }
fn rec_try_cmp( fn rec_try_cmp(
@ -3918,8 +3888,8 @@ impl Context {
} }
fn union_refinement(&self, lhs: &RefinementType, rhs: &RefinementType) -> RefinementType { fn union_refinement(&self, lhs: &RefinementType, rhs: &RefinementType) -> RefinementType {
if !self.structural_supertype_of(&lhs.t, &rhs.t, None, None) if !self.structural_supertype_of(&lhs.t, &rhs.t, None)
&& !self.structural_subtype_of(&lhs.t, &rhs.t, None, None) && !self.structural_subtype_of(&lhs.t, &rhs.t, None)
{ {
log!("{lhs}\n{rhs}"); log!("{lhs}\n{rhs}");
todo!() todo!()
@ -4492,8 +4462,7 @@ impl Context {
fn _just_type_ctxs<'a>(&'a self, t: &'a Type) -> Option<(&'a Type, &'a Context)> { fn _just_type_ctxs<'a>(&'a self, t: &'a Type) -> Option<(&'a Type, &'a Context)> {
self.types.iter().find(move |(maybe_sup, ctx)| { self.types.iter().find(move |(maybe_sup, ctx)| {
let bounds = ctx.type_params_bounds(); let bounds = ctx.type_params_bounds();
let variance = ctx.type_params_variance(); self.structural_same_type_of(maybe_sup, t, Some(&bounds))
self.structural_same_type_of(maybe_sup, t, Some(&bounds), Some(&variance))
}) })
} }
@ -4501,8 +4470,7 @@ impl Context {
fn _sup_type_ctxs<'a>(&'a self, t: &'a Type) -> impl Iterator<Item = (&'a Type, &'a Context)> { fn _sup_type_ctxs<'a>(&'a self, t: &'a Type) -> impl Iterator<Item = (&'a Type, &'a Context)> {
self.types.iter().filter_map(move |(maybe_sup, ctx)| { self.types.iter().filter_map(move |(maybe_sup, ctx)| {
let bounds = ctx.type_params_bounds(); let bounds = ctx.type_params_bounds();
let variance = ctx.type_params_variance(); if self.structural_supertype_of(maybe_sup, t, Some(&bounds)) {
if self.structural_supertype_of(maybe_sup, t, Some(&bounds), Some(&variance)) {
Some((maybe_sup, ctx)) Some((maybe_sup, ctx))
} else { } else {
None None

View file

@ -246,7 +246,7 @@ pub struct Local {
pub name: Token, pub name: Token,
/// オブジェクト自身の名前 /// オブジェクト自身の名前
__name__: Option<Str>, __name__: Option<Str>,
t: Type, pub(crate) t: Type,
} }
impl NestedDisplay for Local { impl NestedDisplay for Local {

View file

@ -133,7 +133,12 @@ impl Context {
// Erg does not have a trait equivalent to `PartialEq` in Rust // Erg does not have a trait equivalent to `PartialEq` in Rust
// This means, Erg's `Float` cannot be compared with other `Float` // This means, Erg's `Float` cannot be compared with other `Float`
// use `l - r < EPSILON` to check if two floats are almost equal // use `l - r < EPSILON` to check if two floats are almost equal
let mut eq = Self::poly_trait("Eq", vec![PS::t("R", WithDefault)], vec![], Self::TOP_LEVEL); let mut eq = Self::poly_trait(
"Eq",
vec![PS::t("R", WithDefault)],
vec![poly("Output", vec![ty_tp(mono_q("R"))])],
Self::TOP_LEVEL,
);
// __eq__: |Self <: Eq()| Self.(Self) -> Bool // __eq__: |Self <: Eq()| Self.(Self) -> Bool
let op_t = fn1_met(mono_q("Self"), mono_q("R"), Bool); let op_t = fn1_met(mono_q("Self"), mono_q("R"), Bool);
let op_t = quant( let op_t = quant(
@ -194,7 +199,7 @@ impl Context {
let mut add = Self::poly_trait( let mut add = Self::poly_trait(
"Add", "Add",
params.clone(), params.clone(),
vec![poly("Output", vec![ty_tp(mono_q("R"))])], vec![poly("Output", vec![ty_tp(mono_q("R"))])], // Rについて共変(__add__の型とは関係ない)
Self::TOP_LEVEL, Self::TOP_LEVEL,
); );
let self_bound = subtypeof(mono_q("Self"), poly("Add", ty_params.clone())); let self_bound = subtypeof(mono_q("Self"), poly("Add", ty_params.clone()));