mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 10:49:54 +00:00
fix: type inference failure of as
operator
Now the `as` operator is a kind of type ascription, i.e., a special operator.
This commit is contained in:
parent
6cb4e75fea
commit
b3e09f213f
23 changed files with 435 additions and 318 deletions
|
@ -475,6 +475,7 @@ impl<Checker: BuildRunnable> Server<Checker> {
|
|||
self.file_cache.incremental_update(params.clone());
|
||||
if self.opt_features.contains(&OptionalFeatures::CheckOnType) {
|
||||
let uri = NormalizedUrl::new(params.text_document.uri);
|
||||
// TODO: reset mutable dependent types
|
||||
self.quick_check_file(uri)?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -1464,11 +1464,6 @@ impl PyCodeGenerator {
|
|||
self.emit_push_null();
|
||||
self.emit_load_name_instr(Identifier::private("#in_operator"));
|
||||
}
|
||||
// (x as T) == x
|
||||
TokenKind::AsOp => {
|
||||
self.emit_expr(*bin.lhs);
|
||||
return;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let lhs_t = bin
|
||||
|
|
|
@ -113,8 +113,8 @@ impl Context {
|
|||
return true;
|
||||
}
|
||||
(l, r) if l.has_unbound_var() || r.has_unbound_var() => {
|
||||
let lt = self.get_tp_t(l).unwrap();
|
||||
let rt = self.get_tp_t(r).unwrap();
|
||||
let Ok(lt) = self.get_tp_t(l) else { return false; };
|
||||
let Ok(rt) = self.get_tp_t(r) else { return false };
|
||||
return self.same_type_of(<, &rt);
|
||||
}
|
||||
_ => {}
|
||||
|
|
|
@ -618,10 +618,6 @@ impl Context {
|
|||
let op_t = bin_op(I, T, Bool).quantify();
|
||||
self.register_builtin_erg_impl(OP_IN, op_t.clone(), Const, Visibility::BUILTIN_PRIVATE);
|
||||
self.register_builtin_erg_impl(OP_NOT_IN, op_t, Const, Visibility::BUILTIN_PRIVATE);
|
||||
let Sub = mono_q(TY_SUB, instanceof(Type));
|
||||
let Sup = mono_q(TY_SUP, supertypeof(Sub.clone()));
|
||||
let op_t = bin_op(Sub, tp_enum(Type, set! { ty_tp(Sup.clone()) }), Sup).quantify();
|
||||
self.register_builtin_erg_impl(OP_AS, op_t, Const, Visibility::BUILTIN_PRIVATE);
|
||||
/* unary */
|
||||
// TODO: +/- Bool would like to be warned
|
||||
let M = mono_q(TY_M, subtypeof(mono(MUTIZABLE)));
|
||||
|
|
|
@ -346,7 +346,6 @@ const OP_DIV: &str = "__div__";
|
|||
const OP_FLOOR_DIV: &str = "__floordiv__";
|
||||
const OP_ABS: &str = "__abs__";
|
||||
const OP_PARTIAL_CMP: &str = "__partial_cmp__";
|
||||
const OP_AS: &str = "__as__";
|
||||
const OP_AND: &str = "__and__";
|
||||
const OP_OR: &str = "__or__";
|
||||
const OP_POW: &str = "__pow__";
|
||||
|
@ -406,8 +405,6 @@ const TY_L: &str = "L";
|
|||
const TY_N: &str = "N";
|
||||
const TY_M: &str = "M";
|
||||
const TY_O: &str = "O";
|
||||
const TY_SUB: &str = "Sub";
|
||||
const TY_SUP: &str = "Sup";
|
||||
|
||||
const KW_OLD: &str = "old";
|
||||
const KW_B: &str = "b";
|
||||
|
|
|
@ -128,23 +128,22 @@ impl Context {
|
|||
Ok(())
|
||||
}
|
||||
TypeBoundSpec::NonDefault { lhs, spec } => {
|
||||
let constr =
|
||||
match spec.op.kind {
|
||||
TokenKind::SubtypeOf => Constraint::new_subtype_of(
|
||||
self.instantiate_typespec(&spec.t_spec, None, tv_cache, mode, true)?,
|
||||
),
|
||||
TokenKind::SupertypeOf => Constraint::new_supertype_of(
|
||||
self.instantiate_typespec(&spec.t_spec, None, tv_cache, mode, true)?,
|
||||
),
|
||||
TokenKind::Colon => Constraint::new_type_of(self.instantiate_typespec(
|
||||
&spec.t_spec,
|
||||
None,
|
||||
tv_cache,
|
||||
mode,
|
||||
true,
|
||||
)?),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let constr = match spec.op.kind {
|
||||
TokenKind::SubtypeOf => Constraint::new_subtype_of(
|
||||
self.instantiate_typespec_full(&spec.t_spec, None, tv_cache, mode, true)?,
|
||||
),
|
||||
TokenKind::SupertypeOf => Constraint::new_supertype_of(
|
||||
self.instantiate_typespec_full(&spec.t_spec, None, tv_cache, mode, true)?,
|
||||
),
|
||||
TokenKind::Colon => Constraint::new_type_of(self.instantiate_typespec_full(
|
||||
&spec.t_spec,
|
||||
None,
|
||||
tv_cache,
|
||||
mode,
|
||||
true,
|
||||
)?),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
if constr.get_sub_sup().is_none() {
|
||||
let tp = TyParam::named_free_var(lhs.inspect().clone(), self.level, constr);
|
||||
tv_cache.push_or_init_typaram(lhs.inspect(), &tp, self);
|
||||
|
@ -205,7 +204,7 @@ impl Context {
|
|||
) -> TyCheckResult<Type> {
|
||||
let mut tmp_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t = if let Some(t_spec) = t_spec {
|
||||
self.instantiate_typespec(t_spec, None, &mut tmp_tv_cache, mode, false)?
|
||||
self.instantiate_typespec_full(t_spec, None, &mut tmp_tv_cache, mode, false)?
|
||||
} else {
|
||||
free_var(self.level, Constraint::new_type_of(Type))
|
||||
};
|
||||
|
@ -303,7 +302,7 @@ impl Context {
|
|||
let opt_decl_t = opt_decl_sig_t
|
||||
.as_ref()
|
||||
.map(|subr| ParamTy::Pos(subr.return_t.as_ref().clone()));
|
||||
match self.instantiate_typespec(
|
||||
match self.instantiate_typespec_full(
|
||||
t_spec,
|
||||
opt_decl_t.as_ref(),
|
||||
&mut tmp_tv_cache,
|
||||
|
@ -355,7 +354,13 @@ impl Context {
|
|||
free_var(level, Constraint::new_type_of(Type))
|
||||
};
|
||||
let spec_t = if let Some(spec_with_op) = &sig.t_spec {
|
||||
self.instantiate_typespec(&spec_with_op.t_spec, opt_decl_t, tmp_tv_cache, mode, false)?
|
||||
self.instantiate_typespec_full(
|
||||
&spec_with_op.t_spec,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
mode,
|
||||
false,
|
||||
)?
|
||||
} else {
|
||||
match &sig.pat {
|
||||
ast::ParamPattern::Lit(lit) => v_enum(set![self.eval_lit(lit)?]),
|
||||
|
@ -589,6 +594,13 @@ impl Context {
|
|||
line!(),
|
||||
))
|
||||
}),
|
||||
"True" | "False" | "None" => Err(TyCheckErrors::from(TyCheckError::not_a_type_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
simple.loc(),
|
||||
self.caused_by(),
|
||||
simple.ident.inspect(),
|
||||
))),
|
||||
other if simple.args.is_empty() => {
|
||||
if let Some(TyParam::Type(t)) = self.get_tp_from_tv_cache(other, tmp_tv_cache) {
|
||||
return Ok(*t);
|
||||
|
@ -638,14 +650,16 @@ impl Context {
|
|||
};
|
||||
// FIXME: kw args
|
||||
let mut new_params = vec![];
|
||||
for (i, arg) in simple.args.pos_args().enumerate() {
|
||||
let params = self.instantiate_const_expr(
|
||||
for ((i, arg), (name, param_vi)) in
|
||||
simple.args.pos_args().enumerate().zip(ctx.params.iter())
|
||||
{
|
||||
let param = self.instantiate_const_expr(
|
||||
&arg.expr,
|
||||
Some((ctx, i)),
|
||||
tmp_tv_cache,
|
||||
not_found_is_qvar,
|
||||
);
|
||||
let params = params.or_else(|e| {
|
||||
let param = param.or_else(|e| {
|
||||
if not_found_is_qvar {
|
||||
let name = arg.expr.to_string();
|
||||
// FIXME: handle `::` as a right way
|
||||
|
@ -661,7 +675,23 @@ impl Context {
|
|||
Err(e)
|
||||
}
|
||||
})?;
|
||||
new_params.push(params);
|
||||
let arg_t = self.get_tp_t(¶m).unwrap_or(Obj);
|
||||
if self.subtype_of(&arg_t, ¶m_vi.t) {
|
||||
new_params.push(param);
|
||||
} else {
|
||||
return Err(TyCheckErrors::from(TyCheckError::type_mismatch_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
arg.expr.loc(),
|
||||
self.caused_by(),
|
||||
name.as_ref().map_or("", |n| &n.inspect()[..]),
|
||||
Some(i),
|
||||
¶m_vi.t,
|
||||
&arg_t,
|
||||
None,
|
||||
None,
|
||||
)));
|
||||
}
|
||||
}
|
||||
// FIXME: non-builtin
|
||||
Ok(poly(Str::rc(other), new_params))
|
||||
|
@ -942,7 +972,7 @@ impl Context {
|
|||
tmp_tv_cache,
|
||||
not_found_is_qvar,
|
||||
)?;
|
||||
let spec_t = self.instantiate_typespec(
|
||||
let spec_t = self.instantiate_typespec_full(
|
||||
&tasc.t_spec.t_spec,
|
||||
None,
|
||||
tmp_tv_cache,
|
||||
|
@ -1041,12 +1071,12 @@ impl Context {
|
|||
tmp_tv_cache: &mut TyVarCache,
|
||||
mode: RegistrationMode,
|
||||
) -> TyCheckResult<ParamTy> {
|
||||
let t = self.instantiate_typespec(&p.ty, opt_decl_t, tmp_tv_cache, mode, false)?;
|
||||
let t = self.instantiate_typespec_full(&p.ty, opt_decl_t, tmp_tv_cache, mode, false)?;
|
||||
if let Some(default_t) = default_t {
|
||||
Ok(ParamTy::kw_default(
|
||||
p.name.as_ref().unwrap().inspect().to_owned(),
|
||||
t,
|
||||
self.instantiate_typespec(default_t, opt_decl_t, tmp_tv_cache, mode, false)?,
|
||||
self.instantiate_typespec_full(default_t, opt_decl_t, tmp_tv_cache, mode, false)?,
|
||||
))
|
||||
} else {
|
||||
Ok(ParamTy::pos_or_kw(
|
||||
|
@ -1056,7 +1086,7 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn instantiate_typespec(
|
||||
pub(crate) fn instantiate_typespec_full(
|
||||
&self,
|
||||
t_spec: &TypeSpec,
|
||||
opt_decl_t: Option<&ParamTy>,
|
||||
|
@ -1073,14 +1103,14 @@ impl Context {
|
|||
not_found_is_qvar,
|
||||
)?),
|
||||
TypeSpec::And(lhs, rhs) => Ok(self.intersection(
|
||||
&self.instantiate_typespec(
|
||||
&self.instantiate_typespec_full(
|
||||
lhs,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
mode,
|
||||
not_found_is_qvar,
|
||||
)?,
|
||||
&self.instantiate_typespec(
|
||||
&self.instantiate_typespec_full(
|
||||
rhs,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
|
@ -1089,14 +1119,14 @@ impl Context {
|
|||
)?,
|
||||
)),
|
||||
TypeSpec::Or(lhs, rhs) => Ok(self.union(
|
||||
&self.instantiate_typespec(
|
||||
&self.instantiate_typespec_full(
|
||||
lhs,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
mode,
|
||||
not_found_is_qvar,
|
||||
)?,
|
||||
&self.instantiate_typespec(
|
||||
&self.instantiate_typespec_full(
|
||||
rhs,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
|
@ -1104,7 +1134,7 @@ impl Context {
|
|||
not_found_is_qvar,
|
||||
)?,
|
||||
)),
|
||||
TypeSpec::Not(ty) => Ok(self.complement(&self.instantiate_typespec(
|
||||
TypeSpec::Not(ty) => Ok(self.complement(&self.instantiate_typespec_full(
|
||||
ty,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
|
@ -1112,7 +1142,7 @@ impl Context {
|
|||
not_found_is_qvar,
|
||||
)?)),
|
||||
TypeSpec::Array(arr) => {
|
||||
let elem_t = self.instantiate_typespec(
|
||||
let elem_t = self.instantiate_typespec_full(
|
||||
&arr.ty,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
|
@ -1127,7 +1157,7 @@ impl Context {
|
|||
Ok(array_t(elem_t, len))
|
||||
}
|
||||
TypeSpec::SetWithLen(set) => {
|
||||
let elem_t = self.instantiate_typespec(
|
||||
let elem_t = self.instantiate_typespec_full(
|
||||
&set.ty,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
|
@ -1144,7 +1174,7 @@ impl Context {
|
|||
TypeSpec::Tuple(tup) => {
|
||||
let mut inst_tys = vec![];
|
||||
for spec in tup.tys.iter() {
|
||||
inst_tys.push(self.instantiate_typespec(
|
||||
inst_tys.push(self.instantiate_typespec_full(
|
||||
spec,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
|
@ -1158,14 +1188,14 @@ impl Context {
|
|||
let mut inst_tys = dict! {};
|
||||
for (k, v) in dict {
|
||||
inst_tys.insert(
|
||||
self.instantiate_typespec(
|
||||
self.instantiate_typespec_full(
|
||||
k,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
mode,
|
||||
not_found_is_qvar,
|
||||
)?,
|
||||
self.instantiate_typespec(
|
||||
self.instantiate_typespec_full(
|
||||
v,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
|
@ -1181,7 +1211,7 @@ impl Context {
|
|||
for (k, v) in rec {
|
||||
inst_tys.insert(
|
||||
self.instantiate_field(k)?,
|
||||
self.instantiate_typespec(
|
||||
self.instantiate_typespec_full(
|
||||
v,
|
||||
opt_decl_t,
|
||||
tmp_tv_cache,
|
||||
|
@ -1261,7 +1291,7 @@ impl Context {
|
|||
})?
|
||||
.into_iter()
|
||||
.collect();
|
||||
let return_t = self.instantiate_typespec(
|
||||
let return_t = self.instantiate_typespec_full(
|
||||
&subr.return_t,
|
||||
opt_decl_t,
|
||||
tmp_tv_ctx,
|
||||
|
@ -1286,12 +1316,23 @@ impl Context {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn instantiate_field(&self, ident: &Identifier) -> TyCheckResult<Field> {
|
||||
pub(crate) fn instantiate_typespec(&self, t_spec: &ast::TypeSpec) -> TyCheckResult<Type> {
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
self.instantiate_typespec_full(
|
||||
t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn instantiate_field(&self, ident: &Identifier) -> TyCheckResult<Field> {
|
||||
let vis = self.instantiate_vis_modifier(&ident.vis)?;
|
||||
Ok(Field::new(vis, ident.inspect().clone()))
|
||||
}
|
||||
|
||||
pub fn instantiate_vis_modifier(
|
||||
pub(crate) fn instantiate_vis_modifier(
|
||||
&self,
|
||||
spec: &VisModifierSpec,
|
||||
) -> TyCheckResult<VisibilityModifier> {
|
||||
|
@ -1331,14 +1372,7 @@ impl Context {
|
|||
Ok(VisibilityModifier::Restricted(namespaces))
|
||||
}
|
||||
VisRestriction::SubtypeOf(typ) => {
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let t = self.instantiate_typespec(
|
||||
typ,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?;
|
||||
let t = self.instantiate_typespec(typ)?;
|
||||
Ok(VisibilityModifier::SubtypeRestricted(t))
|
||||
}
|
||||
},
|
||||
|
@ -1347,9 +1381,7 @@ impl Context {
|
|||
|
||||
pub(crate) fn expr_to_type(&self, expr: ast::Expr) -> Option<Type> {
|
||||
let t_spec = Parser::expr_to_type_spec(expr).ok()?;
|
||||
let mut dummy = TyVarCache::new(self.level, self);
|
||||
self.instantiate_typespec(&t_spec, None, &mut dummy, RegistrationMode::Normal, false)
|
||||
.ok()
|
||||
self.instantiate_typespec(&t_spec).ok()
|
||||
}
|
||||
|
||||
pub(crate) fn expr_to_value(&self, expr: ast::Expr) -> Option<ValueObj> {
|
||||
|
|
|
@ -143,7 +143,8 @@ impl Context {
|
|||
};
|
||||
let vis = self.instantiate_vis_modifier(&ident.vis)?;
|
||||
let kind = id.map_or(VarKind::Declared, VarKind::Defined);
|
||||
let sig_t = self.instantiate_var_sig_t(sig.t_spec.as_ref(), PreRegister)?;
|
||||
let sig_t =
|
||||
self.instantiate_var_sig_t(sig.t_spec.as_ref().map(|ts| &ts.t_spec), PreRegister)?;
|
||||
let py_name = if let ContextKind::PatchMethodDefs(_base) = &self.kind {
|
||||
Some(Str::from(format!("::{}{}", self.name, ident)))
|
||||
} else {
|
||||
|
@ -295,8 +296,16 @@ impl Context {
|
|||
} else {
|
||||
VarKind::Defined(id)
|
||||
};
|
||||
let t = sig.t_spec.as_ref().map_or(body_t.clone(), |ts| {
|
||||
if ts.ascription_kind().is_force_cast() {
|
||||
self.instantiate_typespec(&ts.t_spec)
|
||||
.unwrap_or(body_t.clone())
|
||||
} else {
|
||||
body_t.clone()
|
||||
}
|
||||
});
|
||||
let vi = VarInfo::new(
|
||||
body_t.clone(),
|
||||
t,
|
||||
muty,
|
||||
Visibility::new(vis, self.name.clone()),
|
||||
kind,
|
||||
|
@ -902,7 +911,7 @@ impl Context {
|
|||
if let Some(spec) = sig.return_t_spec.as_ref() {
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t = self
|
||||
.instantiate_typespec(
|
||||
.instantiate_typespec_full(
|
||||
spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
|
@ -944,8 +953,8 @@ impl Context {
|
|||
if let Some(spec) = sig.t_spec.as_ref() {
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.level, self);
|
||||
let spec_t = self
|
||||
.instantiate_typespec(
|
||||
spec,
|
||||
.instantiate_typespec_full(
|
||||
&spec.t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
PreRegister,
|
||||
|
|
|
@ -689,13 +689,15 @@ impl Context {
|
|||
let (l, r) = union.union_pair().unwrap_or((lsub, rsub));
|
||||
let unified = self.unify(&l, &r);
|
||||
if unified.is_none() {
|
||||
let maybe_sub = self.readable_type(maybe_sub.clone());
|
||||
let union = self.readable_type(union);
|
||||
return Err(TyCheckErrors::from(TyCheckError::implicit_widening_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
loc.loc(),
|
||||
self.caused_by(),
|
||||
maybe_sub,
|
||||
maybe_sup,
|
||||
&maybe_sub,
|
||||
&union,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
@ -800,14 +802,16 @@ impl Context {
|
|||
let (l, r) = new_sub.union_pair().unwrap_or((maybe_sub.clone(), sub));
|
||||
let unified = self.unify(&l, &r);
|
||||
if unified.is_none() {
|
||||
let maybe_sub = self.readable_type(maybe_sub.clone());
|
||||
let new_sub = self.readable_type(new_sub);
|
||||
return Err(TyCheckErrors::from(
|
||||
TyCheckError::implicit_widening_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
loc.loc(),
|
||||
self.caused_by(),
|
||||
maybe_sub,
|
||||
maybe_sup,
|
||||
&maybe_sub,
|
||||
&new_sub,
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
use erg_common::traits::{Locational, Runnable, Stream};
|
||||
use erg_common::{enum_unwrap, fn_name, log, set, Str};
|
||||
|
||||
use erg_parser::ast::{self, Identifier, VarName, AST};
|
||||
use erg_parser::ast::{self, AscriptionKind, Identifier, VarName, AST};
|
||||
|
||||
use crate::context::instantiate::TyVarCache;
|
||||
use crate::lower::ASTLowerer;
|
||||
use crate::ty::constructors::{mono, v_enum};
|
||||
use crate::ty::free::HasLevel;
|
||||
|
@ -11,7 +10,6 @@ use crate::ty::value::{GenTypeObj, TypeObj, ValueObj};
|
|||
use crate::ty::{HasType, Type, Visibility};
|
||||
|
||||
use crate::compile::AccessKind;
|
||||
use crate::context::RegistrationMode;
|
||||
use crate::error::{LowerError, LowerErrors, LowerResult};
|
||||
use crate::hir;
|
||||
use crate::hir::HIR;
|
||||
|
@ -33,15 +31,7 @@ impl ASTLowerer {
|
|||
)));
|
||||
}
|
||||
let opt_spec_t = if let Some(t_spec) = &sig.t_spec {
|
||||
let mut dummy_tv_cache =
|
||||
TyVarCache::new(self.module.context.level, &self.module.context);
|
||||
let t = self.module.context.instantiate_typespec(
|
||||
t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?;
|
||||
let t = self.module.context.instantiate_typespec(&t_spec.t_spec)?;
|
||||
t.lift();
|
||||
Some(self.module.context.generalize_t(t))
|
||||
} else {
|
||||
|
@ -97,7 +87,14 @@ impl ASTLowerer {
|
|||
ident.vi.t = t;
|
||||
ident.vi.py_name = py_name;
|
||||
ident.vi.def_loc = self.module.context.absolutize(ident.raw.name.loc());
|
||||
let sig = hir::VarSignature::new(ident, sig.t_spec);
|
||||
let t_spec = if let Some(ts) = sig.t_spec {
|
||||
let spec_t = self.module.context.instantiate_typespec(&ts.t_spec)?;
|
||||
let expr = self.fake_lower_expr(*ts.t_spec_as_expr.clone())?;
|
||||
Some(hir::TypeSpecWithOp::new(ts, expr, spec_t))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let sig = hir::VarSignature::new(ident, t_spec);
|
||||
let body = hir::DefBody::new(body.op, hir::Block::new(vec![chunk]), body.id);
|
||||
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
||||
}
|
||||
|
@ -262,7 +259,13 @@ impl ASTLowerer {
|
|||
ast::Signature::Var(var) => {
|
||||
let ident = var.ident().unwrap().clone();
|
||||
let ident = hir::Identifier::bare(ident);
|
||||
let sig = hir::VarSignature::new(ident, var.t_spec);
|
||||
let t_spec = if let Some(ts) = var.t_spec {
|
||||
let expr = self.fake_lower_expr(*ts.t_spec_as_expr.clone())?;
|
||||
Some(hir::TypeSpecWithOp::new(ts, expr, Type::Failure))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let sig = hir::VarSignature::new(ident, t_spec);
|
||||
Ok(hir::Signature::Var(sig))
|
||||
}
|
||||
ast::Signature::Subr(subr) => {
|
||||
|
@ -312,12 +315,17 @@ impl ASTLowerer {
|
|||
elems,
|
||||
)))
|
||||
}
|
||||
other => Err(LowerErrors::from(LowerError::declare_error(
|
||||
self.cfg().input.clone(),
|
||||
line!() as usize,
|
||||
other.loc(),
|
||||
self.module.context.caused_by(),
|
||||
))),
|
||||
ast::Set::WithLength(set) => {
|
||||
let len = self.fake_lower_expr(*set.len)?;
|
||||
let elem = self.fake_lower_expr(set.elem.expr)?;
|
||||
Ok(hir::Set::WithLength(hir::SetWithLength::new(
|
||||
set.l_brace,
|
||||
set.r_brace,
|
||||
Type::Failure,
|
||||
len,
|
||||
elem,
|
||||
)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,17 +412,12 @@ impl ASTLowerer {
|
|||
|
||||
fn fake_lower_type_asc(&self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
|
||||
let expr = self.fake_lower_expr(*tasc.expr)?;
|
||||
let t_spec_as_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr)?;
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context);
|
||||
let spec_t = self.module.context.instantiate_typespec(
|
||||
&tasc.t_spec.t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?;
|
||||
let spec =
|
||||
hir::TypeSpecWithOp::new(tasc.t_spec.op, tasc.t_spec.t_spec, t_spec_as_expr, spec_t);
|
||||
let t_spec_as_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr.clone())?;
|
||||
let spec_t = self
|
||||
.module
|
||||
.context
|
||||
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
||||
let spec = hir::TypeSpecWithOp::new(tasc.t_spec, t_spec_as_expr, spec_t);
|
||||
Ok(hir::TypeAscription::new(expr, spec))
|
||||
}
|
||||
|
||||
|
@ -445,24 +448,26 @@ impl ASTLowerer {
|
|||
|
||||
fn declare_ident(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
|
||||
log!(info "entered {}({})", fn_name!(), tasc);
|
||||
let is_instance_ascription = tasc.is_instance_ascription();
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context);
|
||||
let kind = tasc.kind();
|
||||
match *tasc.expr {
|
||||
ast::Expr::Accessor(ast::Accessor::Ident(ident)) => {
|
||||
let py_name = Str::rc(ident.inspect().trim_end_matches('!'));
|
||||
let t = self.module.context.instantiate_typespec(
|
||||
&tasc.t_spec.t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?;
|
||||
let t = self
|
||||
.module
|
||||
.context
|
||||
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
||||
t.lift();
|
||||
let t = self.module.context.generalize_t(t);
|
||||
if is_instance_ascription {
|
||||
self.declare_instance(&ident, &t, py_name.clone())?;
|
||||
} else {
|
||||
self.declare_subtype(&ident, &t)?;
|
||||
match kind {
|
||||
AscriptionKind::TypeOf | AscriptionKind::AsCast => {
|
||||
self.declare_instance(&ident, &t, py_name.clone())?;
|
||||
}
|
||||
AscriptionKind::SubtypeOf => {
|
||||
self.declare_subtype(&ident, &t)?;
|
||||
}
|
||||
_ => {
|
||||
log!(err "supertype ascription is not supported yet");
|
||||
}
|
||||
}
|
||||
let muty = Mutability::from(&ident.inspect()[..]);
|
||||
let vis = self.module.context.instantiate_vis_modifier(&ident.vis)?;
|
||||
|
@ -477,24 +482,16 @@ impl ASTLowerer {
|
|||
self.module.context.absolutize(ident.name.loc()),
|
||||
);
|
||||
let ident = hir::Identifier::new(ident, None, vi);
|
||||
let t_spec_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr)?;
|
||||
let t_spec = hir::TypeSpecWithOp::new(
|
||||
tasc.t_spec.op,
|
||||
tasc.t_spec.t_spec,
|
||||
t_spec_expr,
|
||||
Type::Failure,
|
||||
);
|
||||
let t_spec_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr.clone())?;
|
||||
let t_spec = hir::TypeSpecWithOp::new(tasc.t_spec, t_spec_expr, Type::Failure);
|
||||
Ok(hir::Expr::Accessor(hir::Accessor::Ident(ident)).type_asc(t_spec))
|
||||
}
|
||||
ast::Expr::Accessor(ast::Accessor::Attr(attr)) => {
|
||||
let py_name = Str::rc(attr.ident.inspect().trim_end_matches('!'));
|
||||
let t = self.module.context.instantiate_typespec(
|
||||
&tasc.t_spec.t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?;
|
||||
let t = self
|
||||
.module
|
||||
.context
|
||||
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
||||
let ctx = self
|
||||
.module
|
||||
.context
|
||||
|
@ -523,13 +520,8 @@ impl ASTLowerer {
|
|||
);
|
||||
let ident = hir::Identifier::new(attr.ident, None, vi);
|
||||
let attr = obj.attr_expr(ident);
|
||||
let t_spec_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr)?;
|
||||
let t_spec = hir::TypeSpecWithOp::new(
|
||||
tasc.t_spec.op,
|
||||
tasc.t_spec.t_spec,
|
||||
t_spec_expr,
|
||||
Type::Failure,
|
||||
);
|
||||
let t_spec_expr = self.fake_lower_expr(*tasc.t_spec.t_spec_as_expr.clone())?;
|
||||
let t_spec = hir::TypeSpecWithOp::new(tasc.t_spec, t_spec_expr, Type::Failure);
|
||||
Ok(attr.type_asc(t_spec))
|
||||
}
|
||||
other => Err(LowerErrors::from(LowerError::declare_error(
|
||||
|
|
|
@ -368,6 +368,42 @@ impl LowerError {
|
|||
)
|
||||
}
|
||||
|
||||
pub fn not_a_type_error(
|
||||
input: Input,
|
||||
errno: usize,
|
||||
loc: Location,
|
||||
caused_by: String,
|
||||
name: &str,
|
||||
) -> Self {
|
||||
let name = readable_name(name);
|
||||
let hint = {
|
||||
let n = StyledStr::new(name, Some(HINT), Some(ATTR));
|
||||
Some(switch_lang!(
|
||||
"japanese" => format!("{{{n}}}({n}のみを要素に持つ型)ではありませんか?"),
|
||||
"simplified_chinese" => format!("{{{n}}}({n}的元素只有{n})是不是?"),
|
||||
"traditional_chinese" => format!("{{{n}}}({n}的元素只有{n})是不是?"),
|
||||
"english" => format!("Do you mean {{{n}}}, a type that has only {n}?"),
|
||||
))
|
||||
};
|
||||
let found = StyledString::new(name, Some(ERR), Some(ATTR));
|
||||
Self::new(
|
||||
ErrorCore::new(
|
||||
vec![SubMessage::ambiguous_new(loc, vec![], hint)],
|
||||
switch_lang!(
|
||||
"japanese" => format!("{found}は型ではありません"),
|
||||
"simplified_chinese" => format!("{found}不是类型"),
|
||||
"traditional_chinese" => format!("{found}不是類型"),
|
||||
"english" => format!("{found} is not a type"),
|
||||
),
|
||||
errno,
|
||||
TypeError,
|
||||
loc,
|
||||
),
|
||||
input,
|
||||
caused_by,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn type_not_found(
|
||||
input: Input,
|
||||
errno: usize,
|
||||
|
|
|
@ -1223,21 +1223,22 @@ passed keyword args: {kw_args_len}"
|
|||
errno: usize,
|
||||
loc: Location,
|
||||
caused_by: String,
|
||||
expect: &Type,
|
||||
found: &Type,
|
||||
before: &Type,
|
||||
after: &Type,
|
||||
) -> Self {
|
||||
let maybe_sub_ = expect
|
||||
let before_ = before
|
||||
.to_string()
|
||||
.with_color(erg_common::style::Color::Yellow);
|
||||
let new_sub = found
|
||||
let after_ = after
|
||||
.to_string()
|
||||
.with_color(erg_common::style::Color::Yellow);
|
||||
let hint = switch_lang!(
|
||||
"japanese" => format!("{maybe_sub_}から{new_sub}への暗黙の型拡大はデフォルトでは禁止されています。明示的に型指定してください"),
|
||||
"simplified_chinese" => format!("隐式扩展{maybe_sub_}到{new_sub}被默认禁止。请明确指定类型。"),
|
||||
"traditional_chinese" => format!("隱式擴展{maybe_sub_}到{new_sub}被默認禁止。請明確指定類型。"),
|
||||
"english" => format!("Implicitly widening {maybe_sub_} to {new_sub} is prohibited by default. Consider specifying the type explicitly."),
|
||||
"japanese" => format!("{before_}から{after_}への暗黙の型拡大はデフォルトでは禁止されています。`as`などを使って明示的に型拡大してください"),
|
||||
"simplified_chinese" => format!("隐式扩展{before_}到{after_}被默认禁止。请使用`as`显式扩展类型。"),
|
||||
"traditional_chinese" => format!("隱式擴展{before_}到{after_}被默認禁止。請使用`as`顯式擴展類型。"),
|
||||
"english" => format!("Implicitly widening {before_} to {after_} is prohibited by default. Consider widening the type explicitly using `as`."),
|
||||
);
|
||||
// actually, this error will be overwritten, only `input`, `hint` and `loc` is useful
|
||||
Self::type_mismatch_error(
|
||||
input,
|
||||
errno,
|
||||
|
@ -1245,8 +1246,8 @@ passed keyword args: {kw_args_len}"
|
|||
caused_by,
|
||||
"",
|
||||
None,
|
||||
expect,
|
||||
found,
|
||||
&Type::Uninited,
|
||||
&Type::Uninited,
|
||||
None,
|
||||
Some(hint),
|
||||
)
|
||||
|
|
|
@ -13,7 +13,7 @@ use erg_common::{
|
|||
impl_nested_display_for_enum, impl_no_type_display_for_enum, impl_stream,
|
||||
};
|
||||
|
||||
use erg_parser::ast;
|
||||
use erg_parser::ast::{self, AscriptionKind};
|
||||
use erg_parser::ast::{
|
||||
fmt_lines, DefId, DefKind, OperationKind, TypeBoundSpecs, TypeSpec, VarName,
|
||||
};
|
||||
|
@ -1547,7 +1547,7 @@ impl Locational for Dummy {
|
|||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct VarSignature {
|
||||
pub ident: Identifier,
|
||||
pub t_spec: Option<TypeSpec>,
|
||||
pub t_spec: Option<TypeSpecWithOp>,
|
||||
}
|
||||
|
||||
impl NestedDisplay for VarSignature {
|
||||
|
@ -1579,7 +1579,7 @@ impl HasType for VarSignature {
|
|||
}
|
||||
|
||||
impl VarSignature {
|
||||
pub const fn new(ident: Identifier, t_spec: Option<TypeSpec>) -> Self {
|
||||
pub const fn new(ident: Identifier, t_spec: Option<TypeSpecWithOp>) -> Self {
|
||||
Self { ident, t_spec }
|
||||
}
|
||||
|
||||
|
@ -2006,7 +2006,7 @@ impl Signature {
|
|||
|
||||
pub fn t_spec(&self) -> Option<&TypeSpec> {
|
||||
match self {
|
||||
Self::Var(v) => v.t_spec.as_ref(),
|
||||
Self::Var(v) => v.t_spec.as_ref().map(|t| &t.raw.t_spec),
|
||||
Self::Subr(s) => s.return_t_spec.as_ref(),
|
||||
}
|
||||
}
|
||||
|
@ -2352,30 +2352,39 @@ impl ReDef {
|
|||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct TypeSpecWithOp {
|
||||
pub op: Token,
|
||||
pub t_spec: TypeSpec,
|
||||
pub t_spec_as_expr: Box<Expr>,
|
||||
pub raw: ast::TypeSpecWithOp,
|
||||
/// Required for dynamic type checking
|
||||
pub expr: Box<Expr>,
|
||||
pub spec_t: Type,
|
||||
}
|
||||
|
||||
impl NestedDisplay for TypeSpecWithOp {
|
||||
fn fmt_nest(&self, f: &mut fmt::Formatter<'_>, _level: usize) -> fmt::Result {
|
||||
write!(f, "{} {}", self.op.content, self.t_spec)
|
||||
write!(f, "{}", self.raw)
|
||||
}
|
||||
}
|
||||
|
||||
impl_display_from_nested!(TypeSpecWithOp);
|
||||
impl_locational!(TypeSpecWithOp, lossy op, t_spec);
|
||||
impl_locational!(TypeSpecWithOp, raw);
|
||||
|
||||
impl TypeSpecWithOp {
|
||||
pub fn new(op: Token, t_spec: TypeSpec, t_spec_as_expr: Expr, spec_t: Type) -> Self {
|
||||
pub fn new(raw: ast::TypeSpecWithOp, expr: Expr, spec_t: Type) -> Self {
|
||||
Self {
|
||||
op,
|
||||
t_spec,
|
||||
t_spec_as_expr: Box::new(t_spec_as_expr),
|
||||
raw,
|
||||
expr: Box::new(expr),
|
||||
spec_t,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> AscriptionKind {
|
||||
match self.raw.op.kind {
|
||||
TokenKind::Colon => AscriptionKind::TypeOf,
|
||||
TokenKind::SubtypeOf => AscriptionKind::SubtypeOf,
|
||||
TokenKind::SupertypeOf => AscriptionKind::SupertypeOf,
|
||||
TokenKind::As => AscriptionKind::AsCast,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -2402,11 +2411,19 @@ impl_locational!(TypeAscription, expr, spec);
|
|||
impl HasType for TypeAscription {
|
||||
#[inline]
|
||||
fn ref_t(&self) -> &Type {
|
||||
self.expr.ref_t()
|
||||
if self.spec.kind().is_force_cast() {
|
||||
&self.spec.spec_t
|
||||
} else {
|
||||
self.expr.ref_t()
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn ref_mut_t(&mut self) -> &mut Type {
|
||||
self.expr.ref_mut_t()
|
||||
if self.spec.kind().is_force_cast() {
|
||||
&mut self.spec.spec_t
|
||||
} else {
|
||||
self.expr.ref_mut_t()
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn signature_t(&self) -> Option<&Type> {
|
||||
|
|
|
@ -14,7 +14,7 @@ use erg_common::traits::{ExitStatus, Locational, NoTypeDisplay, Runnable, Stream
|
|||
use erg_common::triple::Triple;
|
||||
use erg_common::{fmt_option, fn_name, log, switch_lang, Str};
|
||||
|
||||
use erg_parser::ast::{self, VisModifierSpec};
|
||||
use erg_parser::ast::{self, AscriptionKind, VisModifierSpec};
|
||||
use erg_parser::ast::{OperationKind, TypeSpecWithOp, VarName, AST};
|
||||
use erg_parser::build_ast::ASTBuilder;
|
||||
use erg_parser::token::{Token, TokenKind};
|
||||
|
@ -1097,13 +1097,8 @@ impl ASTLowerer {
|
|||
type_spec_with_op: ast::TypeSpecWithOp,
|
||||
spec_t: Type,
|
||||
) -> LowerResult<hir::TypeSpecWithOp> {
|
||||
let expr = self.fake_lower_expr(*type_spec_with_op.t_spec_as_expr)?;
|
||||
Ok(hir::TypeSpecWithOp::new(
|
||||
type_spec_with_op.op,
|
||||
type_spec_with_op.t_spec,
|
||||
expr,
|
||||
spec_t,
|
||||
))
|
||||
let expr = self.fake_lower_expr(*type_spec_with_op.t_spec_as_expr.clone())?;
|
||||
Ok(hir::TypeSpecWithOp::new(type_spec_with_op, expr, spec_t))
|
||||
}
|
||||
|
||||
fn lower_params(&mut self, params: ast::Params) -> LowerResult<hir::Params> {
|
||||
|
@ -1419,7 +1414,7 @@ impl ASTLowerer {
|
|||
.module
|
||||
.context
|
||||
.instantiate_var_sig_t(
|
||||
sig.t_spec.as_ref(),
|
||||
sig.t_spec.as_ref().map(|ts| &ts.t_spec),
|
||||
RegistrationMode::PreRegister,
|
||||
)
|
||||
.ok();
|
||||
|
@ -1453,7 +1448,14 @@ impl ASTLowerer {
|
|||
None,
|
||||
)?;
|
||||
let ident = hir::Identifier::new(ident, None, vi);
|
||||
let sig = hir::VarSignature::new(ident, sig.t_spec);
|
||||
let t_spec = if let Some(ts) = sig.t_spec {
|
||||
let spec_t = self.module.context.instantiate_typespec(&ts.t_spec)?;
|
||||
let expr = self.fake_lower_expr(*ts.t_spec_as_expr.clone())?;
|
||||
Some(hir::TypeSpecWithOp::new(ts, expr, spec_t))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let sig = hir::VarSignature::new(ident, t_spec);
|
||||
let body = hir::DefBody::new(body.op, block, body.id);
|
||||
Ok(hir::Def::new(hir::Signature::Var(sig), body))
|
||||
}
|
||||
|
@ -1703,7 +1705,7 @@ impl ASTLowerer {
|
|||
let (impl_trait, t_spec) = match &args.pos_args().first().unwrap().expr {
|
||||
// TODO: check `tasc.op`
|
||||
ast::Expr::TypeAscription(tasc) => (
|
||||
self.module.context.instantiate_typespec(
|
||||
self.module.context.instantiate_typespec_full(
|
||||
&tasc.t_spec.t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
|
@ -1724,7 +1726,7 @@ impl ASTLowerer {
|
|||
}
|
||||
};
|
||||
Ok((
|
||||
self.module.context.instantiate_typespec(
|
||||
self.module.context.instantiate_typespec_full(
|
||||
spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
|
@ -1735,7 +1737,7 @@ impl ASTLowerer {
|
|||
))
|
||||
}
|
||||
ast::TypeAppArgsKind::SubtypeOf(trait_spec) => {
|
||||
let impl_trait = self.module.context.instantiate_typespec(
|
||||
let impl_trait = self.module.context.instantiate_typespec_full(
|
||||
&trait_spec.t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
|
@ -1743,7 +1745,7 @@ impl ASTLowerer {
|
|||
false,
|
||||
)?;
|
||||
Ok((
|
||||
self.module.context.instantiate_typespec(
|
||||
self.module.context.instantiate_typespec_full(
|
||||
spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
|
@ -1756,7 +1758,7 @@ impl ASTLowerer {
|
|||
}
|
||||
}
|
||||
other => Ok((
|
||||
self.module.context.instantiate_typespec(
|
||||
self.module.context.instantiate_typespec_full(
|
||||
other,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
|
@ -1776,15 +1778,7 @@ impl ASTLowerer {
|
|||
};
|
||||
let base_t_expr = call.args.get_left_or_key("Base").unwrap();
|
||||
let spec = Parser::expr_to_type_spec(base_t_expr.clone()).unwrap();
|
||||
let mut dummy_tv_cache =
|
||||
TyVarCache::new(self.module.context.level, &self.module.context);
|
||||
self.module.context.instantiate_typespec(
|
||||
&spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?
|
||||
self.module.context.instantiate_typespec(&spec)?
|
||||
};
|
||||
let mut hir_def = self.lower_def(class_def.def)?;
|
||||
let base = Self::get_require_or_sup_or_base(hir_def.body.block.remove(0)).unwrap();
|
||||
|
@ -2168,44 +2162,43 @@ impl ASTLowerer {
|
|||
|
||||
fn lower_type_asc(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
|
||||
log!(info "entered {}({tasc})", fn_name!());
|
||||
let is_instance_ascription = tasc.is_instance_ascription();
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context);
|
||||
let spec_t = self.module.context.instantiate_typespec(
|
||||
&tasc.t_spec.t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?;
|
||||
let kind = tasc.kind();
|
||||
let spec_t = self
|
||||
.module
|
||||
.context
|
||||
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
||||
let expr = self.lower_expr(*tasc.expr)?;
|
||||
if is_instance_ascription {
|
||||
self.module.context.sub_unify(
|
||||
expr.ref_t(),
|
||||
&spec_t,
|
||||
&expr,
|
||||
Some(&Str::from(expr.to_string())),
|
||||
)?;
|
||||
} else {
|
||||
// if subtype ascription
|
||||
let &ctx = self
|
||||
.module
|
||||
.context
|
||||
.get_singular_ctxs_by_hir_expr(&expr, &self.module.context)?
|
||||
.first()
|
||||
.unwrap();
|
||||
// REVIEW: need to use subtype_of?
|
||||
if ctx.super_traits.iter().all(|trait_| trait_ != &spec_t)
|
||||
&& ctx.super_classes.iter().all(|class| class != &spec_t)
|
||||
{
|
||||
return Err(LowerErrors::from(LowerError::subtyping_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
expr.ref_t(), // FIXME:
|
||||
match kind {
|
||||
AscriptionKind::TypeOf | AscriptionKind::AsCast => {
|
||||
self.module.context.sub_unify(
|
||||
expr.ref_t(),
|
||||
&spec_t,
|
||||
Location::concat(&expr, &tasc.t_spec),
|
||||
self.module.context.caused_by(),
|
||||
)));
|
||||
&expr,
|
||||
Some(&Str::from(expr.to_string())),
|
||||
)?;
|
||||
}
|
||||
AscriptionKind::SubtypeOf => {
|
||||
let &ctx = self
|
||||
.module
|
||||
.context
|
||||
.get_singular_ctxs_by_hir_expr(&expr, &self.module.context)?
|
||||
.first()
|
||||
.unwrap();
|
||||
// REVIEW: need to use subtype_of?
|
||||
if ctx.super_traits.iter().all(|trait_| trait_ != &spec_t)
|
||||
&& ctx.super_classes.iter().all(|class| class != &spec_t)
|
||||
{
|
||||
return Err(LowerErrors::from(LowerError::subtyping_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
expr.ref_t(), // FIXME:
|
||||
&spec_t,
|
||||
Location::concat(&expr, &tasc.t_spec),
|
||||
self.module.context.caused_by(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let t_spec = self.lower_type_spec_with_op(tasc.t_spec, spec_t)?;
|
||||
Ok(expr.type_asc(t_spec))
|
||||
|
@ -2213,15 +2206,11 @@ impl ASTLowerer {
|
|||
|
||||
fn lower_decl(&mut self, tasc: ast::TypeAscription) -> LowerResult<hir::TypeAscription> {
|
||||
log!(info "entered {}({tasc})", fn_name!());
|
||||
let is_instance_ascription = tasc.is_instance_ascription();
|
||||
let mut dummy_tv_cache = TyVarCache::new(self.module.context.level, &self.module.context);
|
||||
let spec_t = self.module.context.instantiate_typespec(
|
||||
&tasc.t_spec.t_spec,
|
||||
None,
|
||||
&mut dummy_tv_cache,
|
||||
RegistrationMode::Normal,
|
||||
false,
|
||||
)?;
|
||||
let kind = tasc.kind();
|
||||
let spec_t = self
|
||||
.module
|
||||
.context
|
||||
.instantiate_typespec(&tasc.t_spec.t_spec)?;
|
||||
let ast::Expr::Accessor(ast::Accessor::Ident(ident)) = *tasc.expr else {
|
||||
return Err(LowerErrors::from(LowerError::syntax_error(
|
||||
self.cfg.input.clone(),
|
||||
|
@ -2270,22 +2259,28 @@ impl ASTLowerer {
|
|||
similar_info,
|
||||
)
|
||||
})?;
|
||||
if is_instance_ascription {
|
||||
self.module
|
||||
.context
|
||||
.sub_unify(&ident_vi.t, &spec_t, &ident, Some(ident.inspect()))?;
|
||||
} else {
|
||||
// if subtype ascription
|
||||
if self.module.context.subtype_of(&ident_vi.t, &spec_t) {
|
||||
return Err(LowerErrors::from(LowerError::subtyping_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
match kind {
|
||||
AscriptionKind::TypeOf | AscriptionKind::AsCast => {
|
||||
self.module.context.sub_unify(
|
||||
&ident_vi.t,
|
||||
&spec_t,
|
||||
ident.loc(),
|
||||
self.module.context.caused_by(),
|
||||
)));
|
||||
&ident,
|
||||
Some(ident.inspect()),
|
||||
)?;
|
||||
}
|
||||
AscriptionKind::SubtypeOf => {
|
||||
if self.module.context.subtype_of(&ident_vi.t, &spec_t) {
|
||||
return Err(LowerErrors::from(LowerError::subtyping_error(
|
||||
self.cfg.input.clone(),
|
||||
line!() as usize,
|
||||
&ident_vi.t,
|
||||
&spec_t,
|
||||
ident.loc(),
|
||||
self.module.context.caused_by(),
|
||||
)));
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
let qual_name = self
|
||||
.module
|
||||
|
|
|
@ -1909,7 +1909,6 @@ impl ConstTypeAsc {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum ConstExpr {
|
||||
Lit(Literal),
|
||||
Erased(Literal), // _
|
||||
Accessor(ConstAccessor),
|
||||
App(ConstApp),
|
||||
Array(ConstArray),
|
||||
|
@ -1924,9 +1923,9 @@ pub enum ConstExpr {
|
|||
TypeAsc(ConstTypeAsc),
|
||||
}
|
||||
|
||||
impl_nested_display_for_chunk_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Erased, Set, TypeAsc);
|
||||
impl_nested_display_for_chunk_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Set, TypeAsc);
|
||||
impl_display_from_nested!(ConstExpr);
|
||||
impl_locational_for_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Erased, Set, TypeAsc);
|
||||
impl_locational_for_enum!(ConstExpr; Lit, Accessor, App, Array, Set, Dict, Tuple, Record, BinOp, UnaryOp, Def, Lambda, Set, TypeAsc);
|
||||
|
||||
impl ConstExpr {
|
||||
pub fn need_to_be_closed(&self) -> bool {
|
||||
|
@ -1948,7 +1947,6 @@ impl ConstExpr {
|
|||
Self::BinOp(binop) => Expr::BinOp(binop.downcast()),
|
||||
Self::UnaryOp(unop) => Expr::UnaryOp(unop.downcast()),
|
||||
Self::TypeAsc(type_asc) => Expr::TypeAscription(type_asc.downcast()),
|
||||
Self::Erased(lit) => Expr::Dummy(Dummy::new(Some(lit.loc()), vec![])),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2529,6 +2527,7 @@ impl TypeSpec {
|
|||
pub struct TypeSpecWithOp {
|
||||
pub op: Token,
|
||||
pub t_spec: TypeSpec,
|
||||
/// Required for dynamic type checking
|
||||
pub t_spec_as_expr: Box<Expr>,
|
||||
}
|
||||
|
||||
|
@ -2549,6 +2548,16 @@ impl TypeSpecWithOp {
|
|||
t_spec_as_expr: Box::new(t_spec_as_expr),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ascription_kind(&self) -> AscriptionKind {
|
||||
match self.op.kind {
|
||||
TokenKind::Colon => AscriptionKind::TypeOf,
|
||||
TokenKind::SubtypeOf => AscriptionKind::SubtypeOf,
|
||||
TokenKind::SupertypeOf => AscriptionKind::SupertypeOf,
|
||||
TokenKind::As => AscriptionKind::AsCast,
|
||||
kind => todo!("{kind}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
|
@ -3095,6 +3104,7 @@ impl VarRecordPattern {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct VarDataPackPattern {
|
||||
pub class: TypeSpec,
|
||||
pub class_as_expr: Box<Expr>,
|
||||
pub args: VarRecordPattern,
|
||||
}
|
||||
|
||||
|
@ -3107,8 +3117,12 @@ impl fmt::Display for VarDataPackPattern {
|
|||
impl_locational!(VarDataPackPattern, class, args);
|
||||
|
||||
impl VarDataPackPattern {
|
||||
pub const fn new(class: TypeSpec, args: VarRecordPattern) -> Self {
|
||||
Self { class, args }
|
||||
pub const fn new(class: TypeSpec, class_as_expr: Box<Expr>, args: VarRecordPattern) -> Self {
|
||||
Self {
|
||||
class,
|
||||
class_as_expr,
|
||||
args,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3185,7 +3199,7 @@ impl VarPattern {
|
|||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct VarSignature {
|
||||
pub pat: VarPattern,
|
||||
pub t_spec: Option<TypeSpec>,
|
||||
pub t_spec: Option<TypeSpecWithOp>,
|
||||
}
|
||||
|
||||
impl NestedDisplay for VarSignature {
|
||||
|
@ -3207,7 +3221,7 @@ impl Locational for VarSignature {
|
|||
}
|
||||
|
||||
impl VarSignature {
|
||||
pub const fn new(pat: VarPattern, t_spec: Option<TypeSpec>) -> Self {
|
||||
pub const fn new(pat: VarPattern, t_spec: Option<TypeSpecWithOp>) -> Self {
|
||||
Self { pat, t_spec }
|
||||
}
|
||||
|
||||
|
@ -3860,7 +3874,7 @@ impl Signature {
|
|||
|
||||
pub fn t_spec(&self) -> Option<&TypeSpec> {
|
||||
match self {
|
||||
Self::Var(v) => v.t_spec.as_ref(),
|
||||
Self::Var(v) => v.t_spec.as_ref().map(|t| &t.t_spec),
|
||||
Self::Subr(c) => c.return_t_spec.as_ref(),
|
||||
}
|
||||
}
|
||||
|
@ -3884,6 +3898,20 @@ impl Signature {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum AscriptionKind {
|
||||
TypeOf,
|
||||
SubtypeOf,
|
||||
SupertypeOf,
|
||||
AsCast,
|
||||
}
|
||||
|
||||
impl AscriptionKind {
|
||||
pub const fn is_force_cast(&self) -> bool {
|
||||
matches!(self, Self::AsCast)
|
||||
}
|
||||
}
|
||||
|
||||
/// type_ascription ::= expr ':' type
|
||||
/// | expr '<:' type
|
||||
/// | expr ':>' type
|
||||
|
@ -3910,12 +3938,8 @@ impl TypeAscription {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn is_instance_ascription(&self) -> bool {
|
||||
self.t_spec.op.is(TokenKind::Colon)
|
||||
}
|
||||
|
||||
pub fn is_subtype_ascription(&self) -> bool {
|
||||
self.t_spec.op.is(TokenKind::SubtypeOf)
|
||||
pub fn kind(&self) -> AscriptionKind {
|
||||
self.t_spec.ascription_kind()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -198,12 +198,12 @@ impl Parser {
|
|||
pack: DataPack,
|
||||
) -> ParseResult<VarDataPackPattern> {
|
||||
debug_call_info!(self);
|
||||
let class = Self::expr_to_type_spec(*pack.class).map_err(|e| self.errs.push(e))?;
|
||||
let class = Self::expr_to_type_spec(*pack.class.clone()).map_err(|e| self.errs.push(e))?;
|
||||
let args = self
|
||||
.convert_record_to_record_pat(pack.args)
|
||||
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||
debug_exit_info!(self);
|
||||
Ok(VarDataPackPattern::new(class, args))
|
||||
Ok(VarDataPackPattern::new(class, pack.class, args))
|
||||
}
|
||||
|
||||
fn convert_tuple_to_tuple_pat(&mut self, tuple: Tuple) -> ParseResult<VarTuplePattern> {
|
||||
|
@ -243,7 +243,7 @@ impl Parser {
|
|||
.map_err(|_| self.stack_dec(fn_name!()))?;
|
||||
let sig = match sig {
|
||||
Signature::Var(var) => {
|
||||
let var = VarSignature::new(var.pat, Some(tasc.t_spec.t_spec));
|
||||
let var = VarSignature::new(var.pat, Some(tasc.t_spec));
|
||||
Signature::Var(var)
|
||||
}
|
||||
Signature::Subr(subr) => {
|
||||
|
|
|
@ -498,7 +498,11 @@ impl Desugarer {
|
|||
todo!()
|
||||
}
|
||||
|
||||
fn gen_buf_name_and_sig(&mut self, line: u32, t_spec: Option<TypeSpec>) -> (String, Signature) {
|
||||
fn gen_buf_name_and_sig(
|
||||
&mut self,
|
||||
line: u32,
|
||||
t_spec: Option<TypeSpecWithOp>,
|
||||
) -> (String, Signature) {
|
||||
let buf_name = fresh_varname();
|
||||
let buf_sig = Signature::Var(VarSignature::new(
|
||||
VarPattern::Ident(Identifier::private_with_line(Str::rc(&buf_name), line)),
|
||||
|
@ -613,9 +617,14 @@ impl Desugarer {
|
|||
}
|
||||
}
|
||||
VarPattern::DataPack(pack) => {
|
||||
let t_spec = TypeSpecWithOp::new(
|
||||
COLON,
|
||||
pack.class.clone(),
|
||||
*pack.class_as_expr.clone(),
|
||||
);
|
||||
let (buf_name, buf_sig) = self.gen_buf_name_and_sig(
|
||||
v.ln_begin().unwrap_or(1),
|
||||
Some(pack.class.clone()), // TODO: これだとvの型指定の意味がなくなる
|
||||
Some(t_spec), // TODO: これだとvの型指定の意味がなくなる
|
||||
);
|
||||
let block = body
|
||||
.block
|
||||
|
@ -756,8 +765,10 @@ impl Desugarer {
|
|||
}
|
||||
}
|
||||
VarPattern::DataPack(pack) => {
|
||||
let (buf_name, buf_sig) = self
|
||||
.gen_buf_name_and_sig(sig.ln_begin().unwrap_or(1), Some(pack.class.clone()));
|
||||
let t_spec =
|
||||
TypeSpecWithOp::new(COLON, pack.class.clone(), *pack.class_as_expr.clone());
|
||||
let (buf_name, buf_sig) =
|
||||
self.gen_buf_name_and_sig(sig.ln_begin().unwrap_or(1), Some(t_spec));
|
||||
let buf_def = Def::new(buf_sig, body);
|
||||
new_module.push(Expr::Def(buf_def));
|
||||
for VarRecordAttr { lhs, rhs } in pack.args.attrs.iter() {
|
||||
|
@ -1101,7 +1112,7 @@ impl Desugarer {
|
|||
Expr::Def(Def::new(
|
||||
Signature::Var(VarSignature::new(
|
||||
VarPattern::Ident(ident),
|
||||
sig.t_spec.as_ref().map(|ts| ts.t_spec.clone()),
|
||||
sig.t_spec.clone(),
|
||||
)),
|
||||
body,
|
||||
)),
|
||||
|
@ -1150,7 +1161,7 @@ impl Desugarer {
|
|||
Expr::Def(Def::new(
|
||||
Signature::Var(VarSignature::new(
|
||||
VarPattern::Ident(Identifier::private(Str::from(&buf_name))),
|
||||
sig.t_spec.as_ref().map(|ts| ts.t_spec.clone()),
|
||||
sig.t_spec.clone(),
|
||||
)),
|
||||
body,
|
||||
)),
|
||||
|
@ -1188,7 +1199,7 @@ impl Desugarer {
|
|||
Expr::Def(Def::new(
|
||||
Signature::Var(VarSignature::new(
|
||||
VarPattern::Ident(Identifier::private(Str::from(&buf_name))),
|
||||
sig.t_spec.as_ref().map(|ts| ts.t_spec.clone()),
|
||||
sig.t_spec.clone(),
|
||||
)),
|
||||
body,
|
||||
)),
|
||||
|
@ -1255,10 +1266,7 @@ impl Desugarer {
|
|||
*/
|
||||
ParamPattern::VarName(name) => {
|
||||
let ident = Identifier::new(VisModifierSpec::Private, name.clone());
|
||||
let v = VarSignature::new(
|
||||
VarPattern::Ident(ident),
|
||||
sig.t_spec.as_ref().map(|ts| ts.t_spec.clone()),
|
||||
);
|
||||
let v = VarSignature::new(VarPattern::Ident(ident), sig.t_spec.clone());
|
||||
let def = Def::new(Signature::Var(v), body);
|
||||
new_body.insert(insertion_idx, Expr::Def(def));
|
||||
insertion_idx += 1;
|
||||
|
|
|
@ -700,7 +700,7 @@ impl Lexer /*<'a>*/ {
|
|||
// e.g. and(true, true, true) = true
|
||||
let kind = match &cont[..] {
|
||||
"and" => AndOp,
|
||||
"as" => AsOp,
|
||||
"as" => As,
|
||||
"or" => OrOp,
|
||||
"in" => InOp,
|
||||
"notin" => NotInOp,
|
||||
|
|
|
@ -1209,7 +1209,7 @@ impl Parser {
|
|||
// type ascription
|
||||
Some(op)
|
||||
if (op.is(Colon) && !self.nth_is(1, Newline))
|
||||
|| (op.is(SubtypeOf) || op.is(SupertypeOf)) =>
|
||||
|| (op.is(SubtypeOf) || op.is(SupertypeOf) || op.is(As)) =>
|
||||
{
|
||||
// "a": 1 (key-value pair)
|
||||
if in_brace {
|
||||
|
@ -1480,7 +1480,7 @@ impl Parser {
|
|||
// type ascription
|
||||
Some(op)
|
||||
if (op.is(Colon) && !self.nth_is(1, Newline))
|
||||
|| (op.is(SubtypeOf) || op.is(SupertypeOf)) =>
|
||||
|| (op.is(SubtypeOf) || op.is(SupertypeOf) || op.is(As)) =>
|
||||
{
|
||||
// "a": 1 (key-value pair)
|
||||
if in_brace {
|
||||
|
|
|
@ -108,8 +108,6 @@ pub enum TokenKind {
|
|||
IsNotOp,
|
||||
/// `and`
|
||||
AndOp,
|
||||
/// `as`
|
||||
AsOp,
|
||||
/// `or`
|
||||
OrOp,
|
||||
/// `dot` (scalar product)
|
||||
|
@ -156,6 +154,8 @@ pub enum TokenKind {
|
|||
SupertypeOf,
|
||||
/// <:
|
||||
SubtypeOf,
|
||||
/// `as`
|
||||
As,
|
||||
/// ,
|
||||
Comma,
|
||||
/// ^
|
||||
|
@ -241,7 +241,7 @@ impl TokenKind {
|
|||
TokenCategory::UnaryOp
|
||||
}
|
||||
Try => TokenCategory::PostfixOp,
|
||||
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | Dot | Pipe | Walrus
|
||||
Comma | Colon | DblColon | SupertypeOf | SubtypeOf | As | Dot | Pipe | Walrus
|
||||
| Inclusion => TokenCategory::SpecialBinOp,
|
||||
Assign => TokenCategory::DefOp,
|
||||
FuncArrow | ProcArrow => TokenCategory::LambdaOp,
|
||||
|
@ -271,16 +271,15 @@ impl TokenKind {
|
|||
BitXor => 130, // ^^
|
||||
BitOr => 120, // ||
|
||||
Closed | LeftOpen | RightOpen | Open => 100, // range operators
|
||||
Less | Gre | LessEq | GreEq | DblEq | NotEq | AsOp | InOp | NotInOp | IsOp
|
||||
| IsNotOp => 90, // < > <= >= == != as in notin is isnot
|
||||
AndOp => 80, // and
|
||||
OrOp => 70, // or
|
||||
FuncArrow | ProcArrow | Inclusion => 60, // -> => <-
|
||||
Colon | SupertypeOf | SubtypeOf => 50, // : :> <:
|
||||
Comma => 40, // ,
|
||||
Assign | Walrus => 20, // = :=
|
||||
Newline | Semi => 10, // \n ;
|
||||
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
|
||||
Less | Gre | LessEq | GreEq | DblEq | NotEq | InOp | NotInOp | IsOp | IsNotOp => 90, // < > <= >= == != in notin is isnot
|
||||
AndOp => 80, // and
|
||||
OrOp => 70, // or
|
||||
FuncArrow | ProcArrow | Inclusion => 60, // -> => <-
|
||||
Colon | SupertypeOf | SubtypeOf | As => 50, // : :> <: as
|
||||
Comma => 40, // ,
|
||||
Assign | Walrus => 20, // = :=
|
||||
Newline | Semi => 10, // \n ;
|
||||
LParen | LBrace | LSqBr | Indent => 0, // ( { [ Indent
|
||||
_ => return None,
|
||||
};
|
||||
Some(prec)
|
||||
|
|
|
@ -50,30 +50,6 @@ Generate anonymous functions, function types.
|
|||
|
||||
Generate anonymous procedure, procedure type.
|
||||
|
||||
## `:`(subject, T)
|
||||
|
||||
Determine if subject matches T. If they don't match, throw a compile error.
|
||||
|
||||
```python
|
||||
a: Int
|
||||
f x: Int, y: Int = x / y
|
||||
```
|
||||
|
||||
Also used for `:` applied styles.
|
||||
|
||||
```python
|
||||
fx:
|
||||
y
|
||||
z
|
||||
```
|
||||
|
||||
Like `:` and `=`, the result of the operation is undefined.
|
||||
|
||||
```python
|
||||
_ = x: Int # SyntaxError:
|
||||
print!(x: Int) # SyntaxError:
|
||||
```
|
||||
|
||||
## `.`(obj, attr)
|
||||
|
||||
Read attributes of obj.
|
||||
|
@ -87,6 +63,23 @@ Execute `c(obj)`. `x + y |>.foo()` is the same as `(x + y).foo()`.
|
|||
|
||||
Postfix operator. Call `x.unwrap()` and `return` immediately in case of error.
|
||||
|
||||
## `:`(x, T)
|
||||
|
||||
Declares that object `x` is of type `T`. An error is raised if `x` is not a subtype of `T`.
|
||||
|
||||
It can be used for variable declarations or as the right-hand side value of an expression.
|
||||
|
||||
```erg
|
||||
# both are OK
|
||||
x: Int = 1
|
||||
y = x: Int
|
||||
```
|
||||
|
||||
## `as`(x, T)
|
||||
|
||||
Forces the object `x` to be cast to type `T`. If `x` is not a subtype of `T`, an error is raised.
|
||||
The difference from `:` is that `(x: T): U` when `x: U; U <: T`, but `(x as T): T`.
|
||||
|
||||
## match(obj, *lambdas: Lambda)
|
||||
|
||||
For obj, execute lambdas that match the pattern.
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/special.md&commit_hash=8673a0ce564fd282d0ca586642fa7f002e8a3c50)
|
||||
|
||||
|
||||
特殊形式は、Ergの型システムでは表現ができない演算子、サブルーチン(のようなもの)である。``で囲っているが、実際は捕捉できない。
|
||||
また、`Pattern`や`Body`, `Conv`といった型が便宜上登場するが、そのような型が存在するわけではない。その意味もコンテクストによって異なる。
|
||||
|
||||
|
@ -65,6 +64,15 @@ objの属性を読み込む。
|
|||
|
||||
後置演算子。`x.unwrap()`を呼び出し、エラーの場合はその場で`return`する。
|
||||
|
||||
## `:`(x, T)
|
||||
|
||||
オブジェクト`x`が`T`型であることを宣言する。`x`の型が`T`の部分型でなければエラーとなる。
|
||||
|
||||
## `as`(x, T)
|
||||
|
||||
オブジェクト`x`を`T`型に強制キャストする。`x`の型が`T`の部分型でなければエラーとなる。
|
||||
`:`との違いとして、`x: U; U <: T`であるとき`(x: T): U`となるが、`(x as T): T`である。
|
||||
|
||||
## match(obj, *arms: Lambda)
|
||||
|
||||
objについて、パターンにマッチしたarmを実行する。armは無名関数でなくてはならない。
|
||||
|
|
|
@ -5,3 +5,13 @@ n = 1
|
|||
_ = n.times!
|
||||
i = n as Int
|
||||
_ = i.times! # ERR
|
||||
|
||||
v: Array!(Int or Str, 2) = ![1, 2]
|
||||
v.push! 1 # OK
|
||||
v.push! "a" # ERR
|
||||
v.push! None # ERR
|
||||
|
||||
v2 as Array!(Int or Str, 2) = ![1, 2]
|
||||
v2.push! 1 # OK
|
||||
v2.push! "a" # OK
|
||||
v2.push! None # ERR
|
||||
|
|
|
@ -244,7 +244,7 @@ fn exec_array_err() -> Result<(), ()> {
|
|||
|
||||
#[test]
|
||||
fn exec_as() -> Result<(), ()> {
|
||||
expect_failure("tests/should_err/as.er", 0, 3)
|
||||
expect_failure("tests/should_err/as.er", 0, 6)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue