fix: declaration bugs

This commit is contained in:
Shunsuke Shibayama 2023-07-31 11:08:53 +09:00
parent 14b26a7f4d
commit 6c3536cc31
16 changed files with 275 additions and 61 deletions

View file

@ -791,7 +791,7 @@ impl Context {
rparams: &[TyParam],
) -> bool {
log!(
"poly_supertype_of: {}, {}, {}",
"poly_supertype_of: {}\nlps: {}\nrps: {}",
typ.qual_name(),
erg_common::fmt_vec(lparams),
erg_common::fmt_vec(rparams)

View file

@ -1433,7 +1433,7 @@ impl Context {
self.convert_tp_into_value(fv.crack().clone())
}
TyParam::Value(v) => Ok(v),
other => Err(other),
other => self.convert_tp_into_type(other).map(ValueObj::builtin_type),
}
}
@ -2210,7 +2210,8 @@ impl Context {
},
TyParam::ProjCall { obj, attr, args } => {
let tp = self.eval_proj_call(*obj, attr, args, &())?;
Ok(tp_enum(self.get_tp_t(&tp).unwrap_or(Type::Obj), set![tp]))
let ty = self.get_tp_t(&tp).unwrap_or(Type::Obj).derefine();
Ok(tp_enum(ty, set![tp]))
}
other => feature_error!(
self,

View file

@ -141,7 +141,7 @@ const COMPLEX: &str = "Complex";
const INT: &str = "Int";
const MUT_INT: &str = "Int!";
const RATIO: &str = "Ratio";
const MUT_RATIO: &str = "Raltio!";
const MUT_RATIO: &str = "Ratio!";
const FUNC_ABS: &str = "abs";
const FUNC_SUCC: &str = "succ";
const FUNC_PRED: &str = "pred";

View file

@ -187,6 +187,7 @@ impl Context {
}
Ok(ctxs)
}
hir::Expr::TypeAsc(tasc) => self.get_singular_ctxs_by_hir_expr(&tasc.expr, namespace),
// TODO: change error
_ => Err(TyCheckError::no_var_error(
self.cfg.input.clone(),
@ -226,11 +227,21 @@ impl Context {
})
}
#[allow(unused)]
pub(crate) fn get_mut_singular_ctxs_by_ident(
&mut self,
ident: &ast::Identifier,
namespace: &Str,
) -> SingleTyCheckResult<&mut Context> {
self.get_mut_singular_ctxs_and_t_by_ident(ident, namespace)
.map(|(_, ctx)| ctx)
}
pub(crate) fn get_mut_singular_ctxs_and_t_by_ident(
&mut self,
ident: &ast::Identifier,
namespace: &Str,
) -> SingleTyCheckResult<(&Type, &mut Context)> {
let err = TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
@ -239,9 +250,7 @@ impl Context {
ident.inspect(),
self.get_similar_name(ident.inspect()),
);
self.rec_get_mut_type(ident.inspect())
.map(|(_, ctx)| ctx)
.ok_or(err)
self.rec_get_mut_type(ident.inspect()).ok_or(err)
}
pub(crate) fn get_singular_ctxs(
@ -262,6 +271,44 @@ impl Context {
}
Ok(ctxs)
}
ast::Expr::Accessor(ast::Accessor::TypeApp(tapp)) => {
self.get_singular_ctxs(&tapp.obj, namespace)
}
ast::Expr::Call(call) => self.get_singular_ctxs(&call.obj, namespace),
ast::Expr::TypeAscription(tasc) => self.get_singular_ctxs(&tasc.expr, namespace),
_ => Err(TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
obj.loc(),
self.caused_by(),
&obj.to_string(),
None,
)),
}
}
pub(crate) fn get_mut_singular_ctx_and_t(
&mut self,
obj: &ast::Expr,
namespace: &Str,
) -> SingleTyCheckResult<(&Type, &mut Context)> {
match obj {
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => {
self.get_mut_singular_ctxs_and_t_by_ident(ident, namespace)
}
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => {
// REVIEW: 両方singularとは限らない?
let ctx = self.get_mut_singular_ctx(&attr.obj, namespace)?;
let attr = ast::Expr::Accessor(ast::Accessor::Ident(attr.ident.clone()));
ctx.get_mut_singular_ctx_and_t(&attr, namespace)
}
ast::Expr::Accessor(ast::Accessor::TypeApp(tapp)) => {
self.get_mut_singular_ctx_and_t(&tapp.obj, namespace)
}
ast::Expr::Call(call) => self.get_mut_singular_ctx_and_t(&call.obj, namespace),
ast::Expr::TypeAscription(tasc) => {
self.get_mut_singular_ctx_and_t(&tasc.expr, namespace)
}
_ => Err(TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
@ -278,25 +325,8 @@ impl Context {
obj: &ast::Expr,
namespace: &Str,
) -> SingleTyCheckResult<&mut Context> {
match obj {
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => {
self.get_mut_singular_ctxs_by_ident(ident, namespace)
}
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => {
// REVIEW: 両方singularとは限らない?
let ctx = self.get_mut_singular_ctx(&attr.obj, namespace)?;
let attr = ast::Expr::Accessor(ast::Accessor::Ident(attr.ident.clone()));
ctx.get_mut_singular_ctx(&attr, namespace)
}
_ => Err(TyCheckError::no_var_error(
self.cfg.input.clone(),
line!() as usize,
obj.loc(),
self.caused_by(),
&obj.to_string(),
None,
)),
}
self.get_mut_singular_ctx_and_t(obj, namespace)
.map(|(_, ctx)| ctx)
}
fn get_match_call_t(
@ -1912,7 +1942,10 @@ impl Context {
log!(info "Substituted:\ninstance: {instance}");
let res = self
.eval_t_params(instance, self.level, obj)
.map_err(|(t, errs)| (Some(VarInfo { t, ..found.clone() }), errs))?;
.map_err(|(t, errs)| {
log!(err "failed to eval: {t}");
(Some(VarInfo { t, ..found.clone() }), errs)
})?;
debug_assert!(res.has_no_qvar(), "{res} has qvar");
log!(info "Params evaluated:\nres: {res}\n");
let res = VarInfo { t: res, ..found };
@ -3026,9 +3059,10 @@ impl Context {
/// Int.meta_type() == ClassType (<: Type)
/// Show.meta_type() == TraitType (<: Type)
/// [Int; 3].meta_type() == [ClassType; 3] (<: Type)
/// Indexable(T).meta_type() == TraitType (<: Type)
pub fn meta_type(&self, typ: &Type) -> Type {
match typ {
Type::Poly { name, params } => poly(
Type::Poly { name, params } if &name[..] == "Array" || &name[..] == "Set" => poly(
name.clone(),
params
.iter()

View file

@ -13,6 +13,7 @@ use erg_parser::ast::VarName;
use crate::ty::constructors::*;
use crate::ty::free::FreeTyParam;
use crate::ty::free::GENERIC_LEVEL;
use crate::ty::free::{Constraint, HasLevel};
use crate::ty::typaram::{TyParam, TyParamLambda};
use crate::ty::ValueObj;
@ -44,7 +45,7 @@ impl fmt::Display for TyVarCache {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"TyVarInstContext {{ tyvar_instances: {}, typaram_instances: {} }}",
"TyVarContext {{ tyvar_instances: {}, typaram_instances: {} }}",
self.tyvar_instances, self.typaram_instances,
)
}
@ -192,6 +193,10 @@ impl TyVarCache {
}
fn update_typaram(&self, inst: &TyParam, tp: &TyParam, ctx: &Context) {
if inst.level() == Some(GENERIC_LEVEL) {
log!(err "{inst} is fixed");
return;
}
let Ok(free_inst) = <&FreeTyParam>::try_from(inst) else {
if let (Ok(inst), Ok(t)) = (<&Type>::try_from(inst), <&Type>::try_from(tp)) {
return self.update_tyvar(inst, t, ctx);

View file

@ -850,7 +850,11 @@ impl Context {
)?;
args.push(arg_t);
}
Ok(TyParam::app(ident.inspect().clone(), args))
if ctx.kind.is_type() && !ctx.params.is_empty() {
Ok(TyParam::t(poly(ctx.name.clone(), args)))
} else {
Ok(TyParam::app(ident.inspect().clone(), args))
}
}
ast::ConstExpr::Array(ConstArray::Normal(array)) => {
let mut tp_arr = vec![];
@ -1445,7 +1449,7 @@ impl Context {
)?);
}
let ty = new_set.iter().fold(Type::Never, |t, tp| {
self.union(&t, &self.get_tp_t(tp).unwrap())
self.union(&t, &self.get_tp_t(tp).unwrap().derefine())
});
Ok(tp_enum(ty, new_set))
}

View file

@ -139,6 +139,27 @@ impl ClassDefType {
pub const fn impl_trait(class: Type, impl_trait: Type) -> Self {
ClassDefType::ImplTrait { class, impl_trait }
}
pub fn class(&self) -> &Type {
match self {
ClassDefType::Simple(class) => class,
ClassDefType::ImplTrait { class, .. } => class,
}
}
pub fn is_class_of(&self, t: &Type) -> bool {
match self {
ClassDefType::Simple(class) => class == t,
ClassDefType::ImplTrait { class, .. } => class == t,
}
}
pub fn is_impl_of(&self, trait_: &Type) -> bool {
match self {
ClassDefType::ImplTrait { impl_trait, .. } => impl_trait == trait_,
_ => false,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]

View file

@ -4,10 +4,11 @@ use erg_common::consts::PYTHON_MODE;
use erg_common::traits::{Locational, Runnable, Stream};
use erg_common::{enum_unwrap, fn_name, log, set, Str, Triple};
use erg_parser::ast::{self, AscriptionKind, Identifier, VarName, AST};
use erg_parser::ast::{self, AscriptionKind, Identifier, TypeAppArgsKind, VarName, AST};
use erg_parser::desugar::Desugarer;
use crate::context::instantiate::TyVarCache;
use crate::context::{ClassDefType, Context, MethodPair, TraitImpl};
use crate::lower::ASTLowerer;
use crate::ty::constructors::{mono, mono_q_tp, poly, v_enum};
use crate::ty::free::{Constraint, HasLevel};
@ -155,6 +156,7 @@ impl ASTLowerer {
}
fn fake_lower_acc(&self, acc: ast::Accessor) -> LowerResult<hir::Accessor> {
// TypeApp is lowered in `fake_lower_expr`
match acc {
ast::Accessor::Ident(ident) => {
// to resolve `py_name`
@ -509,6 +511,7 @@ impl ASTLowerer {
ast::Expr::Record(rec) => Ok(hir::Expr::Record(self.fake_lower_record(rec)?)),
ast::Expr::Set(set) => Ok(hir::Expr::Set(self.fake_lower_set(set)?)),
ast::Expr::Dict(dict) => Ok(hir::Expr::Dict(self.fake_lower_dict(dict)?)),
ast::Expr::Accessor(ast::Accessor::TypeApp(tapp)) => self.fake_lower_expr(*tapp.obj),
ast::Expr::Accessor(acc) => Ok(hir::Expr::Accessor(self.fake_lower_acc(acc)?)),
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.fake_lower_call(call)?)),
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.fake_lower_lambda(lambda)?)),
@ -525,6 +528,18 @@ impl ASTLowerer {
}
}
fn get_tv_ctx(&self, ident: &ast::Identifier, args: &ast::Args) -> TyVarCache {
let mut tv_ctx = TyVarCache::new(self.module.context.level, &self.module.context);
if let Some((t, _)) = self.module.context.get_type(ident.inspect()) {
for (tp, arg) in t.typarams().iter().zip(args.pos_args()) {
if let ast::Expr::Accessor(ast::Accessor::Ident(ident)) = &arg.expr {
tv_ctx.push_or_init_typaram(&ident.name, tp, &self.module.context);
}
}
}
tv_ctx
}
fn declare_ident(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
log!(info "entered {}({})", fn_name!(), tasc);
let kind = tasc.kind();
@ -567,20 +582,98 @@ impl ASTLowerer {
}
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => {
let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!'));
let mut tv_cache = if let Ok(call) = ast::Call::try_from(*attr.obj.clone()) {
let ast::Expr::Accessor(ast::Accessor::Ident(ident)) = *call.obj else {
return feature_error!(
LowerErrors,
LowerError,
&self.module.context,
call.obj.loc(),
"complex polymorphic type declaration"
);
};
self.get_tv_ctx(&ident, &call.args)
} else {
TyVarCache::new(self.module.context.level, &self.module.context)
};
let t = self
.module
.context
.instantiate_typespec(&tasc.t_spec.t_spec)?;
let ctx = self
.module
.context
.get_mut_singular_ctx(attr.obj.as_ref(), &self.module.context.name.clone())?;
ctx.assign_var_sig(
.instantiate_typespec_with_tv_cache(&tasc.t_spec.t_spec, &mut tv_cache)?;
let impl_trait = if let ast::Expr::Accessor(ast::Accessor::TypeApp(tapp)) =
attr.obj.as_ref()
{
match &tapp.type_args.args {
TypeAppArgsKind::SubtypeOf(typ) => {
let trait_ = self
.module
.context
.instantiate_typespec_with_tv_cache(&typ.t_spec, &mut tv_cache)?;
Some(trait_)
}
TypeAppArgsKind::Args(args) => {
log!(err "{args}");
None
}
}
} else {
None
};
let (class, ctx) = self.module.context.get_mut_singular_ctx_and_t(
attr.obj.as_ref(),
&self.module.context.name.clone(),
)?;
let class = class.clone();
let ctx = if let Some(impl_trait) = impl_trait {
match ctx
.methods_list
.iter_mut()
.find(|(class, _ctx)| class.is_impl_of(&impl_trait))
{
Some((_, impl_ctx)) => impl_ctx,
None => {
let impl_ctx = Context::methods(
Some(impl_trait.clone()),
self.cfg.copy(),
ctx.shared.clone(),
0,
ctx.level,
);
ctx.super_traits.push(impl_trait.clone());
if let Some(mut impls) =
ctx.trait_impls().get_mut(&impl_trait.qual_name())
{
impls.insert(TraitImpl::new(class.clone(), impl_trait.clone()));
}
ctx.methods_list.push((
ClassDefType::impl_trait(class.clone(), impl_trait),
impl_ctx,
));
&mut ctx.methods_list.iter_mut().last().unwrap().1
}
}
} else {
ctx
};
let vi = ctx.assign_var_sig(
&ast::VarSignature::new(ast::VarPattern::Ident(attr.ident.clone()), None),
&t,
ast::DefId(0),
Some(py_name.clone()),
)?;
if let Some(types) = self
.module
.context
.method_to_classes
.get_mut(attr.ident.inspect())
{
types.push(MethodPair::new(class, vi.clone()));
} else {
self.module.context.method_to_classes.insert(
attr.ident.inspect().clone(),
vec![MethodPair::new(class, vi.clone())],
);
}
let obj = self.fake_lower_expr(*attr.obj)?;
let muty = Mutability::from(&attr.ident.inspect()[..]);
let vis = self
@ -614,14 +707,7 @@ impl ASTLowerer {
);
};
let py_name = Str::rc(ident.inspect().trim_end_matches('!'));
let mut tv_cache = TyVarCache::new(self.module.context.level, &self.module.context);
if let Some((t, _)) = self.module.context.get_type(ident.inspect()) {
for (tp, arg) in t.typarams().iter().zip(call.args.pos_args()) {
if let ast::Expr::Accessor(ast::Accessor::Ident(ident)) = &arg.expr {
tv_cache.push_or_init_typaram(&ident.name, tp, &self.module.context);
}
}
}
let mut tv_cache = self.get_tv_ctx(&ident, &call.args);
let t = self
.module
.context

View file

@ -1,6 +1,9 @@
.NDArray = 'ndarray': (T: Type, Shape: [Nat; _]) -> ClassType
.NDArray(T, _) <: Output T
.NDArray(_, _) <: Num
.NDArray(T, S)|<: Add .NDArray(T, S)|.
Output: {.NDArray(T, S)}
__add__: |T, S: [Nat; _]|(self: .NDArray(T, S), other: .NDArray(T, S)) -> .NDArray(T, S)
.NDArray.
shape: [Nat; _]
ndim: Nat
@ -11,7 +14,7 @@
.Nan: Float
.abs: |T|(object: .NDArray(T),) -> .NDArray(T)
.add: |T|(object: .NDArray(T), other: .NDArray(T)) -> .NDArray(T)
.add: |T, S: [Nat; _]|(object: .NDArray(T, S), other: .NDArray(T, S)) -> .NDArray(T, S)
.all: |T <: Num|(object: .NDArray(T),) -> Bool
.any: |T <: Num|(object: .NDArray(T),) -> Bool
.arange: |T <: Num|(start: T, stop := T, step := T) -> .NDArray(T)

View file

@ -5,8 +5,8 @@ use erg_common::traits::{Locational, Stream};
use erg_common::Str;
use erg_parser::ast::{
Accessor, ClassAttr, ClassDef, Expr, Identifier, Methods, Module, PatchDef, PreDeclTypeSpec,
TypeAscription, TypeSpec, AST,
Accessor, ClassAttr, ClassDef, Expr, Identifier, Methods, Module, PatchDef, TypeAscription,
TypeSpec, AST,
};
use crate::error::{TyCheckError, TyCheckErrors};
@ -77,13 +77,12 @@ impl ASTLinker {
}
}
match &methods.class {
TypeSpec::PreDeclTy(PreDeclTypeSpec::Mono(ident)) => {
self.link_methods(ident.inspect().clone(), &mut new, methods, mode)
TypeSpec::PreDeclTy(predecl) => {
self.link_methods(predecl.ident().into(), &mut new, methods, mode)
}
TypeSpec::TypeApp { spec, .. } => {
if let TypeSpec::PreDeclTy(PreDeclTypeSpec::Mono(ident)) = spec.as_ref()
{
self.link_methods(ident.inspect().clone(), &mut new, methods, mode)
if let Some(ident) = spec.ident() {
self.link_methods(ident.into(), &mut new, methods, mode)
} else {
let similar_name = self
.def_root_pos_map

View file

@ -72,7 +72,7 @@ pub fn expr_to_variable(expr: &ast::Expr) -> Option<Variable> {
/// Checks & infers types of an AST, and convert (lower) it into a HIR
#[derive(Debug)]
pub struct ASTLowerer {
cfg: ErgConfig,
pub(crate) cfg: ErgConfig,
pub(crate) module: ModuleContext,
pub(crate) errs: LowerErrors,
pub(crate) warns: LowerWarnings,
@ -1741,10 +1741,10 @@ impl ASTLowerer {
} else {
self.check_override(&class, None);
}
if let Err(err) = self.check_trait_impl(impl_trait, &class) {
if let Err(err) = self.check_trait_impl(impl_trait.clone(), &class) {
self.errs.push(err);
}
self.check_collision_and_push(class);
self.check_collision_and_push(class, impl_trait.map(|(t, _)| t));
}
let class = self.module.context.gen_type(&hir_def.sig.ident().raw);
let Some((_, class_ctx)) = self.module.context.get_nominal_type_ctx(&class) else {
@ -2180,7 +2180,7 @@ impl ASTLowerer {
(unverified_names, errors)
}
fn check_collision_and_push(&mut self, class: Type) {
fn check_collision_and_push(&mut self, class: Type, impl_trait: Option<Type>) {
let methods = self.module.context.pop();
let Some((_, class_root)) = self
.module
@ -2214,9 +2214,12 @@ impl ASTLowerer {
}
}
}
class_root
.methods_list
.push((ClassDefType::Simple(class), methods));
let typ = if let Some(impl_trait) = impl_trait {
ClassDefType::impl_trait(class, impl_trait)
} else {
ClassDefType::Simple(class)
};
class_root.methods_list.push((typ, methods));
}
fn push_patch(&mut self) {

View file

@ -16,6 +16,8 @@ use crate::context::TraitImpl;
/// (Erg links all scripts defined in erg and outputs them to a single pyc file).
#[derive(Debug, Default)]
pub struct TraitImpls {
/// * key: trait qualified name
/// * value: set of trait impls
cache: Dict<Str, Set<TraitImpl>>,
}

View file

@ -820,6 +820,7 @@ impl<T: Send + Sync + 'static + Clone> Free<T> {
self.borrow().is_unnamed_unbound()
}
/// interior-mut
#[track_caller]
pub fn replace(&self, to: FreeKind<T>) {
// prevent linking to self
@ -831,6 +832,7 @@ impl<T: Send + Sync + 'static + Clone> Free<T> {
}
impl<T: Clone + fmt::Debug + Send + Sync + 'static> Free<T> {
/// interior-mut
/// SAFETY: use `Type/TyParam::link` instead of this.
/// This method may cause circular references.
#[track_caller]
@ -842,6 +844,7 @@ impl<T: Clone + fmt::Debug + Send + Sync + 'static> Free<T> {
self.borrow_mut().replace(to.clone());
}
/// interior-mut
#[track_caller]
pub(super) fn undoable_link(&self, to: &T) {
if self.is_linked() && addr_eq!(*self.crack(), *to) {
@ -855,6 +858,7 @@ impl<T: Clone + fmt::Debug + Send + Sync + 'static> Free<T> {
*self.borrow_mut() = new;
}
/// interior-mut
pub fn undo(&self) {
let prev = match &*self.borrow() {
FreeKind::UndoableLinked { previous, .. } => *previous.clone(),
@ -942,6 +946,7 @@ impl<T: Clone + fmt::Debug + Send + Sync + 'static> Free<T> {
}
impl<T: Default + Clone + fmt::Debug + Send + Sync + 'static> Free<T> {
/// interior-mut
#[track_caller]
pub fn dummy_link(&self) {
self.undoable_link(&T::default());
@ -991,8 +996,12 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
self.constraint().map(|c| c.is_uninited()).unwrap_or(false)
}
/// interior-mut
/// if `in_inst_or_gen` is true, constraint will be updated forcibly
pub fn update_constraint(&self, new_constraint: Constraint, in_inst_or_gen: bool) {
if new_constraint.get_type() == Some(&Type::Never) {
panic!();
}
match &mut *self.borrow_mut() {
FreeKind::Unbound {
lev, constraint, ..
@ -1015,6 +1024,7 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
}
}
/// interior-mut
pub fn update_sub<F>(&self, f: F)
where
F: FnOnce(Type) -> Type,
@ -1024,6 +1034,7 @@ impl<T: CanbeFree + Send + Clone> Free<T> {
self.update_constraint(new_constraint, true);
}
/// interior-mut
pub fn update_super<F>(&self, f: F)
where
F: FnOnce(Type) -> Type,

View file

@ -3127,10 +3127,14 @@ impl Type {
}
}
/// interior-mut
pub(crate) fn link(&self, to: &Type) {
if self.addr_eq(to) {
return;
}
if self.level() == Some(GENERIC_LEVEL) {
panic!("{self} is fixed");
}
match self {
Self::FreeVar(fv) => fv.link(to),
Self::Refinement(refine) => refine.t.link(to),
@ -3138,6 +3142,7 @@ impl Type {
}
}
/// interior-mut
pub(crate) fn undoable_link(&self, to: &Type) {
if self.addr_eq(to) {
return;

View file

@ -1257,16 +1257,21 @@ impl TyParam {
}
}
/// interior-mut
pub(crate) fn link(&self, to: &TyParam) {
if self.addr_eq(to) {
return;
}
if self.level() == Some(GENERIC_LEVEL) {
panic!("{self} is fixed");
}
match self {
Self::FreeVar(fv) => fv.link(to),
_ => panic!("{self} is not a free variable"),
}
}
/// interior-mut
pub(crate) fn undoable_link(&self, to: &TyParam) {
if self.addr_eq(to) {
return;