tests: cleanup sum type tests (#6950)

pull/6954/head
Daniel Däschle 2020-11-25 20:40:29 +01:00 committed by GitHub
parent fa126b950a
commit 8e2b7fe3d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 385 additions and 593 deletions

View File

@ -38,6 +38,51 @@ fn test_nested_if_smartcast() {
}
}
type Bar = string | Test
type Xya = int | string
struct Test {
x string
xya Xya
}
struct BarWrapper {
y Bar
}
fn test_nested_selector_smartcast() {
f := BarWrapper{
y: Bar(Test{
x: 'Hi'
xya: Xya(int(5))
})
}
if f.y is Test {
z := f.y.x
assert f.y.x == 'Hi'
assert z == 'Hi'
if f.y.xya is int {
assert f.y.xya == 5
}
}
}
type Inner = int | string
struct InnerStruct {
x Inner
}
type Outer = string | InnerStruct
fn test_nested_if_is() {
b := Outer(InnerStruct{Inner(0)})
if b is InnerStruct {
if b.x is int {
assert b.x == 0
}
}
}
struct MutContainer {
mut:
abc Alphabet
@ -122,3 +167,89 @@ fn test_mutability() {
println('$cell.u')
}
}
type Expr = CallExpr | CTempVarExpr
struct ExprWrapper {
mut:
expr Expr
}
struct CallExpr {
y int
x string
}
struct CTempVarExpr {
x string
}
fn gen(_ Expr) CTempVarExpr {
return CTempVarExpr{}
}
fn test_reassign_from_function_with_parameter_selector() {
mut f := ExprWrapper{Expr(CallExpr{})}
if f.expr is CallExpr {
f.expr = gen(f.expr)
}
}
type Node = Expr | string
fn test_nested_sumtype() {
c := Node(Expr(CallExpr{y: 1}))
if c is Expr {
if c is CallExpr {
assert c.y == 1
}
else {
assert false
}
}
else {
assert false
}
}
type Food = Milk | Eggs
struct FoodWrapper {
mut:
food Food
}
struct Milk {
mut:
name string
}
struct Eggs {
mut:
name string
}
fn test_if_mut_selector() {
mut f := FoodWrapper{Food(Milk{'test'})}
if mut f.food is Milk {
f.food.name = 'milk'
assert f.food.name == 'milk'
}
}
struct NodeWrapper {
node Node
}
fn test_nested_sumtype_selector() {
c := NodeWrapper{Node(Expr(CallExpr{y: 1}))}
if c.node is Expr {
if c.node is CallExpr {
assert c.node.y == 1
}
else {
assert false
}
}
else {
assert false
}
}

View File

@ -0,0 +1,94 @@
type Node = Expr | string
type Expr = IfExpr | IntegerLiteral
struct IntegerLiteral {}
struct IfExpr {
pos int
}
struct NodeWrapper {
node Node
}
fn test_nested_sumtype_match_selector() {
c := NodeWrapper{Node(Expr(IfExpr{pos: 1}))}
match c.node {
Expr {
match c.node {
IfExpr {
assert c.node.pos == 1
}
else {
assert false
}
}
}
else {
assert false
}
}
}
fn test_nested_sumtype_match() {
c := Node(Expr(IfExpr{pos: 1}))
match c {
Expr {
match c {
IfExpr {
assert c.pos == 1
}
else {
assert false
}
}
}
else {
assert false
}
}
}
struct Milk {
mut:
name string
}
struct Eggs {
mut:
name string
}
type Food = Milk | Eggs
struct FoodWrapper {
mut:
food Food
}
fn test_match_mut() {
mut f := Food(Milk{'test'})
match mut f {
Eggs {
f.name = 'eggs'
assert f.name == 'eggs'
}
Milk {
f.name = 'milk'
assert f.name == 'milk'
}
}
}
fn test_match_mut_selector() {
mut f := FoodWrapper{Food(Milk{'test'})}
match mut f.food {
Eggs {
f.food.name = 'eggs'
assert f.food.name == 'eggs'
}
Milk {
f.food.name = 'milk'
assert f.food.name == 'milk'
}
}
}

View File

@ -10,7 +10,6 @@ struct StructDecl {
pos int
}
struct IfExpr {
pos int
}
@ -19,49 +18,24 @@ struct IntegerLiteral {
val string
}
fn handle(e Expr) string {
is_literal := e is IntegerLiteral
assert is_literal
assert !(e !is IntegerLiteral)
if e is IntegerLiteral {
println('int')
}
match e {
IntegerLiteral {
assert e.val == '12'
return 'int'
}
IfExpr {
return 'if'
}
}
return ''
}
fn test_expr() {
expr := IntegerLiteral{
val: '12'
}
assert handle(expr) == 'int'
// assert expr is IntegerLiteral // TODO
}
fn test_assignment_and_push() {
mut expr1 := Expr{}
mut arr1 := []Expr{}
expr := IntegerLiteral{
val: '111'
}
arr1 << expr
match arr1[0] {
IntegerLiteral {
arr1 << arr1[0]
// should ref/dereference on assignent be made automatic?
// currently it is done for return stmt and fn args
expr1 = arr1[0]
}
else {}
}
fn test_sum_type_match() {
// TODO: Remove these casts
assert is_gt_simple('3', int(2))
assert !is_gt_simple('3', int(5))
assert is_gt_simple('3', f64(1.2))
assert !is_gt_simple('3', f64(3.5))
assert is_gt_nested('3', int(2))
assert !is_gt_nested('3', int(5))
assert is_gt_nested('3', f64(1.2))
assert !is_gt_nested('3', f64(3.5))
assert concat('3', int(2)) == '3(int)2'
assert concat('3', int(5)) == '3(int)5'
assert concat('3', f64(1.2)) == '3(float)1.2'
assert concat('3', f64(3.5)) == '3(float)3.5'
assert get_sum('3', int(2)) == 5.0
assert get_sum('3', int(5)) == 8.0
assert get_sum('3', f64(1.2)) == 4.2
assert get_sum('3', f64(3.5)) == 6.5
}
// Test moving structs between master/sub arrays
@ -105,18 +79,121 @@ fn test_converting_down() {
assert res[1].name == 'three'
}
fn test_nested_sumtype() {
c := Node(Expr(IfExpr{pos:1}))
if c is Expr {
if c is IfExpr {
assert true
fn test_assignment_and_push() {
mut expr1 := Expr{}
mut arr1 := []Expr{}
expr := IntegerLiteral{
val: '111'
}
arr1 << expr
match arr1[0] {
IntegerLiteral {
arr1 << arr1[0]
expr1 = arr1[0]
}
else {
assert false
else {}
}
}
fn test_expr() {
expr := IntegerLiteral{
val: '12'
}
assert handle(expr) == 'int'
// assert expr is IntegerLiteral // TODO
}
struct Outer2 {
e Expr
}
fn test_zero_value_init() {
// no c compiler error then it's successful
_ := Outer2{}
}
type Bar = string | Test
type Xyz = int | string
struct Test {
x string
xyz Xyz
}
fn test_assignment() {
y := 5
mut x := Xyz(y)
x = 'test'
if x is string {
x2 := x as string
assert x2 == 'test'
}
}
struct Foo {
y Bar
}
fn test_as_cast() {
f := Foo{
y: Bar('test')
}
y := f.y as string
assert y == 'test'
}
fn test_typeof() {
x := Expr(IfExpr{})
assert typeof(x) == 'IfExpr'
}
type Food = Milk | Eggs
struct FoodWrapper {
mut:
food Food
}
struct Milk {
mut:
name string
}
struct Eggs {
mut:
name string
}
fn test_match_aggregate() {
f := Food(Milk{'test'})
match f {
Milk, Eggs {
assert f.name == 'test'
}
}
else {
assert false
}
fn test_if() {
mut f := Food(Milk{'test'})
if f is Milk {
// only works without smartcast
assert f is Milk
}
}
fn test_match() {
mut f := Food(Milk{'test'})
match f {
Eggs {
// only works without smartcast
assert f is Eggs
}
Milk {
// only works without smartcast
assert f is Milk
}
}
}
@ -158,15 +235,15 @@ fn test_int_cast_to_sumtype() {
}
}
// TODO: change definition once types other than any_int and any_float (int, f64, etc) are supported in sumtype
type Number = any_int | any_float
// TODO: change definition once types other than int and f64 (int, f64, etc) are supported in sumtype
type Number = int | f64
fn is_gt_simple(val string, dst Number) bool {
match dst {
any_int {
int {
return val.int() > dst
}
any_float {
f64 {
return dst < val.f64()
}
}
@ -175,9 +252,9 @@ fn is_gt_simple(val string, dst Number) bool {
fn is_gt_nested(val string, dst Number) bool {
dst2 := dst
match dst {
any_int {
int {
match dst2 {
any_int {
int {
return val.int() > dst
}
// this branch should never been hit
@ -186,9 +263,9 @@ fn is_gt_nested(val string, dst Number) bool {
}
}
}
any_float {
f64 {
match dst2 {
any_float {
f64 {
return dst < val.f64()
}
// this branch should never been hit
@ -202,12 +279,12 @@ fn is_gt_nested(val string, dst Number) bool {
fn concat(val string, dst Number) string {
match dst {
any_int {
int {
mut res := val + '(int)'
res += dst.str()
return res
}
any_float {
f64 {
mut res := val + '(float)'
res += dst.str()
return res
@ -217,12 +294,12 @@ fn concat(val string, dst Number) string {
fn get_sum(val string, dst Number) f64 {
match dst {
any_int {
int {
mut res := val.int()
res += dst
return res
}
any_float {
f64 {
mut res := val.f64()
res += dst
return res
@ -230,21 +307,22 @@ fn get_sum(val string, dst Number) f64 {
}
}
fn test_sum_type_match() {
assert is_gt_simple('3', 2)
assert !is_gt_simple('3', 5)
assert is_gt_simple('3', 1.2)
assert !is_gt_simple('3', 3.5)
assert is_gt_nested('3', 2)
assert !is_gt_nested('3', 5)
assert is_gt_nested('3', 1.2)
assert !is_gt_nested('3', 3.5)
assert concat('3', 2) == '3(int)2'
assert concat('3', 5) == '3(int)5'
assert concat('3', 1.2) == '3(float)1.2'
assert concat('3', 3.5) == '3(float)3.5'
assert get_sum('3', 2) == 5.0
assert get_sum('3', 5) == 8.0
assert get_sum('3', 1.2) == 4.2
assert get_sum('3', 3.5) == 6.5
fn handle(e Expr) string {
is_literal := e is IntegerLiteral
assert is_literal
assert !(e !is IntegerLiteral)
if e is IntegerLiteral {
assert typeof(e.val) == 'string'
}
match e {
IntegerLiteral {
assert e.val == '12'
// assert e.val == '12' // TODO
return 'int'
}
IfExpr {
return 'if'
}
}
return ''
}

View File

@ -1,511 +0,0 @@
type Expr = IfExpr | IntegerLiteral
type Stmt = FnDecl | StructDecl
type Node = Expr | Stmt
struct FnDecl {
pos int
}
struct StructDecl {
pos int
}
struct IfExpr {
pos int
}
struct IntegerLiteral {
val string
}
fn handle(e Expr) string {
is_literal := e is IntegerLiteral
assert is_literal
assert !(e !is IntegerLiteral)
if e is IntegerLiteral {
assert typeof(e.val) == 'string'
}
match e {
IntegerLiteral {
assert e.val == '12'
// assert e.val == '12' // TODO
return 'int'
}
IfExpr {
return 'if'
}
}
return ''
}
fn test_expr() {
expr := IntegerLiteral{
val: '12'
}
assert handle(expr) == 'int'
// assert expr is IntegerLiteral // TODO
}
fn test_assignment_and_push() {
mut expr1 := Expr{}
mut arr1 := []Expr{}
expr := IntegerLiteral{
val: '111'
}
arr1 << expr
match arr1[0] {
IntegerLiteral {
arr1 << arr1[0]
// should ref/dereference on assignent be made automatic?
// currently it is done for return stmt and fn args
expr1 = arr1[0]
}
else {}
}
}
// Test moving structs between master/sub arrays
type Master = Sub1 | Sub2
struct Sub1 {
mut:
val int
name string
}
struct Sub2 {
name string
val int
}
fn test_converting_down() {
mut out := []Master{}
out << Sub1{
val: 1
name: 'one'
}
out << Sub2{
val: 2
name: 'two'
}
out << Sub2{
val: 3
name: 'three'
}
mut res := []Sub2{cap: out.len}
for d in out {
match d {
Sub2 { res << d }
else {}
}
}
assert res[0].val == 2
assert res[0].name == 'two'
assert res[1].val == 3
assert res[1].name == 'three'
}
struct NodeWrapper {
node Node
}
fn test_nested_sumtype_selector() {
c := NodeWrapper{Node(Expr(IfExpr{pos: 1}))}
if c.node is Expr {
if c.node is IfExpr {
assert c.node.pos == 1
}
else {
assert false
}
}
else {
assert false
}
}
fn test_nested_sumtype_match_selector() {
c := NodeWrapper{Node(Expr(IfExpr{pos: 1}))}
match c.node {
Expr {
match c.node {
IfExpr {
assert c.node.pos == 1
}
else {
assert false
}
}
}
else {
assert false
}
}
}
fn test_nested_sumtype() {
c := Node(Expr(IfExpr{pos:1}))
if c is Expr {
if c is IfExpr {
assert c.pos == 1
}
else {
assert false
}
}
else {
assert false
}
}
fn test_nested_sumtype_match() {
c := Node(Expr(IfExpr{pos: 1}))
match c {
Expr {
match c {
IfExpr {
assert c.pos == 1
}
else {
assert false
}
}
}
else {
assert false
}
}
}
type Abc = int | string
fn test_string_cast_to_sumtype() {
a := Abc('test')
match a {
int {
assert false
}
string {
assert true
}
}
}
fn test_int_cast_to_sumtype() {
// literal
a := Abc(111)
match a {
int {
assert true
}
string {
assert false
}
}
// var
i := 111
b := Abc(i)
match b {
int {
assert true
}
string {
assert false
}
}
}
// TODO: change definition once types other than int and f64 (int, f64, etc) are supported in sumtype
type Number = int | f64
fn is_gt_simple(val string, dst Number) bool {
match dst {
int {
return val.int() > dst
}
f64 {
return dst < val.f64()
}
}
}
fn is_gt_nested(val string, dst Number) bool {
dst2 := dst
match dst {
int {
match dst2 {
int {
return val.int() > dst
}
// this branch should never been hit
else {
return val.int() < dst
}
}
}
f64 {
match dst2 {
f64 {
return dst < val.f64()
}
// this branch should never been hit
else {
return dst > val.f64()
}
}
}
}
}
fn concat(val string, dst Number) string {
match dst {
int {
mut res := val + '(int)'
res += dst.str()
return res
}
f64 {
mut res := val + '(float)'
res += dst.str()
return res
}
}
}
fn get_sum(val string, dst Number) f64 {
match dst {
int {
mut res := val.int()
res += dst
return res
}
f64 {
mut res := val.f64()
res += dst
return res
}
}
}
type Bar = string | Test
type Xyz = int | string
struct Test {
x string
xyz Xyz
}
struct Foo {
y Bar
}
fn test_nested_selector_smartcast() {
f := Foo{
y: Bar(Test{
x: 'Hi'
xyz: Xyz(5)
})
}
if f.y is Test {
z := f.y.x
assert f.y.x == 'Hi'
assert z == 'Hi'
if f.y.xyz is int {
assert f.y.xyz == 5
}
}
}
fn test_as_cast() {
f := Foo{
y: Bar('test')
}
y := f.y as string
assert y == 'test'
}
fn test_assignment() {
y := 5
mut x := Xyz(y)
x = 'test'
if x is string {
x2 := x as string
assert x2 == 'test'
}
}
type Inner = int | string
struct InnerStruct {
x Inner
}
type Outer = string | InnerStruct
fn test_nested_if_is() {
b := Outer(InnerStruct{Inner(0)})
if b is InnerStruct {
if b.x is int {
assert b.x == 0
}
}
}
type Expr3 = CallExpr | CTempVarExpr
struct Expr3Wrapper {
mut:
expr Expr3
}
struct CallExpr {
y int
x string
}
struct CTempVarExpr {
x string
}
fn gen(_ Expr3) CTempVarExpr {
return CTempVarExpr{}
}
fn test_reassign_from_function_with_parameter() {
mut f := Expr3(CallExpr{})
if f is CallExpr {
f = gen(f)
}
}
fn test_reassign_from_function_with_parameter_selector() {
mut f := Expr3Wrapper{Expr3(CallExpr{})}
if f.expr is CallExpr {
f.expr = gen(f.expr)
}
}
fn test_typeof() {
x := Expr3(CTempVarExpr{})
assert typeof(x) == 'CTempVarExpr'
}
struct Outer2 {
e Expr3
}
fn test_zero_value_init() {
// no c compiler error then it's successful
_ := Outer2{}
}
struct Milk {
mut:
name string
}
struct Eggs {
mut:
name string
}
type Food = Milk | Eggs
struct FoodWrapper {
mut:
food Food
}
fn test_match_aggregate() {
f := Food(Milk{'test'})
match f {
Milk, Eggs {
assert f.name == 'test'
}
}
}
fn test_match_mut() {
mut f := Food(Milk{'test'})
match mut f {
Eggs {
f.name = 'eggs'
assert f.name == 'eggs'
}
Milk {
f.name = 'milk'
assert f.name == 'milk'
}
}
}
fn test_match_not_mut() {
mut f := Food(Milk{'test'})
match f {
Eggs {
// only works without smartcast
assert f is Eggs
}
Milk {
// only works without smartcast
assert f is Milk
}
}
}
fn test_if_mut() {
mut f := Food(Milk{'test'})
if mut f is Milk {
f.name = 'milk'
assert f.name == 'milk'
}
}
fn test_if_not_mut() {
mut f := Food(Milk{'test'})
if f is Milk {
// only works without smartcast
assert f is Milk
}
}
fn test_match_mut_selector() {
mut f := FoodWrapper{Food(Milk{'test'})}
match mut f.food {
Eggs {
f.food.name = 'eggs'
assert f.food.name == 'eggs'
}
Milk {
f.food.name = 'milk'
assert f.food.name == 'milk'
}
}
}
fn test_if_mut_selector() {
mut f := FoodWrapper{Food(Milk{'test'})}
if mut f.food is Milk {
f.food.name = 'milk'
assert f.food.name == 'milk'
}
}
fn test_sum_type_match() {
// TODO: Remove these casts
assert is_gt_simple('3', int(2))
assert !is_gt_simple('3', int(5))
assert is_gt_simple('3', f64(1.2))
assert !is_gt_simple('3', f64(3.5))
assert is_gt_nested('3', int(2))
assert !is_gt_nested('3', int(5))
assert is_gt_nested('3', f64(1.2))
assert !is_gt_nested('3', f64(3.5))
assert concat('3', int(2)) == '3(int)2'
assert concat('3', int(5)) == '3(int)5'
assert concat('3', f64(1.2)) == '3(float)1.2'
assert concat('3', f64(3.5)) == '3(float)3.5'
assert get_sum('3', int(2)) == 5.0
assert get_sum('3', int(5)) == 8.0
assert get_sum('3', f64(1.2)) == 4.2
assert get_sum('3', f64(3.5)) == 6.5
}