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