mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-29 20:34:44 +00:00
Fix #247
This commit is contained in:
parent
1a9ae3349d
commit
111a9f5615
23 changed files with 213 additions and 97 deletions
|
@ -57,8 +57,8 @@ impl Context {
|
||||||
found.union_types()
|
found.union_types()
|
||||||
.map(|(t1, t2)| format!("cannot {verb} {t1} {preposition} {t2}"))
|
.map(|(t1, t2)| format!("cannot {verb} {t1} {preposition} {t2}"))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
let ts = expected.inner_ts();
|
let expected_inner = Self::readable_type(&expected.inner_ts()[0]);
|
||||||
Some(format!("cannot {verb} {found} {preposition} {}", ts[0]))
|
Some(format!("cannot {verb} {found} {preposition} {expected_inner}"))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -849,7 +849,7 @@ impl Context {
|
||||||
/// substitute_call(instance: ((?T, Int) -> ?T), [Int, Nat], []) => instance: (Int, Int) -> Str
|
/// substitute_call(instance: ((?T, Int) -> ?T), [Int, Nat], []) => instance: (Int, Int) -> Str
|
||||||
/// substitute_call(instance: ((?M(: Nat)..?N(: Nat)) -> ?M+?N), [1..2], []) => instance: (1..2) -> {3}
|
/// substitute_call(instance: ((?M(: Nat)..?N(: Nat)) -> ?M+?N), [1..2], []) => instance: (1..2) -> {3}
|
||||||
/// substitute_call(instance: ((?L(: Add(?R, ?O)), ?R) -> ?O), [1, 2], []) => instance: (Nat, Nat) -> Nat
|
/// substitute_call(instance: ((?L(: Add(?R, ?O)), ?R) -> ?O), [1, 2], []) => instance: (Nat, Nat) -> Nat
|
||||||
/// substitute_call(instance: ?T, [Int, Str], []) => instance: (Int, Str) -> Int
|
/// substitute_call(instance: ((Failure, ?T) -> ?T), [Int, Int]) => instance: (Failure, Int) -> Int
|
||||||
/// ```
|
/// ```
|
||||||
fn substitute_call(
|
fn substitute_call(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -205,31 +205,47 @@ impl Context {
|
||||||
sig: &ast::SubrSignature,
|
sig: &ast::SubrSignature,
|
||||||
default_ts: Vec<Type>,
|
default_ts: Vec<Type>,
|
||||||
mode: RegistrationMode,
|
mode: RegistrationMode,
|
||||||
) -> TyCheckResult<Type> {
|
) -> Result<Type, (TyCheckErrors, Type)> {
|
||||||
|
let mut errs = TyCheckErrors::empty();
|
||||||
// -> Result<Type, (Type, TyCheckErrors)> {
|
// -> Result<Type, (Type, TyCheckErrors)> {
|
||||||
let opt_decl_sig_t = self
|
let opt_decl_sig_t = self
|
||||||
.rec_get_decl_info(&sig.ident, AccessKind::Name, &self.cfg.input, &self.name)
|
.rec_get_decl_info(&sig.ident, AccessKind::Name, &self.cfg.input, &self.name)
|
||||||
.ok()
|
.ok()
|
||||||
.map(|vi| enum_unwrap!(vi.t, Type::Subr));
|
.map(|vi| enum_unwrap!(vi.t, Type::Subr));
|
||||||
let mut tmp_tv_cache = self.instantiate_ty_bounds(&sig.bounds, PreRegister)?;
|
let mut tmp_tv_cache = self
|
||||||
|
.instantiate_ty_bounds(&sig.bounds, PreRegister)
|
||||||
|
.map_err(|errs| (errs, Type::Failure))?;
|
||||||
let mut non_defaults = vec![];
|
let mut non_defaults = vec![];
|
||||||
for (n, p) in sig.params.non_defaults.iter().enumerate() {
|
for (n, param) in sig.params.non_defaults.iter().enumerate() {
|
||||||
let opt_decl_t = opt_decl_sig_t
|
let opt_decl_t = opt_decl_sig_t
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|subr| subr.non_default_params.get(n));
|
.and_then(|subr| subr.non_default_params.get(n));
|
||||||
non_defaults.push(self.instantiate_param_ty(
|
match self.instantiate_param_ty(param, None, opt_decl_t, &mut tmp_tv_cache, mode) {
|
||||||
p,
|
Ok(t) => non_defaults.push(t),
|
||||||
None,
|
Err(es) => {
|
||||||
opt_decl_t,
|
errs.extend(es);
|
||||||
&mut tmp_tv_cache,
|
non_defaults.push(ParamTy::pos(param.inspect().cloned(), Type::Failure));
|
||||||
mode,
|
}
|
||||||
)?);
|
}
|
||||||
}
|
}
|
||||||
let var_args = if let Some(var_args) = sig.params.var_args.as_ref() {
|
let var_args = if let Some(var_args) = sig.params.var_args.as_ref() {
|
||||||
let opt_decl_t = opt_decl_sig_t
|
let opt_decl_t = opt_decl_sig_t
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref()));
|
.and_then(|subr| subr.var_params.as_ref().map(|v| v.as_ref()));
|
||||||
Some(self.instantiate_param_ty(var_args, None, opt_decl_t, &mut tmp_tv_cache, mode)?)
|
let pt = match self.instantiate_param_ty(
|
||||||
|
var_args,
|
||||||
|
None,
|
||||||
|
opt_decl_t,
|
||||||
|
&mut tmp_tv_cache,
|
||||||
|
mode,
|
||||||
|
) {
|
||||||
|
Ok(pt) => pt,
|
||||||
|
Err(es) => {
|
||||||
|
errs.extend(es);
|
||||||
|
ParamTy::pos(var_args.inspect().cloned(), Type::Failure)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
Some(pt)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
@ -238,19 +254,32 @@ impl Context {
|
||||||
let opt_decl_t = opt_decl_sig_t
|
let opt_decl_t = opt_decl_sig_t
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|subr| subr.default_params.get(n));
|
.and_then(|subr| subr.default_params.get(n));
|
||||||
defaults.push(self.instantiate_param_ty(
|
match self.instantiate_param_ty(
|
||||||
&p.sig,
|
&p.sig,
|
||||||
Some(default_t),
|
Some(default_t),
|
||||||
opt_decl_t,
|
opt_decl_t,
|
||||||
&mut tmp_tv_cache,
|
&mut tmp_tv_cache,
|
||||||
mode,
|
mode,
|
||||||
)?);
|
) {
|
||||||
|
Ok(t) => defaults.push(t),
|
||||||
|
Err(es) => {
|
||||||
|
errs.extend(es);
|
||||||
|
defaults.push(ParamTy::pos(p.sig.inspect().cloned(), Type::Failure));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let spec_return_t = if let Some(s) = sig.return_t_spec.as_ref() {
|
let spec_return_t = if let Some(s) = sig.return_t_spec.as_ref() {
|
||||||
let opt_decl_t = opt_decl_sig_t
|
let opt_decl_t = opt_decl_sig_t
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|subr| ParamTy::anonymous(subr.return_t.as_ref().clone()));
|
.map(|subr| ParamTy::anonymous(subr.return_t.as_ref().clone()));
|
||||||
self.instantiate_typespec(s, opt_decl_t.as_ref(), &mut tmp_tv_cache, mode, false)?
|
match self.instantiate_typespec(s, opt_decl_t.as_ref(), &mut tmp_tv_cache, mode, false)
|
||||||
|
{
|
||||||
|
Ok(ty) => ty,
|
||||||
|
Err(es) => {
|
||||||
|
errs.extend(es);
|
||||||
|
Type::Failure
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// preregisterならouter scopeで型宣言(see inference.md)
|
// preregisterならouter scopeで型宣言(see inference.md)
|
||||||
let level = if mode == PreRegister {
|
let level = if mode == PreRegister {
|
||||||
|
@ -260,11 +289,16 @@ impl Context {
|
||||||
};
|
};
|
||||||
free_var(level, Constraint::new_type_of(Type))
|
free_var(level, Constraint::new_type_of(Type))
|
||||||
};
|
};
|
||||||
Ok(if sig.ident.is_procedural() {
|
let typ = if sig.ident.is_procedural() {
|
||||||
proc(non_defaults, var_args, defaults, spec_return_t)
|
proc(non_defaults, var_args, defaults, spec_return_t)
|
||||||
} else {
|
} else {
|
||||||
func(non_defaults, var_args, defaults, spec_return_t)
|
func(non_defaults, var_args, defaults, spec_return_t)
|
||||||
})
|
};
|
||||||
|
if errs.is_empty() {
|
||||||
|
Ok(typ)
|
||||||
|
} else {
|
||||||
|
Err((errs, typ))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// spec_t == Noneかつリテラル推論が不可能なら型変数を発行する
|
/// spec_t == Noneかつリテラル推論が不可能なら型変数を発行する
|
||||||
|
@ -454,12 +488,12 @@ impl Context {
|
||||||
tmp_tv_cache.push_or_init_tyvar(&Str::rc(other), &tyvar);
|
tmp_tv_cache.push_or_init_tyvar(&Str::rc(other), &tyvar);
|
||||||
Ok(tyvar)
|
Ok(tyvar)
|
||||||
} else {
|
} else {
|
||||||
Err(TyCheckErrors::from(TyCheckError::no_var_error(
|
Err(TyCheckErrors::from(TyCheckError::no_type_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
simple.loc(),
|
simple.loc(),
|
||||||
self.caused_by(),
|
self.caused_by(),
|
||||||
&format!("(Type) {other}"),
|
other,
|
||||||
self.get_similar_name(other),
|
self.get_similar_name(other),
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -468,12 +502,12 @@ impl Context {
|
||||||
let ctx = if let Some((_, ctx)) = self.rec_get_type(other) {
|
let ctx = if let Some((_, ctx)) = self.rec_get_type(other) {
|
||||||
ctx
|
ctx
|
||||||
} else {
|
} else {
|
||||||
return Err(TyCheckErrors::from(TyCheckError::no_var_error(
|
return Err(TyCheckErrors::from(TyCheckError::no_type_error(
|
||||||
self.cfg.input.clone(),
|
self.cfg.input.clone(),
|
||||||
line!() as usize,
|
line!() as usize,
|
||||||
simple.ident.loc(),
|
simple.ident.loc(),
|
||||||
self.caused_by(),
|
self.caused_by(),
|
||||||
&format!("(Type) {other}"),
|
other,
|
||||||
self.get_similar_name(other),
|
self.get_similar_name(other),
|
||||||
)));
|
)));
|
||||||
};
|
};
|
||||||
|
|
|
@ -115,21 +115,10 @@ impl Context {
|
||||||
.collect::<Set<_>>();
|
.collect::<Set<_>>();
|
||||||
let default_ts =
|
let default_ts =
|
||||||
vec![free_var(self.level, Constraint::new_type_of(Type::Type)); sig.params.len()];
|
vec![free_var(self.level, Constraint::new_type_of(Type::Type)); sig.params.len()];
|
||||||
let t = self
|
let (errs, t) = match self.instantiate_sub_sig_t(sig, default_ts, PreRegister) {
|
||||||
.instantiate_sub_sig_t(sig, default_ts, PreRegister)
|
Ok(t) => (TyCheckErrors::empty(), t),
|
||||||
.map_err(|e| {
|
Err((errs, t)) => (errs, t),
|
||||||
let vi = VarInfo::new(
|
};
|
||||||
Type::Failure,
|
|
||||||
muty,
|
|
||||||
vis,
|
|
||||||
kind.clone(),
|
|
||||||
Some(comptime_decos.clone()),
|
|
||||||
self.impl_of(),
|
|
||||||
None,
|
|
||||||
);
|
|
||||||
self.decls.insert(sig.ident.name.clone(), vi);
|
|
||||||
e
|
|
||||||
})?;
|
|
||||||
let vi = VarInfo::new(
|
let vi = VarInfo::new(
|
||||||
t,
|
t,
|
||||||
muty,
|
muty,
|
||||||
|
@ -149,7 +138,11 @@ impl Context {
|
||||||
)))
|
)))
|
||||||
} else {
|
} else {
|
||||||
self.decls.insert(sig.ident.name.clone(), vi);
|
self.decls.insert(sig.ident.name.clone(), vi);
|
||||||
Ok(())
|
if errs.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,6 +338,7 @@ impl Context {
|
||||||
params: &hir::Params,
|
params: &hir::Params,
|
||||||
opt_decl_subr_t: Option<SubrType>,
|
opt_decl_subr_t: Option<SubrType>,
|
||||||
) -> TyCheckResult<()> {
|
) -> TyCheckResult<()> {
|
||||||
|
let mut errs = TyCheckErrors::empty();
|
||||||
if let Some(decl_subr_t) = opt_decl_subr_t {
|
if let Some(decl_subr_t) = opt_decl_subr_t {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
params.non_defaults.len(),
|
params.non_defaults.len(),
|
||||||
|
@ -356,24 +350,36 @@ impl Context {
|
||||||
.iter()
|
.iter()
|
||||||
.zip(decl_subr_t.non_default_params.iter())
|
.zip(decl_subr_t.non_default_params.iter())
|
||||||
{
|
{
|
||||||
self.assign_param(sig, false, Some(pt))?;
|
if let Err(es) = self.assign_param(sig, false, Some(pt)) {
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for (sig, pt) in params
|
for (sig, pt) in params
|
||||||
.defaults
|
.defaults
|
||||||
.iter()
|
.iter()
|
||||||
.zip(decl_subr_t.default_params.iter())
|
.zip(decl_subr_t.default_params.iter())
|
||||||
{
|
{
|
||||||
self.assign_param(&sig.sig, true, Some(pt))?;
|
if let Err(es) = self.assign_param(&sig.sig, true, Some(pt)) {
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for sig in params.non_defaults.iter() {
|
for sig in params.non_defaults.iter() {
|
||||||
self.assign_param(sig, false, None)?;
|
if let Err(es) = self.assign_param(sig, false, None) {
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for sig in params.defaults.iter() {
|
for sig in params.defaults.iter() {
|
||||||
self.assign_param(&sig.sig, true, None)?;
|
if let Err(es) = self.assign_param(&sig.sig, true, None) {
|
||||||
|
errs.extend(es);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
if errs.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(errs)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ## Errors
|
/// ## Errors
|
||||||
|
|
|
@ -1268,6 +1268,10 @@ impl Context {
|
||||||
if maybe_sub == &Type::Never || maybe_sup == &Type::Obj || maybe_sup == maybe_sub {
|
if maybe_sub == &Type::Never || maybe_sup == &Type::Obj || maybe_sup == maybe_sub {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
// API definition was failed and inspection is useless after this
|
||||||
|
if maybe_sub == &Type::Failure || maybe_sup == &Type::Failure {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
self.occur(maybe_sub, maybe_sup, loc)?;
|
self.occur(maybe_sub, maybe_sup, loc)?;
|
||||||
let maybe_sub_is_sub = self.subtype_of(maybe_sub, maybe_sup);
|
let maybe_sub_is_sub = self.subtype_of(maybe_sub, maybe_sup);
|
||||||
if maybe_sub.has_no_unbound_var() && maybe_sup.has_no_unbound_var() && maybe_sub_is_sub {
|
if maybe_sub.has_no_unbound_var() && maybe_sup.has_no_unbound_var() && maybe_sub_is_sub {
|
||||||
|
|
|
@ -1577,6 +1577,43 @@ impl LowerError {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn no_type_error(
|
||||||
|
input: Input,
|
||||||
|
errno: usize,
|
||||||
|
loc: Location,
|
||||||
|
caused_by: String,
|
||||||
|
name: &str,
|
||||||
|
similar_name: Option<&str>,
|
||||||
|
) -> Self {
|
||||||
|
let name = readable_name(name);
|
||||||
|
let hint = similar_name.map(|n| {
|
||||||
|
let n = StyledStr::new(n, Some(HINT), Some(ATTR));
|
||||||
|
switch_lang!(
|
||||||
|
"japanese" => format!("似た名前の型があります: {n}"),
|
||||||
|
"simplified_chinese" => format!("存在相同名称类型: {n}"),
|
||||||
|
"traditional_chinese" => format!("存在相同名稱類型: {n}"),
|
||||||
|
"english" => format!("exists a similar name type: {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!("Type {found} is not defined"),
|
||||||
|
),
|
||||||
|
errno,
|
||||||
|
NameError,
|
||||||
|
loc,
|
||||||
|
),
|
||||||
|
input,
|
||||||
|
caused_by,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn type_not_found(
|
pub fn type_not_found(
|
||||||
input: Input,
|
input: Input,
|
||||||
errno: usize,
|
errno: usize,
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from _erg_result import Error
|
from _erg_result import Error
|
||||||
|
|
||||||
class Nat(int):
|
class Nat(int):
|
||||||
def try_new(i: int): # -> Result[Nat]
|
def try_new(i): # -> Result[Nat]
|
||||||
if i >= 0:
|
if i >= 0:
|
||||||
return Nat(i)
|
return Nat(i)
|
||||||
else:
|
else:
|
||||||
|
@ -10,3 +10,9 @@ class Nat(int):
|
||||||
def times(self, f):
|
def times(self, f):
|
||||||
for _ in range(self):
|
for _ in range(self):
|
||||||
f()
|
f()
|
||||||
|
|
||||||
|
def saturating_sub(self, other):
|
||||||
|
if self > other:
|
||||||
|
return self - other
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
|
@ -835,18 +835,27 @@ impl ASTLowerer {
|
||||||
|
|
||||||
fn lower_params(&mut self, params: ast::Params) -> LowerResult<hir::Params> {
|
fn lower_params(&mut self, params: ast::Params) -> LowerResult<hir::Params> {
|
||||||
log!(info "entered {}({})", fn_name!(), params);
|
log!(info "entered {}({})", fn_name!(), params);
|
||||||
|
let mut errs = LowerErrors::empty();
|
||||||
let mut hir_defaults = vec![];
|
let mut hir_defaults = vec![];
|
||||||
for default in params.defaults.into_iter() {
|
for default in params.defaults.into_iter() {
|
||||||
let default_val = self.lower_expr(default.default_val)?;
|
match self.lower_expr(default.default_val) {
|
||||||
hir_defaults.push(hir::DefaultParamSignature::new(default.sig, default_val));
|
Ok(default_val) => {
|
||||||
|
hir_defaults.push(hir::DefaultParamSignature::new(default.sig, default_val));
|
||||||
|
}
|
||||||
|
Err(es) => errs.extend(es),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !errs.is_empty() {
|
||||||
|
Err(errs)
|
||||||
|
} else {
|
||||||
|
let hir_params = hir::Params::new(
|
||||||
|
params.non_defaults,
|
||||||
|
params.var_args,
|
||||||
|
hir_defaults,
|
||||||
|
params.parens,
|
||||||
|
);
|
||||||
|
Ok(hir_params)
|
||||||
}
|
}
|
||||||
let hir_params = hir::Params::new(
|
|
||||||
params.non_defaults,
|
|
||||||
params.var_args,
|
|
||||||
hir_defaults,
|
|
||||||
params.parens,
|
|
||||||
);
|
|
||||||
Ok(hir_params)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO: varargs
|
/// TODO: varargs
|
||||||
|
|
4
tests/should_err/addition.er
Normal file
4
tests/should_err/addition.er
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
add x, y =
|
||||||
|
x + y
|
||||||
|
|
||||||
|
print! add("a", 1) # this will be an error
|
7
tests/should_err/invalid_param.er
Normal file
7
tests/should_err/invalid_param.er
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Typo: Inu
|
||||||
|
add x: Int, y: Inu, z: Int = x + y + z
|
||||||
|
|
||||||
|
# 3rd arg is wrong
|
||||||
|
print! add(1, 2, "")
|
||||||
|
# missing argument
|
||||||
|
print! add(1, 2)
|
|
@ -4,4 +4,3 @@ add x, y =
|
||||||
print! add(1, 1)
|
print! add(1, 1)
|
||||||
print! add(1.0, 1)
|
print! add(1.0, 1)
|
||||||
print! add("a", "b")
|
print! add("a", "b")
|
||||||
print! add("a", 1) # this will be an error
|
|
|
@ -10,13 +10,13 @@ use erg_compiler::error::CompileErrors;
|
||||||
use erg::DummyVM;
|
use erg::DummyVM;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_addition() -> Result<(), ()> {
|
fn exec_addition_ok() -> Result<(), ()> {
|
||||||
expect_failure("tests/addition.er", 1)
|
expect_success("tests/should_ok/addition.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_advanced_type_spec() -> Result<(), ()> {
|
fn exec_advanced_type_spec() -> Result<(), ()> {
|
||||||
expect_success("tests/advanced_type_spec.er")
|
expect_success("tests/should_ok/advanced_type_spec.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -31,7 +31,7 @@ fn exec_class() -> Result<(), ()> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_control() -> Result<(), ()> {
|
fn exec_control() -> Result<(), ()> {
|
||||||
expect_success("tests/control.er")
|
expect_success("tests/should_ok/control.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -66,31 +66,17 @@ fn exec_import() -> Result<(), ()> {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_infer_class() -> Result<(), ()> {
|
fn exec_infer_class() -> Result<(), ()> {
|
||||||
expect_success("tests/infer_class.er")
|
expect_success("tests/should_ok/infer_class.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_infer_trait() -> Result<(), ()> {
|
fn exec_infer_trait() -> Result<(), ()> {
|
||||||
expect_success("tests/infer_trait.er")
|
expect_success("tests/should_ok/infer_trait.er")
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exec_move_check() -> Result<(), ()> {
|
|
||||||
expect_failure("examples/move_check.er", 1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_pattern() -> Result<(), ()> {
|
fn exec_pattern() -> Result<(), ()> {
|
||||||
expect_success("tests/pattern.er")
|
expect_success("tests/should_ok/pattern.er")
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exec_pyimport() -> Result<(), ()> {
|
|
||||||
if cfg!(unix) {
|
|
||||||
expect_end_with("examples/pyimport.er", 111)
|
|
||||||
} else {
|
|
||||||
expect_failure("examples/pyimport.er", 1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -103,32 +89,11 @@ fn exec_raw_ident() -> Result<(), ()> {
|
||||||
expect_success("examples/raw_ident.er")
|
expect_success("examples/raw_ident.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exec_rec() -> Result<(), ()> {
|
|
||||||
// this script is valid but the current code generating process has a bug.
|
|
||||||
expect_end_with("tests/rec.er", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_record() -> Result<(), ()> {
|
fn exec_record() -> Result<(), ()> {
|
||||||
expect_success("examples/record.er")
|
expect_success("examples/record.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exec_set() -> Result<(), ()> {
|
|
||||||
expect_failure("examples/set.er", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exec_side_effect() -> Result<(), ()> {
|
|
||||||
expect_failure("examples/side_effect.er", 4)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn exec_subtyping() -> Result<(), ()> {
|
|
||||||
expect_failure("tests/subtyping.er", 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn exec_trait() -> Result<(), ()> {
|
fn exec_trait() -> Result<(), ()> {
|
||||||
expect_success("examples/trait.er")
|
expect_success("examples/trait.er")
|
||||||
|
@ -154,6 +119,51 @@ fn exec_with() -> Result<(), ()> {
|
||||||
expect_success("examples/with.er")
|
expect_success("examples/with.er")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_addition_err() -> Result<(), ()> {
|
||||||
|
expect_failure("tests/should_err/addition.er", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_invalid_param() -> Result<(), ()> {
|
||||||
|
expect_failure("tests/should_err/invalid_param.er", 3)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_move_check() -> Result<(), ()> {
|
||||||
|
expect_failure("examples/move_check.er", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_pyimport() -> Result<(), ()> {
|
||||||
|
if cfg!(unix) {
|
||||||
|
expect_end_with("examples/pyimport.er", 111)
|
||||||
|
} else {
|
||||||
|
expect_failure("examples/pyimport.er", 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_rec() -> Result<(), ()> {
|
||||||
|
// this script is valid but the current code generating process has a bug.
|
||||||
|
expect_end_with("tests/should_err/rec.er", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_set() -> Result<(), ()> {
|
||||||
|
expect_failure("examples/set.er", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_side_effect() -> Result<(), ()> {
|
||||||
|
expect_failure("examples/side_effect.er", 4)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn exec_subtyping() -> Result<(), ()> {
|
||||||
|
expect_failure("tests/should_err/subtyping.er", 1)
|
||||||
|
}
|
||||||
|
|
||||||
fn expect_success(file_path: &'static str) -> Result<(), ()> {
|
fn expect_success(file_path: &'static str) -> Result<(), ()> {
|
||||||
match exec_vm(file_path) {
|
match exec_vm(file_path) {
|
||||||
Ok(0) => Ok(()),
|
Ok(0) => Ok(()),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue