Merge branch 'main' into fix-els

This commit is contained in:
Shunsuke Shibayama 2023-08-23 01:52:40 +09:00
commit fd6e75a435
12 changed files with 198 additions and 173 deletions

View file

@ -383,9 +383,9 @@ impl Context {
(Some((_, l_sup)), Some((r_sub, _))) => self.supertype_of(&l_sup, &r_sub), (Some((_, l_sup)), Some((r_sub, _))) => self.supertype_of(&l_sup, &r_sub),
_ => { _ => {
if lfv.is_linked() { if lfv.is_linked() {
self.supertype_of(&lfv.crack(), rhs) self.supertype_of(lfv.unsafe_crack(), rhs)
} else if rfv.is_linked() { } else if rfv.is_linked() {
self.supertype_of(lhs, &rfv.crack()) self.supertype_of(lhs, rfv.unsafe_crack())
} else { } else {
false false
} }
@ -1418,7 +1418,8 @@ impl Context {
Not(t) => *t.clone(), Not(t) => *t.clone(),
Refinement(r) => Type::Refinement(r.clone().invert()), Refinement(r) => Type::Refinement(r.clone().invert()),
Guard(guard) => Type::Guard(GuardType::new( Guard(guard) => Type::Guard(GuardType::new(
guard.var.clone(), guard.namespace.clone(),
guard.target.clone(),
self.complement(&guard.to), self.complement(&guard.to),
)), )),
Or(l, r) => self.intersection(&self.complement(l), &self.complement(r)), Or(l, r) => self.intersection(&self.complement(l), &self.complement(r)),

View file

@ -1092,9 +1092,9 @@ impl Context {
.unbound_name() .unbound_name()
.map_or(false, |name| !qnames.contains(&name)) .map_or(false, |name| !qnames.contains(&name))
{ {
let t = mem::take(acc.ref_mut_t()); let t = mem::take(acc.ref_mut_t().unwrap());
let mut dereferencer = Dereferencer::simple(self, qnames, acc); let mut dereferencer = Dereferencer::simple(self, qnames, acc);
*acc.ref_mut_t() = dereferencer.deref_tyvar(t)?; *acc.ref_mut_t().unwrap() = dereferencer.deref_tyvar(t)?;
} }
if let hir::Accessor::Attr(attr) = acc { if let hir::Accessor::Attr(attr) = acc {
self.resolve_expr_t(&mut attr.obj, qnames)?; self.resolve_expr_t(&mut attr.obj, qnames)?;
@ -1181,10 +1181,10 @@ impl Context {
let mut dereferencer = Dereferencer::simple(self, qnames, record); let mut dereferencer = Dereferencer::simple(self, qnames, record);
record.t = dereferencer.deref_tyvar(t)?; record.t = dereferencer.deref_tyvar(t)?;
for attr in record.attrs.iter_mut() { for attr in record.attrs.iter_mut() {
let t = mem::take(attr.sig.ref_mut_t()); let t = mem::take(attr.sig.ref_mut_t().unwrap());
let mut dereferencer = Dereferencer::simple(self, qnames, &attr.sig); let mut dereferencer = Dereferencer::simple(self, qnames, &attr.sig);
let t = dereferencer.deref_tyvar(t)?; let t = dereferencer.deref_tyvar(t)?;
*attr.sig.ref_mut_t() = t; *attr.sig.ref_mut_t().unwrap() = t;
for chunk in attr.body.block.iter_mut() { for chunk in attr.body.block.iter_mut() {
self.resolve_expr_t(chunk, qnames)?; self.resolve_expr_t(chunk, qnames)?;
} }
@ -1232,9 +1232,9 @@ impl Context {
} else { } else {
qnames.clone() qnames.clone()
}; };
let t = mem::take(def.sig.ref_mut_t()); let t = mem::take(def.sig.ref_mut_t().unwrap());
let mut dereferencer = Dereferencer::simple(self, &qnames, &def.sig); let mut dereferencer = Dereferencer::simple(self, &qnames, &def.sig);
*def.sig.ref_mut_t() = dereferencer.deref_tyvar(t)?; *def.sig.ref_mut_t().unwrap() = dereferencer.deref_tyvar(t)?;
if let Some(params) = def.sig.params_mut() { if let Some(params) = def.sig.params_mut() {
self.resolve_params_t(params, &qnames)?; self.resolve_params_t(params, &qnames)?;
} }

View file

@ -2873,6 +2873,14 @@ impl Context {
} }
} }
pub(crate) fn rec_get_guards(&self) -> Vec<&GuardType> {
if let Some(outer) = self.get_outer() {
[self.guards.iter().collect(), outer.rec_get_guards()].concat()
} else {
self.guards.iter().collect()
}
}
// TODO: `Override` decorator should also be used // TODO: `Override` decorator should also be used
/// e.g. /// e.g.
/// ```erg /// ```erg
@ -3203,9 +3211,9 @@ impl Context {
return Err(TyCheckErrors::from(TyCheckError::invalid_type_cast_error( return Err(TyCheckErrors::from(TyCheckError::invalid_type_cast_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
guard.var.loc(), guard.target.loc(),
self.caused_by(), self.caused_by(),
&guard.var.to_string(), &guard.target.to_string(),
base, base,
&guard.to, &guard.to,
None, None,
@ -3229,9 +3237,9 @@ impl Context {
Err(TyCheckErrors::from(TyCheckError::invalid_type_cast_error( Err(TyCheckErrors::from(TyCheckError::invalid_type_cast_error(
self.cfg.input.clone(), self.cfg.input.clone(),
line!() as usize, line!() as usize,
guard.var.loc(), guard.target.loc(),
self.caused_by(), self.caused_by(),
&guard.var.to_string(), &guard.target.to_string(),
base, base,
&guard.to, &guard.to,
None, None,

View file

@ -35,7 +35,7 @@ use crate::ty::free::{Constraint, HasLevel};
use crate::ty::typaram::TyParam; use crate::ty::typaram::TyParam;
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj}; use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
use crate::ty::{ use crate::ty::{
Field, GuardType, HasType, ParamTy, SubrType, Type, Variable, Visibility, VisibilityModifier, CastTarget, Field, GuardType, HasType, ParamTy, SubrType, Type, Visibility, VisibilityModifier,
}; };
use crate::build_hir::HIRBuilder; use crate::build_hir::HIRBuilder;
@ -2272,49 +2272,61 @@ impl Context {
} }
} }
pub(crate) fn get_casted_type(&self, expr: &ast::Expr) -> Option<Type> {
for guard in self.rec_get_guards() {
if !self.name.starts_with(&guard.namespace[..]) {
continue;
}
if let CastTarget::Expr(target) = &guard.target {
if expr == target.as_ref() {
return Some(*guard.to.clone());
}
}
}
None
}
pub(crate) fn cast( pub(crate) fn cast(
&mut self, &mut self,
guard: GuardType, guard: GuardType,
overwritten: &mut Vec<(VarName, VarInfo)>, overwritten: &mut Vec<(VarName, VarInfo)>,
) -> TyCheckResult<()> { ) -> TyCheckResult<()> {
if let Variable::Var { match &guard.target {
namespace, name, .. CastTarget::Var { name, .. } => {
} = &guard.var if !self.name.starts_with(&guard.namespace[..]) {
{ return Ok(());
if !self.name.starts_with(&namespace[..]) {
return Ok(());
}
let vi = if let Some((name, vi)) = self.locals.remove_entry(name) {
overwritten.push((name, vi.clone()));
vi
} else if let Some((n, vi)) = self.get_var_kv(name) {
overwritten.push((n.clone(), vi.clone()));
vi.clone()
} else {
VarInfo::nd_parameter(
*guard.to.clone(),
self.absolutize(().loc()),
self.name.clone(),
)
};
match self.recover_typarams(&vi.t, &guard) {
Ok(t) => {
self.locals
.insert(VarName::from_str(name.clone()), VarInfo { t, ..vi });
} }
Err(errs) => { let vi = if let Some((name, vi)) = self.locals.remove_entry(name) {
self.locals.insert(VarName::from_str(name.clone()), vi); overwritten.push((name, vi.clone()));
return Err(errs); vi
} else if let Some((n, vi)) = self.get_var_kv(name) {
overwritten.push((n.clone(), vi.clone()));
vi.clone()
} else {
VarInfo::nd_parameter(
*guard.to.clone(),
self.absolutize(().loc()),
self.name.clone(),
)
};
match self.recover_typarams(&vi.t, &guard) {
Ok(t) => {
self.locals
.insert(VarName::from_str(name.clone()), VarInfo { t, ..vi });
}
Err(errs) => {
self.locals.insert(VarName::from_str(name.clone()), vi);
return Err(errs);
}
} }
} }
} /* else { CastTarget::Param { .. } => {
return Err(TyCheckErrors::from(TyCheckError::feature_error( // TODO:
self.cfg.input.clone(), }
guard.var.loc(), CastTarget::Expr(_) => {
&format!("casting {}", guard.var), self.guards.push(guard);
self.caused_by(), }
))); }
} */
Ok(()) Ok(())
} }

View file

@ -413,8 +413,8 @@ impl HasType for Identifier {
&self.vi.t &self.vi.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
&mut self.vi.t Some(&mut self.vi.t)
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
@ -545,7 +545,7 @@ impl HasType for Attribute {
self.ident.ref_t() self.ident.ref_t()
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
self.ident.ref_mut_t() self.ident.ref_mut_t()
} }
#[inline] #[inline]
@ -1221,8 +1221,8 @@ impl HasType for BinOp {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
self.info.t.return_t().unwrap() self.info.t.return_t().unwrap()
} }
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
self.info.t.mut_return_t().unwrap() self.info.t.mut_return_t()
} }
#[inline] #[inline]
fn lhs_t(&self) -> &Type { fn lhs_t(&self) -> &Type {
@ -1268,8 +1268,8 @@ impl HasType for UnaryOp {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
self.info.t.return_t().unwrap() self.info.t.return_t().unwrap()
} }
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
self.info.t.mut_return_t().unwrap() self.info.t.mut_return_t()
} }
#[inline] #[inline]
fn lhs_t(&self) -> &Type { fn lhs_t(&self) -> &Type {
@ -1357,11 +1357,11 @@ impl HasType for Call {
} }
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
if let Some(attr) = self.attr_name.as_mut() { if let Some(attr) = self.attr_name.as_mut() {
attr.ref_mut_t().mut_return_t().unwrap() attr.ref_mut_t()?.mut_return_t()
} else { } else {
self.obj.ref_mut_t().mut_return_t().unwrap() self.obj.ref_mut_t()?.mut_return_t()
} }
} }
#[inline] #[inline]
@ -1391,12 +1391,12 @@ impl HasType for Call {
#[inline] #[inline]
fn signature_mut_t(&mut self) -> Option<&mut Type> { fn signature_mut_t(&mut self) -> Option<&mut Type> {
if let Some(attr) = self.attr_name.as_mut() { if let Some(attr) = self.attr_name.as_mut() {
Some(attr.ref_mut_t()) attr.ref_mut_t()
} else { } else {
if let Expr::Call(call) = self.obj.as_ref() { if let Expr::Call(call) = self.obj.as_ref() {
call.return_t()?; call.return_t()?;
} }
Some(self.obj.ref_mut_t()) self.obj.ref_mut_t()
} }
} }
} }
@ -1466,8 +1466,8 @@ impl HasType for Block {
.unwrap_or(Type::FAILURE) .unwrap_or(Type::FAILURE)
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
self.last_mut().unwrap().ref_mut_t() self.last_mut()?.ref_mut_t()
} }
#[inline] #[inline]
fn t(&self) -> Type { fn t(&self) -> Type {
@ -1517,8 +1517,8 @@ impl HasType for Dummy {
Type::FAILURE Type::FAILURE
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
todo!() None
} }
#[inline] #[inline]
fn t(&self) -> Type { fn t(&self) -> Type {
@ -1583,7 +1583,7 @@ impl HasType for VarSignature {
self.ident.ref_t() self.ident.ref_t()
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
self.ident.ref_mut_t() self.ident.ref_mut_t()
} }
#[inline] #[inline]
@ -1874,7 +1874,7 @@ impl HasType for SubrSignature {
self.ident.ref_t() self.ident.ref_t()
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
self.ident.ref_mut_t() self.ident.ref_mut_t()
} }
#[inline] #[inline]
@ -2105,8 +2105,8 @@ impl HasType for Def {
Type::NONE Type::NONE
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
todo!() None
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
@ -2188,8 +2188,8 @@ impl HasType for Methods {
Type::NONE Type::NONE
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
todo!() None
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
@ -2242,8 +2242,8 @@ impl HasType for ClassDef {
Type::NONE Type::NONE
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
todo!() None
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
@ -2312,8 +2312,8 @@ impl HasType for PatchDef {
Type::NONE Type::NONE
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
todo!() None
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
@ -2368,8 +2368,8 @@ impl HasType for ReDef {
Type::NONE Type::NONE
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
todo!() None
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
@ -2455,9 +2455,9 @@ impl HasType for TypeAscription {
} }
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
if self.spec.kind().is_force_cast() { if self.spec.kind().is_force_cast() {
&mut self.spec.spec_t Some(&mut self.spec.spec_t)
} else { } else {
self.expr.ref_mut_t() self.expr.ref_mut_t()
} }

View file

@ -31,7 +31,7 @@ use crate::ty::constructors::{
use crate::ty::free::Constraint; use crate::ty::free::Constraint;
use crate::ty::typaram::TyParam; use crate::ty::typaram::TyParam;
use crate::ty::value::{GenTypeObj, TypeObj, ValueObj}; use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
use crate::ty::{GuardType, HasType, ParamTy, Predicate, Type, Variable, VisibilityModifier}; use crate::ty::{CastTarget, GuardType, HasType, ParamTy, Predicate, Type, VisibilityModifier};
use crate::context::{ use crate::context::{
ClassDefType, Context, ContextKind, ContextProvider, ControlKind, ModuleContext, ClassDefType, Context, ContextKind, ContextProvider, ControlKind, ModuleContext,
@ -50,26 +50,13 @@ use crate::{feature_error, unreachable_error};
use VisibilityModifier::*; use VisibilityModifier::*;
pub fn acc_to_variable(namespace: Str, acc: &ast::Accessor) -> Option<Variable> { pub fn expr_to_cast_target(expr: &ast::Expr) -> CastTarget {
match acc { match expr {
ast::Accessor::Ident(ident) => Some(Variable::Var { ast::Expr::Accessor(ast::Accessor::Ident(ident)) => CastTarget::Var {
namespace,
name: ident.inspect().clone(), name: ident.inspect().clone(),
loc: ident.loc(), loc: ident.loc(),
}), },
ast::Accessor::Attr(attr) => Some(Variable::attr( _ => CastTarget::expr(expr.clone()),
expr_to_variable(namespace, &attr.obj)?,
attr.ident.inspect().clone(),
attr.loc(),
)),
_ => None,
}
}
pub fn expr_to_variable(namespace: Str, expr: &ast::Expr) -> Option<Variable> {
match expr {
ast::Expr::Accessor(acc) => acc_to_variable(namespace, acc),
_ => None,
} }
} }
@ -746,28 +733,29 @@ impl ASTLowerer {
} }
fn get_guard_type(&self, op: &Token, lhs: &ast::Expr, rhs: &ast::Expr) -> Option<Type> { fn get_guard_type(&self, op: &Token, lhs: &ast::Expr, rhs: &ast::Expr) -> Option<Type> {
let var = if op.kind == TokenKind::ContainsOp { let target = if op.kind == TokenKind::ContainsOp {
expr_to_variable(self.module.context.name.clone(), rhs)? expr_to_cast_target(rhs)
} else { } else {
expr_to_variable(self.module.context.name.clone(), lhs)? expr_to_cast_target(lhs)
}; };
let namespace = self.module.context.name.clone();
match op.kind { match op.kind {
// l in T -> T contains l // l in T -> T contains l
TokenKind::ContainsOp => { TokenKind::ContainsOp => {
let to = self.module.context.expr_to_type(lhs.clone())?; let to = self.module.context.expr_to_type(lhs.clone())?;
Some(guard(var, to)) Some(guard(namespace, target, to))
} }
TokenKind::Symbol if &op.content[..] == "isinstance" => { TokenKind::Symbol if &op.content[..] == "isinstance" => {
let to = self.module.context.expr_to_type(rhs.clone())?; let to = self.module.context.expr_to_type(rhs.clone())?;
Some(guard(var, to)) Some(guard(namespace, target, to))
} }
TokenKind::IsOp | TokenKind::DblEq => { TokenKind::IsOp | TokenKind::DblEq => {
let value = self.module.context.expr_to_value(rhs.clone())?; let value = self.module.context.expr_to_value(rhs.clone())?;
Some(guard(var, v_enum(set! { value }))) Some(guard(namespace, target, v_enum(set! { value })))
} }
TokenKind::IsNotOp | TokenKind::NotEq => { TokenKind::IsNotOp | TokenKind::NotEq => {
let value = self.module.context.expr_to_value(rhs.clone())?; let value = self.module.context.expr_to_value(rhs.clone())?;
let ty = guard(var, v_enum(set! { value })); let ty = guard(namespace, target, v_enum(set! { value }));
Some(self.module.context.complement(&ty)) Some(self.module.context.complement(&ty))
} }
TokenKind::Gre => { TokenKind::Gre => {
@ -776,7 +764,7 @@ impl ASTLowerer {
let varname = self.fresh_gen.fresh_varname(); let varname = self.fresh_gen.fresh_varname();
let pred = Predicate::gt(varname.clone(), TyParam::value(value)); let pred = Predicate::gt(varname.clone(), TyParam::value(value));
let refine = refinement(varname, t, pred); let refine = refinement(varname, t, pred);
Some(guard(var, refine)) Some(guard(namespace, target, refine))
} }
TokenKind::GreEq => { TokenKind::GreEq => {
let value = self.module.context.expr_to_value(rhs.clone())?; let value = self.module.context.expr_to_value(rhs.clone())?;
@ -784,7 +772,7 @@ impl ASTLowerer {
let varname = self.fresh_gen.fresh_varname(); let varname = self.fresh_gen.fresh_varname();
let pred = Predicate::ge(varname.clone(), TyParam::value(value)); let pred = Predicate::ge(varname.clone(), TyParam::value(value));
let refine = refinement(varname, t, pred); let refine = refinement(varname, t, pred);
Some(guard(var, refine)) Some(guard(namespace, target, refine))
} }
TokenKind::Less => { TokenKind::Less => {
let value = self.module.context.expr_to_value(rhs.clone())?; let value = self.module.context.expr_to_value(rhs.clone())?;
@ -792,7 +780,7 @@ impl ASTLowerer {
let varname = self.fresh_gen.fresh_varname(); let varname = self.fresh_gen.fresh_varname();
let pred = Predicate::lt(varname.clone(), TyParam::value(value)); let pred = Predicate::lt(varname.clone(), TyParam::value(value));
let refine = refinement(varname, t, pred); let refine = refinement(varname, t, pred);
Some(guard(var, refine)) Some(guard(namespace, target, refine))
} }
TokenKind::LessEq => { TokenKind::LessEq => {
let value = self.module.context.expr_to_value(rhs.clone())?; let value = self.module.context.expr_to_value(rhs.clone())?;
@ -800,7 +788,7 @@ impl ASTLowerer {
let varname = self.fresh_gen.fresh_varname(); let varname = self.fresh_gen.fresh_varname();
let pred = Predicate::le(varname.clone(), TyParam::value(value)); let pred = Predicate::le(varname.clone(), TyParam::value(value));
let refine = refinement(varname, t, pred); let refine = refinement(varname, t, pred);
Some(guard(var, refine)) Some(guard(namespace, target, refine))
} }
_ => None, _ => None,
} }
@ -930,7 +918,8 @@ impl ASTLowerer {
} }
1 if kind.is_if() => { 1 if kind.is_if() => {
let guard = GuardType::new( let guard = GuardType::new(
guard.var.clone(), guard.namespace.clone(),
guard.target.clone(),
self.module.context.complement(&guard.to), self.module.context.complement(&guard.to),
); );
self.module.context.guards.push(guard); self.module.context.guards.push(guard);
@ -1015,10 +1004,10 @@ impl ASTLowerer {
} else { } else {
if let hir::Expr::Call(call) = &obj { if let hir::Expr::Call(call) = &obj {
if call.return_t().is_some() { if call.return_t().is_some() {
*obj.ref_mut_t() = vi.t; *obj.ref_mut_t().unwrap() = vi.t;
} }
} else { } else {
*obj.ref_mut_t() = vi.t; *obj.ref_mut_t().unwrap() = vi.t;
} }
None None
}; };
@ -1964,7 +1953,7 @@ impl ASTLowerer {
) { ) {
Err(err) => self.errs.push(err), Err(err) => self.errs.push(err),
Ok(_) => { Ok(_) => {
*attr.ref_mut_t() = derefined.clone(); *attr.ref_mut_t().unwrap() = derefined.clone();
if let hir::Accessor::Ident(ident) = &attr { if let hir::Accessor::Ident(ident) = &attr {
if let Some(vi) = self if let Some(vi) = self
.module .module
@ -2426,27 +2415,36 @@ impl ASTLowerer {
// so turn off type checking (check=false) // so turn off type checking (check=false)
fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> { fn lower_expr(&mut self, expr: ast::Expr) -> LowerResult<hir::Expr> {
log!(info "entered {}", fn_name!()); log!(info "entered {}", fn_name!());
match expr { let casted = self.module.context.get_casted_type(&expr);
ast::Expr::Literal(lit) => Ok(hir::Expr::Lit(self.lower_literal(lit)?)), let mut expr = match expr {
ast::Expr::Array(arr) => Ok(hir::Expr::Array(self.lower_array(arr)?)), ast::Expr::Literal(lit) => hir::Expr::Lit(self.lower_literal(lit)?),
ast::Expr::Tuple(tup) => Ok(hir::Expr::Tuple(self.lower_tuple(tup)?)), ast::Expr::Array(arr) => hir::Expr::Array(self.lower_array(arr)?),
ast::Expr::Record(rec) => Ok(hir::Expr::Record(self.lower_record(rec)?)), ast::Expr::Tuple(tup) => hir::Expr::Tuple(self.lower_tuple(tup)?),
ast::Expr::Set(set) => Ok(hir::Expr::Set(self.lower_set(set)?)), ast::Expr::Record(rec) => hir::Expr::Record(self.lower_record(rec)?),
ast::Expr::Dict(dict) => Ok(hir::Expr::Dict(self.lower_dict(dict)?)), ast::Expr::Set(set) => hir::Expr::Set(self.lower_set(set)?),
ast::Expr::Accessor(acc) => Ok(hir::Expr::Accessor(self.lower_acc(acc)?)), ast::Expr::Dict(dict) => hir::Expr::Dict(self.lower_dict(dict)?),
ast::Expr::BinOp(bin) => Ok(hir::Expr::BinOp(self.lower_bin(bin))), ast::Expr::Accessor(acc) => hir::Expr::Accessor(self.lower_acc(acc)?),
ast::Expr::UnaryOp(unary) => Ok(hir::Expr::UnaryOp(self.lower_unary(unary))), ast::Expr::BinOp(bin) => hir::Expr::BinOp(self.lower_bin(bin)),
ast::Expr::Call(call) => Ok(hir::Expr::Call(self.lower_call(call)?)), ast::Expr::UnaryOp(unary) => hir::Expr::UnaryOp(self.lower_unary(unary)),
ast::Expr::DataPack(pack) => Ok(hir::Expr::Call(self.lower_pack(pack)?)), ast::Expr::Call(call) => hir::Expr::Call(self.lower_call(call)?),
ast::Expr::Lambda(lambda) => Ok(hir::Expr::Lambda(self.lower_lambda(lambda)?)), ast::Expr::DataPack(pack) => hir::Expr::Call(self.lower_pack(pack)?),
ast::Expr::TypeAscription(tasc) => Ok(hir::Expr::TypeAsc(self.lower_type_asc(tasc)?)), ast::Expr::Lambda(lambda) => hir::Expr::Lambda(self.lower_lambda(lambda)?),
ast::Expr::TypeAscription(tasc) => hir::Expr::TypeAsc(self.lower_type_asc(tasc)?),
// Checking is also performed for expressions in Dummy. However, it has no meaning in code generation // Checking is also performed for expressions in Dummy. However, it has no meaning in code generation
ast::Expr::Dummy(dummy) => Ok(hir::Expr::Dummy(self.lower_dummy(dummy)?)), ast::Expr::Dummy(dummy) => hir::Expr::Dummy(self.lower_dummy(dummy)?),
other => { other => {
log!(err "unreachable: {other}"); log!(err "unreachable: {other}");
unreachable_error!(LowerErrors, LowerError, self.module.context) return unreachable_error!(LowerErrors, LowerError, self.module.context);
}
};
if let Some(casted) = casted {
if self.module.context.subtype_of(&casted, expr.ref_t()) {
if let Some(ref_mut_t) = expr.ref_mut_t() {
*ref_mut_t = casted;
}
} }
} }
Ok(expr)
} }
/// The meaning of TypeAscription changes between chunk and expr. /// The meaning of TypeAscription changes between chunk and expr.

View file

@ -210,8 +210,8 @@ impl HasType for CodeObj {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
&Type::Code &Type::Code
} }
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
todo!() None
} }
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
None None

View file

@ -474,8 +474,8 @@ pub fn not(ty: Type) -> Type {
Type::Not(Box::new(ty)) Type::Not(Box::new(ty))
} }
pub fn guard(var: Variable, to: Type) -> Type { pub fn guard(namespace: Str, target: CastTarget, to: Type) -> Type {
Type::Guard(GuardType::new(var, to)) Type::Guard(GuardType::new(namespace, target, to))
} }
pub fn bounded(sub: Type, sup: Type) -> Type { pub fn bounded(sub: Type, sup: Type) -> Type {

View file

@ -31,6 +31,7 @@ use erg_common::set::Set;
use erg_common::traits::{LimitedDisplay, Locational, StructuralEq}; use erg_common::traits::{LimitedDisplay, Locational, StructuralEq};
use erg_common::{enum_unwrap, fmt_option, ref_addr_eq, set, Str}; use erg_common::{enum_unwrap, fmt_option, ref_addr_eq, set, Str};
use erg_parser::ast::Expr;
use erg_parser::token::TokenKind; use erg_parser::token::TokenKind;
pub use const_subr::*; pub use const_subr::*;
@ -59,8 +60,7 @@ pub trait HasType {
// 関数呼び出しの場合、.ref_t()は戻り値を返し、signature_t()は関数全体の型を返す // 関数呼び出しの場合、.ref_t()は戻り値を返し、signature_t()は関数全体の型を返す
fn signature_t(&self) -> Option<&Type>; fn signature_t(&self) -> Option<&Type>;
// 最後にHIR全体の型変数を消すために使う // 最後にHIR全体の型変数を消すために使う
/// `x.ref_mut_t()` may panic, in which case `x` is `Call` and `x.ref_t() == Type::Failure`. fn ref_mut_t(&mut self) -> Option<&mut Type>;
fn ref_mut_t(&mut self) -> &mut Type;
fn signature_mut_t(&mut self) -> Option<&mut Type>; fn signature_mut_t(&mut self) -> Option<&mut Type>;
#[inline] #[inline]
fn t(&self) -> Type { fn t(&self) -> Type {
@ -89,8 +89,8 @@ macro_rules! impl_t {
&self.t &self.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
&mut self.t Some(&mut self.t)
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {
@ -109,7 +109,7 @@ macro_rules! impl_t {
&self.$attr.ref_t() &self.$attr.ref_t()
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
self.$attr.ref_mut_t() self.$attr.ref_mut_t()
} }
#[inline] #[inline]
@ -133,7 +133,7 @@ macro_rules! impl_t_for_enum {
$($Enum::$Variant(v) => v.ref_t(),)* $($Enum::$Variant(v) => v.ref_t(),)*
} }
} }
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
match self { match self {
$($Enum::$Variant(v) => v.ref_mut_t(),)* $($Enum::$Variant(v) => v.ref_mut_t(),)*
} }
@ -752,80 +752,74 @@ impl ArgsOwnership {
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Variable { pub enum CastTarget {
Param { Param {
nth: usize, nth: usize,
name: Str, name: Str,
loc: Location, loc: Location,
}, },
Var { Var {
namespace: Str,
name: Str, name: Str,
loc: Location, loc: Location,
}, },
Attr { // NOTE: `Expr(Expr)` causes a bad memory access error
receiver: Box<Variable>, Expr(Box<Expr>),
attr: Str,
loc: Location,
},
} }
impl fmt::Display for Variable { impl fmt::Display for CastTarget {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self { match self {
Self::Param { nth, name, .. } => write!(f, "{name}#{nth}"), Self::Param { nth, name, .. } => write!(f, "{name}#{nth}"),
Self::Var { name, .. } => write!(f, "{name}"), Self::Var { name, .. } => write!(f, "{name}"),
Self::Attr { receiver, attr, .. } => write!(f, "{receiver}.{attr}"), Self::Expr(expr) => write!(f, "{expr}"),
} }
} }
} }
impl Locational for Variable { impl Locational for CastTarget {
fn loc(&self) -> Location { fn loc(&self) -> Location {
match self { match self {
Self::Param { loc, .. } => *loc, Self::Param { loc, .. } => *loc,
Self::Var { loc, .. } => *loc, Self::Var { loc, .. } => *loc,
Self::Attr { loc, .. } => *loc, Self::Expr(expr) => expr.loc(),
} }
} }
} }
impl Variable { impl CastTarget {
pub const fn param(nth: usize, name: Str, loc: Location) -> Self { pub const fn param(nth: usize, name: Str, loc: Location) -> Self {
Self::Param { nth, name, loc } Self::Param { nth, name, loc }
} }
pub fn attr(receiver: Variable, attr: Str, loc: Location) -> Self { pub fn expr(expr: Expr) -> Self {
Self::Attr { Self::Expr(Box::new(expr))
receiver: Box::new(receiver),
attr,
loc,
}
} }
} }
#[derive(Debug, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct GuardType { pub struct GuardType {
pub var: Variable, pub namespace: Str,
pub target: CastTarget,
pub to: Box<Type>, pub to: Box<Type>,
} }
impl fmt::Display for GuardType { impl fmt::Display for GuardType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{{} in {}}}", self.var, self.to) write!(f, "{{{} in {}}}", self.target, self.to)
} }
} }
impl StructuralEq for GuardType { impl StructuralEq for GuardType {
fn structural_eq(&self, other: &Self) -> bool { fn structural_eq(&self, other: &Self) -> bool {
self.var == other.var && self.to.structural_eq(&other.to) self.target == other.target && self.to.structural_eq(&other.to)
} }
} }
impl GuardType { impl GuardType {
pub fn new(var: Variable, to: Type) -> Self { pub fn new(namespace: Str, target: CastTarget, to: Type) -> Self {
Self { Self {
var, namespace,
target,
to: Box::new(to), to: Box::new(to),
} }
} }
@ -1359,8 +1353,8 @@ impl HasType for Type {
self self
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
self Some(self)
} }
fn inner_ts(&self) -> Vec<Type> { fn inner_ts(&self) -> Vec<Type> {
match self { match self {
@ -3107,9 +3101,11 @@ impl Type {
proj_call(lhs, attr_name.clone(), args) proj_call(lhs, attr_name.clone(), args)
} }
Self::Structural(ty) => ty.derefine().structuralize(), Self::Structural(ty) => ty.derefine().structuralize(),
Self::Guard(guard) => { Self::Guard(guard) => Self::Guard(GuardType::new(
Self::Guard(GuardType::new(guard.var.clone(), guard.to.derefine())) guard.namespace.clone(),
} guard.target.clone(),
guard.to.derefine(),
)),
Self::Bounded { sub, sup } => Self::Bounded { Self::Bounded { sub, sup } => Self::Bounded {
sub: Box::new(sub.derefine()), sub: Box::new(sub.derefine()),
sup: Box::new(sup.derefine()), sup: Box::new(sup.derefine()),
@ -3253,7 +3249,8 @@ impl Type {
} }
Self::Structural(ty) => ty._replace(target, to).structuralize(), Self::Structural(ty) => ty._replace(target, to).structuralize(),
Self::Guard(guard) => Self::Guard(GuardType::new( Self::Guard(guard) => Self::Guard(GuardType::new(
guard.var.clone(), guard.namespace,
guard.target.clone(),
guard.to._replace(target, to), guard.to._replace(target, to),
)), )),
Self::Bounded { sub, sup } => Self::Bounded { Self::Bounded { sub, sup } => Self::Bounded {
@ -3315,7 +3312,11 @@ impl Type {
Self::Or(l, r) => l.normalize() | r.normalize(), Self::Or(l, r) => l.normalize() | r.normalize(),
Self::Not(ty) => !ty.normalize(), Self::Not(ty) => !ty.normalize(),
Self::Structural(ty) => ty.normalize().structuralize(), Self::Structural(ty) => ty.normalize().structuralize(),
Self::Guard(guard) => Self::Guard(GuardType::new(guard.var, guard.to.normalize())), Self::Guard(guard) => Self::Guard(GuardType::new(
guard.namespace,
guard.target,
guard.to.normalize(),
)),
Self::Bounded { sub, sup } => Self::Bounded { Self::Bounded { sub, sup } => Self::Bounded {
sub: Box::new(sub.normalize()), sub: Box::new(sub.normalize()),
sup: Box::new(sup.normalize()), sup: Box::new(sup.normalize()),

View file

@ -880,8 +880,8 @@ impl HasType for ValueObj {
fn ref_t(&self) -> &Type { fn ref_t(&self) -> &Type {
panic!("cannot get reference of the const") panic!("cannot get reference of the const")
} }
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
panic!("cannot get mutable reference of the const") None
} }
/// その要素だけの集合型を返す、クラスが欲しい場合は.classで /// その要素だけの集合型を返す、クラスが欲しい場合は.classで
#[inline] #[inline]

View file

@ -216,8 +216,8 @@ impl HasType for VarInfo {
&self.t &self.t
} }
#[inline] #[inline]
fn ref_mut_t(&mut self) -> &mut Type { fn ref_mut_t(&mut self) -> Option<&mut Type> {
&mut self.t Some(&mut self.t)
} }
#[inline] #[inline]
fn signature_t(&self) -> Option<&Type> { fn signature_t(&self) -> Option<&Type> {

View file

@ -10,3 +10,8 @@ j = json.loads "{ \"a\": [1] }"
assert j in {Str: Obj} assert j in {Str: Obj}
assert j["a"] in Array(Int) assert j["a"] in Array(Int)
assert j["a"] notin Array(Str) assert j["a"] notin Array(Str)
_: Array(Int) = j["a"]
.f dic: {Str: Str or Array(Str)} =
assert dic["key"] in Str # Required to pass the check on the next line
assert dic["key"] in {"a", "b", "c"}