mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 12:51:10 +00:00
Fix a refinement + union types bug
This commit is contained in:
parent
188f8ad965
commit
6cb3231845
12 changed files with 144 additions and 101 deletions
|
@ -262,7 +262,7 @@ impl Context {
|
||||||
if !self.is_class(lhs) || !self.is_class(rhs) {
|
if !self.is_class(lhs) || !self.is_class(rhs) {
|
||||||
return (Maybe, false);
|
return (Maybe, false);
|
||||||
}
|
}
|
||||||
if let Some(ty_ctx) = self.get_nominal_type_ctx(rhs) {
|
if let Some((_, ty_ctx)) = self.get_nominal_type_ctx(rhs) {
|
||||||
for rhs_sup in ty_ctx.super_classes.iter() {
|
for rhs_sup in ty_ctx.super_classes.iter() {
|
||||||
let rhs_sup = if rhs_sup.has_qvar() {
|
let rhs_sup = if rhs_sup.has_qvar() {
|
||||||
let rhs = match rhs {
|
let rhs = match rhs {
|
||||||
|
@ -300,7 +300,7 @@ impl Context {
|
||||||
if !self.is_trait(lhs) {
|
if !self.is_trait(lhs) {
|
||||||
return (Maybe, false);
|
return (Maybe, false);
|
||||||
}
|
}
|
||||||
if let Some(rhs_ctx) = self.get_nominal_type_ctx(rhs) {
|
if let Some((_, rhs_ctx)) = self.get_nominal_type_ctx(rhs) {
|
||||||
for rhs_sup in rhs_ctx.super_traits.iter() {
|
for rhs_sup in rhs_ctx.super_traits.iter() {
|
||||||
// Not `supertype_of` (only structures are compared)
|
// Not `supertype_of` (only structures are compared)
|
||||||
match self.cheap_supertype_of(lhs, rhs_sup) {
|
match self.cheap_supertype_of(lhs, rhs_sup) {
|
||||||
|
@ -644,7 +644,7 @@ impl Context {
|
||||||
erg_common::fmt_vec(lparams),
|
erg_common::fmt_vec(lparams),
|
||||||
erg_common::fmt_vec(rparams)
|
erg_common::fmt_vec(rparams)
|
||||||
);
|
);
|
||||||
let ctx = self
|
let (_, ctx) = self
|
||||||
.get_nominal_type_ctx(typ)
|
.get_nominal_type_ctx(typ)
|
||||||
.unwrap_or_else(|| panic!("{typ} is not found"));
|
.unwrap_or_else(|| panic!("{typ} is not found"));
|
||||||
let variances = ctx.type_params_variance();
|
let variances = ctx.type_params_variance();
|
||||||
|
@ -846,9 +846,13 @@ impl Context {
|
||||||
}
|
}
|
||||||
(Refinement(l), Refinement(r)) => Type::Refinement(self.union_refinement(l, r)),
|
(Refinement(l), Refinement(r)) => Type::Refinement(self.union_refinement(l, r)),
|
||||||
(t, Type::Never) | (Type::Never, t) => t.clone(),
|
(t, Type::Never) | (Type::Never, t) => t.clone(),
|
||||||
(t, Refinement(r)) | (Refinement(r), t) => {
|
// ?T or {"b"} cannot be {I: (?T or Str) | I == "b"} because ?T may be {"a"} etc.
|
||||||
let t = self.into_refinement(t.clone());
|
// (if so, {I: ?T or Str | I == "b"} == {I: {"a"} or Str | I == "b"} == {I: Str | I == "b"})
|
||||||
Type::Refinement(self.union_refinement(&t, r))
|
(other, Refinement(refine)) | (Refinement(refine), other)
|
||||||
|
if !other.is_unbound_var() =>
|
||||||
|
{
|
||||||
|
let other = self.into_refinement(other.clone());
|
||||||
|
Type::Refinement(self.union_refinement(&other, refine))
|
||||||
}
|
}
|
||||||
// Array({1, 2}, 2), Array({3, 4}, 2) ==> Array({1, 2, 3, 4}, 2)
|
// Array({1, 2}, 2), Array({3, 4}, 2) ==> Array({1, 2, 3, 4}, 2)
|
||||||
(
|
(
|
||||||
|
|
|
@ -21,7 +21,7 @@ enum Sequence {
|
||||||
|
|
||||||
// TODO: these should not be in Context
|
// TODO: these should not be in Context
|
||||||
impl Context {
|
impl Context {
|
||||||
fn readable_type(typ: &Type) -> Type {
|
pub(crate) fn readable_type(typ: &Type) -> Type {
|
||||||
match typ {
|
match typ {
|
||||||
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
|
Type::FreeVar(fv) if fv.constraint_is_sandwiched() => {
|
||||||
let (sub, sup) = fv.get_subsup().unwrap();
|
let (sub, sup) = fv.get_subsup().unwrap();
|
||||||
|
|
|
@ -551,7 +551,7 @@ impl Context {
|
||||||
self.get_attr_info_from_attributive(&fv.crack(), ident, namespace)
|
self.get_attr_info_from_attributive(&fv.crack(), ident, namespace)
|
||||||
}
|
}
|
||||||
Type::FreeVar(fv) => {
|
Type::FreeVar(fv) => {
|
||||||
let sup = fv.get_sup().unwrap();
|
let sup = fv.get_super().unwrap();
|
||||||
self.get_attr_info_from_attributive(&sup, ident, namespace)
|
self.get_attr_info_from_attributive(&sup, ident, namespace)
|
||||||
}
|
}
|
||||||
Type::Ref(t) => self.get_attr_info_from_attributive(t, ident, namespace),
|
Type::Ref(t) => self.get_attr_info_from_attributive(t, ident, namespace),
|
||||||
|
@ -1573,7 +1573,7 @@ impl Context {
|
||||||
match t {
|
match t {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => self.get_nominal_super_type_ctxs(&fv.crack()),
|
Type::FreeVar(fv) if fv.is_linked() => self.get_nominal_super_type_ctxs(&fv.crack()),
|
||||||
Type::FreeVar(fv) => {
|
Type::FreeVar(fv) => {
|
||||||
if let Some(sup) = fv.get_sup() {
|
if let Some(sup) = fv.get_super() {
|
||||||
self.get_nominal_super_type_ctxs(&sup)
|
self.get_nominal_super_type_ctxs(&sup)
|
||||||
} else {
|
} else {
|
||||||
self.get_nominal_super_type_ctxs(&Type)
|
self.get_nominal_super_type_ctxs(&Type)
|
||||||
|
@ -1614,7 +1614,7 @@ impl Context {
|
||||||
&'a self,
|
&'a self,
|
||||||
t: &Type,
|
t: &Type,
|
||||||
) -> Option<impl Iterator<Item = &'a Context>> {
|
) -> Option<impl Iterator<Item = &'a Context>> {
|
||||||
let ctx = self.get_nominal_type_ctx(t)?;
|
let (_, ctx) = self.get_nominal_type_ctx(t)?;
|
||||||
let sups = ctx
|
let sups = ctx
|
||||||
.super_classes
|
.super_classes
|
||||||
.iter()
|
.iter()
|
||||||
|
@ -1622,18 +1622,19 @@ impl Context {
|
||||||
.map(|sup| {
|
.map(|sup| {
|
||||||
self.get_nominal_type_ctx(sup)
|
self.get_nominal_type_ctx(sup)
|
||||||
.unwrap_or_else(|| todo!("compiler bug: {sup} not found"))
|
.unwrap_or_else(|| todo!("compiler bug: {sup} not found"))
|
||||||
|
.1
|
||||||
});
|
});
|
||||||
Some(vec![ctx].into_iter().chain(sups))
|
Some(vec![ctx].into_iter().chain(sups))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn _get_super_traits(&self, typ: &Type) -> Option<impl Iterator<Item = Type>> {
|
pub(crate) fn _get_super_traits(&self, typ: &Type) -> Option<impl Iterator<Item = Type>> {
|
||||||
self.get_nominal_type_ctx(typ)
|
self.get_nominal_type_ctx(typ)
|
||||||
.map(|ctx| ctx.super_traits.clone().into_iter())
|
.map(|(_, ctx)| ctx.super_traits.clone().into_iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// if `typ` is a refinement type, include the base type (refine.t)
|
/// 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>> {
|
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(|(_, ctx)| {
|
||||||
let super_classes = ctx.super_classes.clone();
|
let super_classes = ctx.super_classes.clone();
|
||||||
let derefined = typ.derefine();
|
let derefined = typ.derefine();
|
||||||
if typ != &derefined {
|
if typ != &derefined {
|
||||||
|
@ -1645,7 +1646,10 @@ impl Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Never
|
// TODO: Never
|
||||||
pub(crate) fn get_nominal_type_ctx<'a>(&'a self, typ: &Type) -> Option<&'a Context> {
|
pub(crate) fn get_nominal_type_ctx<'a>(
|
||||||
|
&'a self,
|
||||||
|
typ: &Type,
|
||||||
|
) -> Option<(&'a Type, &'a Context)> {
|
||||||
match typ {
|
match typ {
|
||||||
Type::FreeVar(fv) if fv.is_linked() => {
|
Type::FreeVar(fv) if fv.is_linked() => {
|
||||||
if let Some(res) = self.get_nominal_type_ctx(&fv.crack()) {
|
if let Some(res) = self.get_nominal_type_ctx(&fv.crack()) {
|
||||||
|
@ -1653,7 +1657,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::FreeVar(fv) => {
|
Type::FreeVar(fv) => {
|
||||||
let sup = fv.get_sup().unwrap();
|
let sup = fv.get_super().unwrap();
|
||||||
if let Some(res) = self.get_nominal_type_ctx(&sup) {
|
if let Some(res) = self.get_nominal_type_ctx(&sup) {
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
|
@ -1664,37 +1668,37 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Quantified(_) => {
|
Type::Quantified(_) => {
|
||||||
if let Some((_t, ctx)) = self
|
if let Some((t, ctx)) = self
|
||||||
.get_builtins()
|
.get_builtins()
|
||||||
.unwrap_or(self)
|
.unwrap_or(self)
|
||||||
.rec_get_mono_type("QuantifiedFunc")
|
.rec_get_mono_type("QuantifiedFunc")
|
||||||
{
|
{
|
||||||
return Some(ctx);
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Subr(subr) => match subr.kind {
|
Type::Subr(subr) => match subr.kind {
|
||||||
SubrKind::Func => {
|
SubrKind::Func => {
|
||||||
if let Some((_, ctx)) = self
|
if let Some((t, ctx)) = self
|
||||||
.get_builtins()
|
.get_builtins()
|
||||||
.unwrap_or(self)
|
.unwrap_or(self)
|
||||||
.rec_get_mono_type("Func")
|
.rec_get_mono_type("Func")
|
||||||
{
|
{
|
||||||
return Some(ctx);
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SubrKind::Proc => {
|
SubrKind::Proc => {
|
||||||
if let Some((_, ctx)) = self
|
if let Some((t, ctx)) = self
|
||||||
.get_builtins()
|
.get_builtins()
|
||||||
.unwrap_or(self)
|
.unwrap_or(self)
|
||||||
.rec_get_mono_type("Proc")
|
.rec_get_mono_type("Proc")
|
||||||
{
|
{
|
||||||
return Some(ctx);
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Type::Mono(name) => {
|
Type::Mono(name) => {
|
||||||
if let Some((_, ctx)) = self.rec_get_mono_type(&typ.local_name()) {
|
if let Some((t, ctx)) = self.rec_get_mono_type(&typ.local_name()) {
|
||||||
return Some(ctx);
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
// e.g. http.client.Response -> http.client
|
// e.g. http.client.Response -> http.client
|
||||||
let mut namespaces = name.split_with(&[".", "::"]);
|
let mut namespaces = name.split_with(&[".", "::"]);
|
||||||
|
@ -1717,14 +1721,14 @@ impl Context {
|
||||||
.and_then(|cache| cache.ref_ctx(path.as_path()))
|
.and_then(|cache| cache.ref_ctx(path.as_path()))
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
if let Some((_, ctx)) = ctx.rec_get_mono_type(type_name) {
|
if let Some((t, ctx)) = ctx.rec_get_mono_type(type_name) {
|
||||||
return Some(ctx);
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Poly { name, .. } => {
|
Type::Poly { name, .. } => {
|
||||||
if let Some((_, ctx)) = self.rec_get_poly_type(&typ.local_name()) {
|
if let Some((t, ctx)) = self.rec_get_poly_type(&typ.local_name()) {
|
||||||
return Some(ctx);
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
// NOTE: This needs to be changed if we want to be able to define classes/traits outside of the top level
|
// NOTE: This needs to be changed if we want to be able to define classes/traits outside of the top level
|
||||||
let mut namespaces = name.split_with(&[".", "::"]);
|
let mut namespaces = name.split_with(&[".", "::"]);
|
||||||
|
@ -1747,8 +1751,8 @@ impl Context {
|
||||||
.and_then(|cache| cache.ref_ctx(path.as_path()))
|
.and_then(|cache| cache.ref_ctx(path.as_path()))
|
||||||
})
|
})
|
||||||
{
|
{
|
||||||
if let Some((_, ctx)) = ctx.rec_get_poly_type(type_name) {
|
if let Some((t, ctx)) = ctx.rec_get_poly_type(type_name) {
|
||||||
return Some(ctx);
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1756,15 +1760,13 @@ impl Context {
|
||||||
return self
|
return self
|
||||||
.get_builtins()
|
.get_builtins()
|
||||||
.unwrap_or(self)
|
.unwrap_or(self)
|
||||||
.rec_get_mono_type("RecordType")
|
.rec_get_mono_type("RecordType");
|
||||||
.map(|(_, ctx)| ctx);
|
|
||||||
}
|
}
|
||||||
Type::Record(_) => {
|
Type::Record(_) => {
|
||||||
return self
|
return self
|
||||||
.get_builtins()
|
.get_builtins()
|
||||||
.unwrap_or(self)
|
.unwrap_or(self)
|
||||||
.rec_get_mono_type("Record")
|
.rec_get_mono_type("Record");
|
||||||
.map(|(_, ctx)| ctx);
|
|
||||||
}
|
}
|
||||||
Type::Or(_l, _r) => {
|
Type::Or(_l, _r) => {
|
||||||
if let Some(ctx) = self.get_nominal_type_ctx(&poly("Or", vec![])) {
|
if let Some(ctx) = self.get_nominal_type_ctx(&poly("Or", vec![])) {
|
||||||
|
@ -1773,8 +1775,8 @@ impl Context {
|
||||||
}
|
}
|
||||||
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
|
// FIXME: `F()`などの場合、実際は引数が省略されていてもmonomorphicになる
|
||||||
other if other.is_monomorphic() => {
|
other if other.is_monomorphic() => {
|
||||||
if let Some((_t, ctx)) = self.rec_get_mono_type(&other.local_name()) {
|
if let Some((t, ctx)) = self.rec_get_mono_type(&other.local_name()) {
|
||||||
return Some(ctx);
|
return Some((t, ctx));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::Ref(t) | Type::RefMut { before: t, .. } => {
|
Type::Ref(t) | Type::RefMut { before: t, .. } => {
|
||||||
|
@ -1801,7 +1803,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Type::FreeVar(fv) => {
|
Type::FreeVar(fv) => {
|
||||||
let sup = fv.get_sup().unwrap();
|
let sup = fv.get_super().unwrap();
|
||||||
if let Some(res) = self.get_mut_nominal_type_ctx(&sup) {
|
if let Some(res) = self.get_mut_nominal_type_ctx(&sup) {
|
||||||
return Some(res);
|
return Some(res);
|
||||||
}
|
}
|
||||||
|
@ -2184,7 +2186,7 @@ impl Context {
|
||||||
#[allow(clippy::single_match)]
|
#[allow(clippy::single_match)]
|
||||||
match lhs {
|
match lhs {
|
||||||
Type::FreeVar(fv) => {
|
Type::FreeVar(fv) => {
|
||||||
if let Some(sup) = fv.get_sup() {
|
if let Some(sup) = fv.get_super() {
|
||||||
let insts = self.get_trait_impls(&sup);
|
let insts = self.get_trait_impls(&sup);
|
||||||
let candidates = insts.into_iter().filter_map(move |inst| {
|
let candidates = insts.into_iter().filter_map(move |inst| {
|
||||||
if self.supertype_of(&inst.sup_trait, &sup) {
|
if self.supertype_of(&inst.sup_trait, &sup) {
|
||||||
|
@ -2220,7 +2222,7 @@ impl Context {
|
||||||
Type::Refinement(refine) => self.is_class(&refine.t),
|
Type::Refinement(refine) => self.is_class(&refine.t),
|
||||||
Type::Ref(t) | Type::RefMut { before: t, .. } => self.is_class(t),
|
Type::Ref(t) | Type::RefMut { before: t, .. } => self.is_class(t),
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(ctx) = self.get_nominal_type_ctx(typ) {
|
if let Some((_, ctx)) = self.get_nominal_type_ctx(typ) {
|
||||||
ctx.kind.is_class()
|
ctx.kind.is_class()
|
||||||
} else {
|
} else {
|
||||||
// TODO: unknown types
|
// TODO: unknown types
|
||||||
|
@ -2243,7 +2245,7 @@ impl Context {
|
||||||
Type::Refinement(refine) => self.is_trait(&refine.t),
|
Type::Refinement(refine) => self.is_trait(&refine.t),
|
||||||
Type::Ref(t) | Type::RefMut { before: t, .. } => self.is_trait(t),
|
Type::Ref(t) | Type::RefMut { before: t, .. } => self.is_trait(t),
|
||||||
_ => {
|
_ => {
|
||||||
if let Some(ctx) = self.get_nominal_type_ctx(typ) {
|
if let Some((_, ctx)) = self.get_nominal_type_ctx(typ) {
|
||||||
ctx.kind.is_trait()
|
ctx.kind.is_trait()
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
|
|
|
@ -416,7 +416,7 @@ impl ContextProvider for Context {
|
||||||
.chain(self.methods_list.iter().flat_map(|(_, ctx)| ctx.dir()))
|
.chain(self.methods_list.iter().flat_map(|(_, ctx)| ctx.dir()))
|
||||||
.collect();
|
.collect();
|
||||||
for sup in self.super_classes.iter() {
|
for sup in self.super_classes.iter() {
|
||||||
if let Some(sup_ctx) = self.get_nominal_type_ctx(sup) {
|
if let Some((_, sup_ctx)) = self.get_nominal_type_ctx(sup) {
|
||||||
vars.extend(sup_ctx.type_dir());
|
vars.extend(sup_ctx.type_dir());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -432,7 +432,7 @@ impl ContextProvider for Context {
|
||||||
self.get_mod(receiver_name)
|
self.get_mod(receiver_name)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
let (_, vi) = self.get_var_info(receiver_name)?;
|
let (_, vi) = self.get_var_info(receiver_name)?;
|
||||||
self.get_nominal_type_ctx(&vi.t)
|
self.get_nominal_type_ctx(&vi.t).map(|(_, ctx)| ctx)
|
||||||
})
|
})
|
||||||
.or_else(|| self.rec_get_type(receiver_name).map(|(_, ctx)| ctx))
|
.or_else(|| self.rec_get_type(receiver_name).map(|(_, ctx)| ctx))
|
||||||
}
|
}
|
||||||
|
|
|
@ -824,7 +824,7 @@ impl Context {
|
||||||
self.level,
|
self.level,
|
||||||
);
|
);
|
||||||
for sup in super_classes.into_iter() {
|
for sup in super_classes.into_iter() {
|
||||||
let sup_ctx = self
|
let (_, sup_ctx) = self
|
||||||
.get_nominal_type_ctx(&sup)
|
.get_nominal_type_ctx(&sup)
|
||||||
.unwrap_or_else(|| todo!("{sup} not found"));
|
.unwrap_or_else(|| todo!("{sup} not found"));
|
||||||
ctx.register_superclass(sup, sup_ctx);
|
ctx.register_superclass(sup, sup_ctx);
|
||||||
|
@ -942,7 +942,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for sup in super_classes.into_iter() {
|
for sup in super_classes.into_iter() {
|
||||||
let sup_ctx = self.get_nominal_type_ctx(&sup).unwrap();
|
let (_, sup_ctx) = self.get_nominal_type_ctx(&sup).unwrap();
|
||||||
ctx.register_supertrait(sup, sup_ctx);
|
ctx.register_supertrait(sup, sup_ctx);
|
||||||
}
|
}
|
||||||
self.register_gen_mono_type(ident, gen, ctx, Const);
|
self.register_gen_mono_type(ident, gen, ctx, Const);
|
||||||
|
|
|
@ -5,7 +5,9 @@ use std::option::Option;
|
||||||
use erg_common::error::Location;
|
use erg_common::error::Location;
|
||||||
use erg_common::traits::{Locational, Stream};
|
use erg_common::traits::{Locational, Stream};
|
||||||
use erg_common::Str;
|
use erg_common::Str;
|
||||||
use erg_common::{assume_unreachable, fn_name, log};
|
use erg_common::{assume_unreachable, fn_name};
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use erg_common::{fmt_vec, log};
|
||||||
|
|
||||||
use crate::ty::constructors::*;
|
use crate::ty::constructors::*;
|
||||||
use crate::ty::free::{Constraint, FreeKind, HasLevel};
|
use crate::ty::free::{Constraint, FreeKind, HasLevel};
|
||||||
|
@ -421,7 +423,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
Type::Poly { name, mut params } => {
|
Type::Poly { name, mut params } => {
|
||||||
let typ = poly(&name, params.clone());
|
let typ = poly(&name, params.clone());
|
||||||
let ctx = self.get_nominal_type_ctx(&typ).unwrap();
|
let (_, ctx) = self.get_nominal_type_ctx(&typ).unwrap();
|
||||||
let variances = ctx.type_params_variance();
|
let variances = ctx.type_params_variance();
|
||||||
for (param, variance) in params.iter_mut().zip(variances.into_iter()) {
|
for (param, variance) in params.iter_mut().zip(variances.into_iter()) {
|
||||||
*param = self.deref_tp(mem::take(param), variance, loc)?;
|
*param = self.deref_tp(mem::take(param), variance, loc)?;
|
||||||
|
@ -1504,55 +1506,65 @@ impl Context {
|
||||||
},
|
},
|
||||||
) => {
|
) => {
|
||||||
// e.g. Set(?T) <: Eq(Set(?T))
|
// e.g. Set(?T) <: Eq(Set(?T))
|
||||||
|
// Array(Str) <: Iterable(Str)
|
||||||
if ln != rn {
|
if ln != rn {
|
||||||
if let Some(sub_ctx) = self.get_nominal_type_ctx(maybe_sub) {
|
if let Some((sub_def_t, sub_ctx)) = self.get_nominal_type_ctx(maybe_sub) {
|
||||||
|
self.substitute_typarams(sub_def_t, maybe_sub);
|
||||||
for sup_trait in sub_ctx.super_traits.iter() {
|
for sup_trait in sub_ctx.super_traits.iter() {
|
||||||
if self.supertype_of(maybe_sup, sup_trait) {
|
if self.supertype_of(maybe_sup, sup_trait) {
|
||||||
for (l_maybe_sub, r_maybe_sup) in sup_trait.typarams().iter().zip(rps.iter()) {
|
for (l_maybe_sub, r_maybe_sup) in sup_trait.typarams().iter().zip(rps.iter()) {
|
||||||
self.sub_unify_tp(l_maybe_sub, r_maybe_sup, None, loc, false)?;
|
self.sub_unify_tp(l_maybe_sub, r_maybe_sup, None, loc, false)
|
||||||
|
.map_err(|e| { self.undo_substitute_typarams(sub_def_t); e })?;
|
||||||
}
|
}
|
||||||
|
self.undo_substitute_typarams(sub_def_t);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Err(TyCheckErrors::from(TyCheckError::unification_error(
|
Err(TyCheckErrors::from(TyCheckError::unification_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
maybe_sub,
|
maybe_sub,
|
||||||
maybe_sup,
|
maybe_sup,
|
||||||
loc,
|
loc,
|
||||||
self.caused_by(),
|
self.caused_by(),
|
||||||
)));
|
)))
|
||||||
}
|
} else {
|
||||||
for (l_maybe_sub, r_maybe_sup) in lps.iter().zip(rps.iter()) {
|
for (l_maybe_sub, r_maybe_sup) in lps.iter().zip(rps.iter()) {
|
||||||
self.sub_unify_tp(l_maybe_sub, r_maybe_sup, None, loc, false)?;
|
self.sub_unify_tp(l_maybe_sub, r_maybe_sup, None, loc, false)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
(Type::And(l, r), _)
|
|
||||||
| (Type::Or(l, r), _)
|
|
||||||
| (Type::Not(l, r), _) => {
|
|
||||||
self.sub_unify(l, maybe_sup, loc, param_name)?;
|
|
||||||
self.sub_unify(r, maybe_sup, loc, param_name)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
(_, Type::And(l, r))
|
// (X or Y) <: Z is valid when X <: Z and Y <: Z
|
||||||
| (_, Type::Or(l, r))
|
(Type::Or(l, r), _) => {
|
||||||
| (_, Type::Not(l, r)) => {
|
self.sub_unify(l, maybe_sup, loc, param_name)?;
|
||||||
|
self.sub_unify(r, maybe_sup, loc, param_name)
|
||||||
|
}
|
||||||
|
// X <: (Y and Z) is valid when X <: Y and X <: Z
|
||||||
|
(_, Type::And(l, r)) => {
|
||||||
self.sub_unify(maybe_sub, l, loc, param_name)?;
|
self.sub_unify(maybe_sub, l, loc, param_name)?;
|
||||||
self.sub_unify(maybe_sub, r, loc, param_name)?;
|
self.sub_unify(maybe_sub, r, loc, param_name)
|
||||||
Ok(())
|
}
|
||||||
|
// (X and Y) <: Z is valid when X <: Z or Y <: Z
|
||||||
|
(Type::And(l, r), _) => {
|
||||||
|
self.sub_unify(l, maybe_sup, loc, param_name)
|
||||||
|
.or_else(|_e| self.sub_unify(r, maybe_sup, loc, param_name))
|
||||||
|
}
|
||||||
|
// X <: (Y or Z) is valid when X <: Y or X <: Z
|
||||||
|
(_, Type::Or(l, r)) => {
|
||||||
|
self.sub_unify(maybe_sub, l, loc, param_name)
|
||||||
|
.or_else(|_e| self.sub_unify(maybe_sub, r, loc, param_name))
|
||||||
}
|
}
|
||||||
(_, Type::Ref(t)) => {
|
(_, Type::Ref(t)) => {
|
||||||
self.sub_unify(maybe_sub, t, loc, param_name)?;
|
self.sub_unify(maybe_sub, t, loc, param_name)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
(_, Type::RefMut{ before, .. }) => {
|
(_, Type::RefMut{ before, .. }) => {
|
||||||
self.sub_unify(maybe_sub, before, loc, param_name)?;
|
self.sub_unify(maybe_sub, before, loc, param_name)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
(Type::Proj { .. }, _) => todo!(),
|
(Type::Proj { .. }, _) => todo!(),
|
||||||
(_, Type::Proj { .. }) => todo!(),
|
(_, Type::Proj { .. }) => todo!(),
|
||||||
|
// TODO: Judgment for any number of preds
|
||||||
(Refinement(sub), Refinement(sup)) => {
|
(Refinement(sub), Refinement(sup)) => {
|
||||||
// {I: Int or Str | I == 0} <: {I: Int}
|
// {I: Int or Str | I == 0} <: {I: Int}
|
||||||
if self.subtype_of(&sub.t, &sup.t) {
|
if self.subtype_of(&sub.t, &sup.t) {
|
||||||
|
|
|
@ -1914,6 +1914,11 @@ impl Expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_string_notype(&self) -> String {
|
||||||
|
let s = self.to_string();
|
||||||
|
s.split("(:").next().unwrap_or("?").trim_end().to_string()
|
||||||
|
}
|
||||||
|
|
||||||
/// 参照するオブジェクト自体が持っている名前(e.g. Int.qual_name == Some("int"), Socket!.qual_name == Some("io.Socket!"))
|
/// 参照するオブジェクト自体が持っている名前(e.g. Int.qual_name == Some("int"), Socket!.qual_name == Some("io.Socket!"))
|
||||||
pub fn qual_name(&self) -> Option<&str> {
|
pub fn qual_name(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -302,16 +302,11 @@ impl ASTLowerer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_normal_array(&mut self, array: ast::NormalArray) -> LowerResult<hir::NormalArray> {
|
fn elem_err(&self, l: &Type, r: &Type, elem: &hir::Expr) -> LowerErrors {
|
||||||
log!(info "entered {}({array})", fn_name!());
|
let elem_disp_notype = elem.to_string_notype();
|
||||||
let mut new_array = vec![];
|
let l = Context::readable_type(l);
|
||||||
let (elems, _) = array.elems.into_iters();
|
let r = Context::readable_type(r);
|
||||||
let mut union = Type::Never;
|
LowerErrors::from(LowerError::syntax_error(
|
||||||
for elem in elems {
|
|
||||||
let elem = self.lower_expr(elem.expr)?;
|
|
||||||
union = self.ctx.union(&union, elem.ref_t());
|
|
||||||
if matches!(union, Type::Or(_, _)) {
|
|
||||||
return Err(LowerErrors::from(LowerError::syntax_error(
|
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
elem.loc(),
|
elem.loc(),
|
||||||
|
@ -323,16 +318,33 @@ impl ASTLowerer {
|
||||||
"english" => "all elements of an array must be of the same type",
|
"english" => "all elements of an array must be of the same type",
|
||||||
)
|
)
|
||||||
.to_owned(),
|
.to_owned(),
|
||||||
Some(
|
Some(switch_lang!(
|
||||||
switch_lang!(
|
"japanese" => format!("[..., {elem_disp_notype}: {l} or {r}]など明示的に型を指定してください"),
|
||||||
"japanese" => "Int or Strなど明示的に型を指定してください",
|
"simplified_chinese" => format!("请明确指定类型,例如: [..., {elem_disp_notype}: {l} or {r}]"),
|
||||||
"simplified_chinese" => "请明确指定类型,例如: Int or Str",
|
"traditional_chinese" => format!("請明確指定類型,例如: [..., {elem_disp_notype}: {l} or {r}]"),
|
||||||
"traditional_chinese" => "請明確指定類型,例如: Int or Str",
|
"english" => format!("please specify the type explicitly, e.g. [..., {elem_disp_notype}: {l} or {r}]"),
|
||||||
"english" => "please specify the type explicitly, e.g. Int or Str",
|
)),
|
||||||
)
|
))
|
||||||
.to_owned(),
|
}
|
||||||
),
|
|
||||||
)));
|
fn lower_normal_array(&mut self, array: ast::NormalArray) -> LowerResult<hir::NormalArray> {
|
||||||
|
log!(info "entered {}({array})", fn_name!());
|
||||||
|
let mut new_array = vec![];
|
||||||
|
let (elems, _) = array.elems.into_iters();
|
||||||
|
let mut union = Type::Never;
|
||||||
|
for elem in elems {
|
||||||
|
let elem = self.lower_expr(elem.expr)?;
|
||||||
|
union = self.ctx.union(&union, elem.ref_t());
|
||||||
|
if let Some((l, r)) = union.union_types() {
|
||||||
|
match (l.is_unbound_var(), r.is_unbound_var()) {
|
||||||
|
(false, false) => {
|
||||||
|
return Err(self.elem_err(&l, &r, &elem));
|
||||||
|
}
|
||||||
|
// TODO: check if the type is compatible with the other type
|
||||||
|
(true, false) => {}
|
||||||
|
(false, true) => {}
|
||||||
|
(true, true) => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
new_array.push(elem);
|
new_array.push(elem);
|
||||||
}
|
}
|
||||||
|
@ -1202,7 +1214,7 @@ impl ASTLowerer {
|
||||||
if let Some((trait_, trait_loc)) = &impl_trait {
|
if let Some((trait_, trait_loc)) = &impl_trait {
|
||||||
self.register_trait_impl(&class, trait_, *trait_loc)?;
|
self.register_trait_impl(&class, trait_, *trait_loc)?;
|
||||||
}
|
}
|
||||||
if let Some(class_root) = self.ctx.get_nominal_type_ctx(&class) {
|
if let Some((_, class_root)) = self.ctx.get_nominal_type_ctx(&class) {
|
||||||
if !class_root.kind.is_class() {
|
if !class_root.kind.is_class() {
|
||||||
return Err(LowerErrors::from(LowerError::method_definition_error(
|
return Err(LowerErrors::from(LowerError::method_definition_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
|
@ -1271,7 +1283,7 @@ impl ASTLowerer {
|
||||||
self.check_collision_and_push(class);
|
self.check_collision_and_push(class);
|
||||||
}
|
}
|
||||||
let class = mono(hir_def.sig.ident().inspect());
|
let class = mono(hir_def.sig.ident().inspect());
|
||||||
let class_ctx = self.ctx.get_nominal_type_ctx(&class).unwrap();
|
let (_, class_ctx) = self.ctx.get_nominal_type_ctx(&class).unwrap();
|
||||||
let type_obj = enum_unwrap!(self.ctx.rec_get_const_obj(hir_def.sig.ident().inspect()).unwrap(), ValueObj::Type:(TypeObj::Generated:(_)));
|
let type_obj = enum_unwrap!(self.ctx.rec_get_const_obj(hir_def.sig.ident().inspect()).unwrap(), ValueObj::Type:(TypeObj::Generated:(_)));
|
||||||
let sup_type = enum_unwrap!(&hir_def.body.block.first().unwrap(), hir::Expr::Call)
|
let sup_type = enum_unwrap!(&hir_def.body.block.first().unwrap(), hir::Expr::Call)
|
||||||
.args
|
.args
|
||||||
|
@ -1313,7 +1325,7 @@ impl ASTLowerer {
|
||||||
set! {TypeRelationInstance::new(class.clone(), trait_.clone())},
|
set! {TypeRelationInstance::new(class.clone(), trait_.clone())},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let trait_ctx = if let Some(trait_ctx) = self.ctx.get_nominal_type_ctx(trait_) {
|
let trait_ctx = if let Some((_, trait_ctx)) = self.ctx.get_nominal_type_ctx(trait_) {
|
||||||
trait_ctx.clone()
|
trait_ctx.clone()
|
||||||
} else {
|
} else {
|
||||||
// TODO: maybe parameters are wrong
|
// TODO: maybe parameters are wrong
|
||||||
|
@ -1451,7 +1463,7 @@ impl ASTLowerer {
|
||||||
other => todo!("{other}"),
|
other => todo!("{other}"),
|
||||||
},
|
},
|
||||||
TypeObj::Builtin(_typ) => {
|
TypeObj::Builtin(_typ) => {
|
||||||
let ctx = self.ctx.get_nominal_type_ctx(_typ).unwrap();
|
let (_, ctx) = self.ctx.get_nominal_type_ctx(_typ).unwrap();
|
||||||
for (decl_name, decl_vi) in ctx.decls.iter() {
|
for (decl_name, decl_vi) in ctx.decls.iter() {
|
||||||
if let Some((name, vi)) = self.ctx.get_local_kv(decl_name.inspect())
|
if let Some((name, vi)) = self.ctx.get_local_kv(decl_name.inspect())
|
||||||
{
|
{
|
||||||
|
|
|
@ -152,6 +152,7 @@ impl Constraint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// :> Sub
|
||||||
pub fn get_sub(&self) -> Option<&Type> {
|
pub fn get_sub(&self) -> Option<&Type> {
|
||||||
match self {
|
match self {
|
||||||
Self::Sandwiched { sub, .. } => Some(sub),
|
Self::Sandwiched { sub, .. } => Some(sub),
|
||||||
|
@ -159,6 +160,7 @@ impl Constraint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <: Sup
|
||||||
pub fn get_super(&self) -> Option<&Type> {
|
pub fn get_super(&self) -> Option<&Type> {
|
||||||
match self {
|
match self {
|
||||||
Self::Sandwiched { sup, .. } => Some(sup),
|
Self::Sandwiched { sup, .. } => Some(sup),
|
||||||
|
@ -567,10 +569,12 @@ impl<T: CanbeFree> Free<T> {
|
||||||
self.constraint().and_then(|c| c.get_type().cloned())
|
self.constraint().and_then(|c| c.get_type().cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_sup(&self) -> Option<Type> {
|
/// <: Super
|
||||||
|
pub fn get_super(&self) -> Option<Type> {
|
||||||
self.constraint().and_then(|c| c.get_super().cloned())
|
self.constraint().and_then(|c| c.get_super().cloned())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// :> Sub
|
||||||
pub fn get_sub(&self) -> Option<Type> {
|
pub fn get_sub(&self) -> Option<Type> {
|
||||||
self.constraint().and_then(|c| c.get_sub().cloned())
|
self.constraint().and_then(|c| c.get_sub().cloned())
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
f x: [{""}; _] = None
|
|
||||||
|
|
||||||
arr = ["aaa"]
|
|
||||||
for! arr, elem =>
|
|
||||||
# elem: Never
|
|
||||||
a = ["", elem] # [{"", "aaa"}; 2]
|
|
||||||
f a
|
|
6
tests/should_err/infer_union_array.er
Normal file
6
tests/should_err/infer_union_array.er
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
f x: [{""}; _] = None
|
||||||
|
|
||||||
|
arr = ["aaa"]
|
||||||
|
for! arr, elem =>
|
||||||
|
a = ["", "aaa"] # [{"", "aaa"}; 2]
|
||||||
|
f a # ERR: type mismatched
|
|
@ -144,6 +144,11 @@ fn exec_args() -> Result<(), ()> {
|
||||||
expect_failure("tests/should_err/args.er", 16)
|
expect_failure("tests/should_err/args.er", 16)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_infer_union_array() -> Result<(), ()> {
|
||||||
|
expect_failure("tests/should_err/infer_union_array.er", 1)
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_invalid_param() -> Result<(), ()> {
|
fn exec_invalid_param() -> Result<(), ()> {
|
||||||
expect_failure("tests/should_err/invalid_param.er", 3)
|
expect_failure("tests/should_err/invalid_param.er", 3)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue