mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 18:58:30 +00:00
fix: trait parameter bug
This commit is contained in:
parent
02a67567d3
commit
0ffa23affd
7 changed files with 73 additions and 32 deletions
|
@ -369,6 +369,18 @@ macro_rules! ref_addr_eq {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! power_assert {
|
||||
($l: expr, $op: tt, $r: expr, $msg: expr $(,)*) => {
|
||||
if !($l $op $r) {
|
||||
let s_l = stringify!($l);
|
||||
let s_r = stringify!($r);
|
||||
let s_op = stringify!($op);
|
||||
println!($msg);
|
||||
panic!(
|
||||
"assertion failed: `{s_l} {s_op} {s_r}` (`{s_l}` = {:#?}, `{s_r}` = {:#?})",
|
||||
$l, $r,
|
||||
)
|
||||
}
|
||||
};
|
||||
($l: expr, $op: tt, $r: expr $(,)*) => {
|
||||
if !($l $op $r) {
|
||||
let s_l = stringify!($l);
|
||||
|
@ -390,6 +402,11 @@ macro_rules! power_assert {
|
|||
|
||||
#[macro_export]
|
||||
macro_rules! debug_power_assert {
|
||||
($l: expr, $op: tt, $r: expr, $msg: expr) => {
|
||||
if cfg!(debug_assertions) {
|
||||
erg_common::power_assert!($l, $op, $r, $msg)
|
||||
}
|
||||
};
|
||||
($l: expr, $op: tt, $r: expr) => {
|
||||
if cfg!(debug_assertions) {
|
||||
erg_common::power_assert!($l, $op, $r)
|
||||
|
|
|
@ -843,10 +843,10 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
|||
/// sub_unify([?T; 0], Mutate): (/* OK */)
|
||||
/// ```
|
||||
fn sub_unify(&self, maybe_sub: &Type, maybe_sup: &Type) -> TyCheckResult<()> {
|
||||
log!(info "trying {}sub_unify:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}", self.undoable.map_or("", |_| "undoable"));
|
||||
log!(info "trying {}sub_unify:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}", self.undoable.map_or("", |_| "undoable_"));
|
||||
// In this case, there is no new information to be gained
|
||||
// この場合、特に新しく得られる情報はない
|
||||
if maybe_sub == &Type::Never || maybe_sup == &Type::Obj || maybe_sup == maybe_sub {
|
||||
if maybe_sub == &Type::Never || maybe_sup == &Type::Obj || maybe_sup.addr_eq(maybe_sub) {
|
||||
log!(info "no-op:\nmaybe_sub: {maybe_sub}\nmaybe_sup: {maybe_sup}");
|
||||
return Ok(());
|
||||
}
|
||||
|
@ -1640,6 +1640,7 @@ impl<'c, 'l, 'u, L: Locational> Unifier<'c, 'l, 'u, L> {
|
|||
list.push_tp(l_maybe_sub);
|
||||
list.push_tp(r_maybe_sup);
|
||||
}
|
||||
// debug_power_assert!(variances.len(), >=, sup_params.len(), "{sub_instance} / {maybe_sup}");
|
||||
let unifier = Unifier::new(self.ctx, self.loc, Some(&list), false, None);
|
||||
for ((l_maybe_sub, r_maybe_sup), variance) in sub_params
|
||||
.iter()
|
||||
|
|
|
@ -1720,6 +1720,20 @@ impl TyParam {
|
|||
}
|
||||
match self {
|
||||
Self::FreeVar(fv) => fv.link(to),
|
||||
Self::Type(t) => {
|
||||
if let Ok(to) = <&Type>::try_from(to) {
|
||||
t.destructive_link(to);
|
||||
} else {
|
||||
panic!("{to} is not a type");
|
||||
}
|
||||
}
|
||||
Self::Value(ValueObj::Type(t)) => {
|
||||
if let Ok(to) = <&Type>::try_from(to) {
|
||||
t.typ().destructive_link(to);
|
||||
} else {
|
||||
panic!("{to} is not a type");
|
||||
}
|
||||
}
|
||||
_ => panic!("{self} is not a free variable"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
fst|T| s: Sequence T = s[0]
|
||||
assert fst([1, 2, 3]) + 1 == 2
|
||||
assert fst(["a", "b", "c"]) + "b" == "ab"
|
||||
assert fst((1, 2, 3)) + 1 == 2
|
||||
|
||||
Norm = Trait {.norm = (self: Self) -> Nat}
|
||||
|
||||
Point2D = Class {x = Int; y = Int}
|
||||
|
|
27
tests/should_err/infer_fn.er
Normal file
27
tests/should_err/infer_fn.er
Normal file
|
@ -0,0 +1,27 @@
|
|||
# g: |T <: Ord and Eq and Show| T -> T
|
||||
g x =
|
||||
_ = x <= x
|
||||
_ = x == x
|
||||
_ = x.__str__()
|
||||
x
|
||||
|
||||
g 1 # OK
|
||||
g None # ERR
|
||||
|
||||
h x, y =
|
||||
_ = x == y
|
||||
_ = x - y
|
||||
x + y
|
||||
|
||||
_ = h -1, -2 # OK
|
||||
_ = h 1, 2 # OK
|
||||
_ = h "a", "b" # ERR
|
||||
|
||||
i|T|(x: T): T =
|
||||
_: Int = x
|
||||
x + "a" # ERR
|
||||
i2|T|(x: T): T =
|
||||
x + "a"
|
||||
|
||||
_ = i 1
|
||||
_ = i2 1 # ERR
|
|
@ -16,7 +16,7 @@ for! zip([1], ["a"]), ((i: Int, s: Str),) =>
|
|||
l = s + "b"
|
||||
print! k, l
|
||||
# ERR: i should be Int
|
||||
for! zip([1], ["a"]), ((i: Str, s: Str),) =>
|
||||
for! zip([1], ["a"]), ((i: Str, s: Str),) => # ERR
|
||||
k = i + "a"
|
||||
print! k
|
||||
for! zip([1], ["a"]), ((i, s),) =>
|
||||
|
@ -38,34 +38,6 @@ inty|T :> Nat, T <: Int|(x: T) = x + x
|
|||
inty 0 # OK
|
||||
inty 1.1 # ERR
|
||||
|
||||
# g: |T <: Ord and Eq and Show| T -> T
|
||||
g x =
|
||||
_ = x <= x
|
||||
_ = x == x
|
||||
_ = x.__str__()
|
||||
x
|
||||
|
||||
g 1 # OK
|
||||
g None # ERR
|
||||
|
||||
h x, y =
|
||||
_ = x == y
|
||||
_ = x - y
|
||||
x + y
|
||||
|
||||
_ = h -1, -2 # OK
|
||||
_ = h 1, 2 # OK
|
||||
_ = h "a", "b" # ERR
|
||||
|
||||
i|T|(x: T): T =
|
||||
_: Int = x
|
||||
x + "a" # ERR
|
||||
i2|T|(x: T): T =
|
||||
x + "a"
|
||||
|
||||
_ = i 1
|
||||
_ = i2 1 # ERR
|
||||
|
||||
_: List!({"a", "b"}, 2) = !["a", "b"] # OK
|
||||
_: List!({"a", "b", "c"}, 2) = !["a", "b"] # OK
|
||||
_: List!({"a", "c"}, 2) = !["a", "b"] # ERR
|
||||
|
|
|
@ -574,6 +574,11 @@ fn exec_incomplete_typespec() -> Result<(), ()> {
|
|||
expect_failure("tests/should_err/incomplete_typespec.er", 0, 3)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_infer_fn() -> Result<(), ()> {
|
||||
expect_failure("tests/should_err/infer_fn.er", 2, 6)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn exec_infer_union_array() -> Result<(), ()> {
|
||||
expect_failure("tests/should_err/infer_union_array.er", 2, 1)
|
||||
|
@ -641,7 +646,7 @@ fn exec_structural_err() -> Result<(), ()> {
|
|||
#[test]
|
||||
fn exec_subtyping_err() -> Result<(), ()> {
|
||||
// NOTE: The content of some errors is semantically redundant and can be reduced.
|
||||
expect_failure("tests/should_err/subtyping.er", 0, 18)
|
||||
expect_failure("tests/should_err/subtyping.er", 3, 13)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue