all: remove old sumtype code (#6937)

pull/6939/head
Daniel Däschle 2020-11-24 17:55:24 +01:00 committed by GitHub
parent aa6303f0b2
commit a042966082
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 145 additions and 467 deletions

View File

@ -7,7 +7,7 @@ import v.token
import v.table
import v.errors
pub __type TypeDecl = AliasTypeDecl | FnTypeDecl | SumTypeDecl | UnionSumTypeDecl
pub __type TypeDecl = AliasTypeDecl | FnTypeDecl | UnionSumTypeDecl
pub __type Expr = AnonFn | ArrayInit | AsCast | Assoc | AtExpr | BoolLiteral | CTempVar |
CallExpr | CastExpr | ChanInit | CharLiteral | Comment | ComptimeCall | ConcatExpr | EnumVal |
@ -529,15 +529,14 @@ pub mut:
pub struct IfBranch {
pub:
cond Expr
pos token.Position
body_pos token.Position
comments []Comment
left_as_name string // `name` in `if cond is SumType as name`
is_mut_name bool // `if mut name is`
cond Expr
pos token.Position
body_pos token.Position
comments []Comment
is_mut_name bool // `if mut name is`
pub mut:
stmts []Stmt
smartcast bool // true when cond is `x is SumType`, set in checker.if_expr // no longer needed with union sum types TODO: remove
stmts []Stmt
smartcast bool // true when cond is `x is SumType`, set in checker.if_expr // no longer needed with union sum types TODO: remove
}
pub struct UnsafeExpr {
@ -564,8 +563,7 @@ pub:
branches []MatchBranch
pos token.Position
is_mut bool // `match mut ast_node {`
var_name string // `match cond as var_name {`
is_union_match bool // temporary union key after match
is_union_match bool // TODO: remove
pub mut:
is_expr bool // returns a value
return_type table.Type
@ -748,15 +746,6 @@ pub:
comments []Comment
}
pub struct SumTypeDecl {
pub:
name string
is_pub bool
sub_types []table.Type
pos token.Position
comments []Comment
}
// New implementation of sum types
pub struct UnionSumTypeDecl {
pub:
@ -1152,7 +1141,7 @@ pub fn (stmt Stmt) position() token.Position {
AssertStmt, AssignStmt, Block, BranchStmt, CompFor, ConstDecl, DeferStmt, EnumDecl, ExprStmt, FnDecl, ForCStmt, ForInStmt, ForStmt, GotoLabel, GotoStmt, Import, Return, StructDecl, GlobalDecl, HashStmt, InterfaceDecl, Module, SqlStmt { return stmt.pos }
GoStmt { return stmt.call_expr.position() }
TypeDecl { match union stmt {
AliasTypeDecl, FnTypeDecl, SumTypeDecl, UnionSumTypeDecl { return stmt.pos }
AliasTypeDecl, FnTypeDecl, UnionSumTypeDecl { return stmt.pos }
} }
// Please, do NOT use else{} here.
// This match is exhaustive *on purpose*, to help force

View File

@ -325,7 +325,7 @@ pub fn (c &Checker) get_default_fmt(ftyp table.Type, typ table.Type) byte {
}
if ftyp in [table.string_type, table.bool_type] ||
sym.kind in
[.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .sum_type] || ftyp.has_flag(.optional) ||
[.enum_, .array, .array_fixed, .struct_, .map, .multi_return, .union_sum_type] || ftyp.has_flag(.optional) ||
sym.has_method('str') {
return `s`
} else {

View File

@ -237,7 +237,7 @@ fn (mut c Checker) check_file_in_main(file ast.File) bool {
if stmt.is_pub {
c.warn('type alias `$stmt.name` $no_pub_in_main_warning', stmt.pos)
}
} else if stmt is ast.SumTypeDecl {
} else if stmt is ast.UnionSumTypeDecl {
if stmt.is_pub {
c.warn('sum type `$stmt.name` $no_pub_in_main_warning', stmt.pos)
}
@ -311,17 +311,6 @@ pub fn (mut c Checker) type_decl(node ast.TypeDecl) {
}
}
}
ast.SumTypeDecl {
c.check_valid_pascal_case(node.name, 'sum type', node.pos)
for typ in node.sub_types {
typ_sym := c.table.get_type_symbol(typ)
if typ_sym.kind == .placeholder {
c.error("type `$typ_sym.source_name` doesn't exist", node.pos)
} else if typ_sym.kind == .interface_ {
c.error('sum type cannot hold an interface', node.pos)
}
}
}
ast.UnionSumTypeDecl {
c.check_valid_pascal_case(node.name, 'sum type', node.pos)
for typ in node.sub_types {
@ -456,7 +445,7 @@ pub fn (mut c Checker) struct_init(mut struct_init ast.StructInit) table.Type {
c.error('unknown type', struct_init.pos)
}
type_sym := c.table.get_type_symbol(struct_init.typ)
if type_sym.kind == .sum_type && struct_init.fields.len == 1 {
if type_sym.kind == .union_sum_type && struct_init.fields.len == 1 {
sexpr := struct_init.fields[0].expr.str()
c.error('cast to sum type using `${type_sym.source_name}($sexpr)` not `$type_sym.source_name{$sexpr}`',
struct_init.pos)
@ -804,12 +793,11 @@ pub fn (mut c Checker) infix_expr(mut infix_expr ast.InfixExpr) table.Type {
c.error('$infix_expr.op.str(): type `$typ_sym.source_name` does not exist',
type_expr.pos)
}
if left.kind !in [.interface_, .sum_type, .union_sum_type] {
if left.kind !in [.interface_, .union_sum_type] {
c.error('`$infix_expr.op.str()` can only be used with interfaces and sum types',
infix_expr.pos)
} else if left.kind == .union_sum_type {
info := left.info as table.UnionSumType
if type_expr.typ !in info.variants {
} else if mut left.info is table.UnionSumType {
if type_expr.typ !in left.info.variants {
c.error('`$left.source_name` has no variant `$right.source_name`',
infix_expr.pos)
}
@ -1110,7 +1098,7 @@ pub fn (mut c Checker) call_method(mut call_expr ast.CallExpr) table.Type {
c.error('optional type cannot be called directly', call_expr.left.position())
return table.void_type
}
if left_type_sym.kind == .sum_type && method_name == 'type_name' {
if left_type_sym.kind == .union_sum_type && method_name == 'type_name' {
return table.string_type
}
// TODO: remove this for actual methods, use only for compiler magic
@ -2294,7 +2282,7 @@ pub fn (mut c Checker) array_init(mut array_init ast.ArrayInit) table.Type {
if array_init.has_default {
c.expr(array_init.default_expr)
}
if sym.kind in [.sum_type, .union_sum_type] {
if sym.kind == .union_sum_type {
if array_init.has_len && !array_init.has_default {
c.error('cannot initalize sum type array without default value', array_init.elem_type_pos)
}
@ -2799,7 +2787,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
node.expr_type = c.expr(node.expr)
expr_type_sym := c.table.get_type_symbol(node.expr_type)
type_sym := c.table.get_type_symbol(node.typ)
if expr_type_sym.kind == .sum_type || expr_type_sym.kind == .union_sum_type {
if expr_type_sym.kind == .union_sum_type {
if type_sym.kind == .placeholder {
// Unknown type used in the right part of `as`
c.error('unknown type `$type_sym.source_name`', node.pos)
@ -2811,7 +2799,7 @@ pub fn (mut c Checker) expr(node ast.Expr) table.Type {
}
} else {
mut s := 'cannot cast non-sum type `$expr_type_sym.source_name` using `as`'
if type_sym.kind == .sum_type || expr_type_sym.kind == .union_sum_type {
if type_sym.kind == .union_sum_type {
s += ' - use e.g. `${type_sym.source_name}(some_expr)` instead.'
}
c.error(s, node.pos)
@ -3066,7 +3054,7 @@ pub fn (mut c Checker) cast_expr(mut node ast.CastExpr) table.Type {
c.error('can not cast type `byte` to string, use `${node.expr.str()}.str()` instead.',
node.pos)
}
if to_type_sym.kind == .sum_type || to_type_sym.kind == .union_sum_type {
if to_type_sym.kind == .union_sum_type {
if node.expr_type in [table.any_int_type, table.any_flt_type] {
node.expr_type = c.promote_num(node.expr_type, if node.expr_type == table.any_int_type { table.int_type } else { table.f64_type })
}
@ -3377,7 +3365,7 @@ pub fn (mut c Checker) match_expr(mut node ast.MatchExpr) table.Type {
c.error('compiler bug: match 0 cond type', node.pos)
}
cond_type_sym := c.table.get_type_symbol(cond_type)
if cond_type_sym.kind !in [.sum_type, .interface_, .union_sum_type] {
if cond_type_sym.kind !in [.interface_, .union_sum_type] {
node.is_sum_type = false
}
c.match_exprs(mut node, cond_type_sym)
@ -3599,8 +3587,8 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
// smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_mut || node.is_mut) && !is_already_casted {
sum_type_casts << expr_type
scope.register(node.var_name, ast.Var{
name: node.var_name
scope.register(node.cond.name, ast.Var{
name: node.cond.name
typ: node.cond_type
pos: node.cond.pos
is_used: true
@ -3621,15 +3609,6 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, type_sym table.TypeSymbol
mut is_exhaustive := true
mut unhandled := []string{}
match union mut type_sym.info {
table.SumType {
for v in type_sym.info.variants {
v_str := c.table.type_to_str(v)
if v_str !in branch_exprs {
is_exhaustive = false
unhandled << '`$v_str`'
}
}
}
table.UnionSumType {
for v in type_sym.info.variants {
v_str := c.table.type_to_str(v)
@ -3833,7 +3812,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
is_variable := if mut infix.left is ast.Ident { infix.left.kind == .variable } else { true }
// Register shadow variable or `as` variable with actual type
if is_variable {
if left_sym.kind in [.sum_type, .interface_, .union_sum_type] {
if left_sym.kind in [.interface_, .union_sum_type] {
mut is_mut := false
mut scope := c.file.scope.innermost(branch.body_pos.pos)
if mut infix.left is ast.Ident {
@ -3842,18 +3821,30 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
is_mut = v.is_mut
sum_type_casts << v.sum_type_casts
}
// smartcast either if the value is immutable or if the mut argument is explicitly given
if (!is_mut || branch.is_mut_name) &&
left_sym.kind == .union_sum_type {
sum_type_casts << right_expr.typ
scope.register(branch.left_as_name, ast.Var{
name: branch.left_as_name
typ: infix.left_type
if left_sym.kind == .union_sum_type {
// smartcast either if the value is immutable or if the mut argument is explicitly given
if !is_mut || branch.is_mut_name {
sum_type_casts << right_expr.typ
scope.register(infix.left.name, ast.Var{
name: infix.left.name
typ: infix.left_type
sum_type_casts: sum_type_casts
pos: infix.left.pos
is_used: true
is_mut: is_mut
})
}
} else if left_sym.kind == .interface_ {
scope.register(infix.left.name, ast.Var{
name: infix.left.name
typ: right_expr.typ.to_ptr()
sum_type_casts: sum_type_casts
pos: infix.left.pos
is_used: true
is_mut: is_mut
})
// TODO: remove that later @danieldaeschle
node.branches[i].smartcast = true
}
} else if mut infix.left is ast.SelectorExpr {
mut sum_type_casts := []table.Type{}
@ -3881,16 +3872,6 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
})
}
}
if left_sym.kind != .union_sum_type && branch.left_as_name.len > 0 {
scope.register(branch.left_as_name, ast.Var{
name: branch.left_as_name
typ: right_expr.typ.to_ptr()
pos: infix.left.position()
is_used: true
is_mut: is_mut
})
node.branches[i].smartcast = true
}
}
}
}
@ -4068,7 +4049,7 @@ fn (mut c Checker) comp_if_branch(cond ast.Expr, pos token.Position) bool {
return false // TODO
} else if cond.name in valid_comp_if_other {
// TODO: This should probably be moved
match cond.name as name {
match cond.name {
'js' { return c.pref.backend != .js }
'debug' { return !c.pref.is_debug }
'test' { return !c.pref.is_test }
@ -4525,7 +4506,7 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) {
if sym.kind == .interface_ {
c.error('interfaces cannot be used as method receiver', node.receiver_pos)
}
if sym.kind == .sum_type && node.name == 'type_name' {
if sym.kind == .union_sum_type && node.name == 'type_name' {
c.error('method overrides built-in sum type method', node.pos)
}
// if sym.has_method(node.name) {

View File

@ -1,8 +1,8 @@
vlib/v/checker/tests/is_type_invalid.vv:14:2: error: cannot use type `byte` as type `IoS`
vlib/v/checker/tests/is_type_invalid.vv:14:12: error: `IoS` has no variant `byte`
12 |
13 | fn main() {
14 | if IoS(1) is byte {
| ~~~~~~~~~~~~~~~~~
| ~~
15 | println('not cool')
16 | }
vlib/v/checker/tests/is_type_invalid.vv:18:2: error: `Cat` doesn't implement method `speak`
@ -11,4 +11,4 @@ vlib/v/checker/tests/is_type_invalid.vv:18:2: error: `Cat` doesn't implement met
18 | if a is Cat {
| ~~~~~~~~~~~
19 | println('not cool either')
20 | }
20 | }

View File

@ -1,4 +1,4 @@
vlib/v/checker/tests/match_invalid_type.vv:5:3: error: cannot match `byte` with `IoS` condition
vlib/v/checker/tests/match_invalid_type.vv:5:3: error: `IoS` has no variant `byte`
3 | fn sum() {
4 | match IoS(1) {
5 | byte {

View File

@ -1,14 +1,14 @@
vlib/v/checker/tests/match_sumtype_multiple_types.vv:25:13: error: type `Charlie` has no field or method `char`
23 | match NATOAlphabet(a) as l {
24 | Alfa, Charlie {
25 | assert l.char == `a`
vlib/v/checker/tests/match_sumtype_multiple_types.vv:26:13: error: type `Charlie` has no field or method `char`
24 | match l {
25 | Alfa, Charlie {
26 | assert l.char == `a`
| ~~~~
26 | assert l.letter() == 'a'
27 | }
vlib/v/checker/tests/match_sumtype_multiple_types.vv:26:13: error: unknown method: `Charlie.letter`
24 | Alfa, Charlie {
25 | assert l.char == `a`
26 | assert l.letter() == 'a'
27 | assert l.letter() == 'a'
28 | }
vlib/v/checker/tests/match_sumtype_multiple_types.vv:27:13: error: unknown method: `Charlie.letter`
25 | Alfa, Charlie {
26 | assert l.char == `a`
27 | assert l.letter() == 'a'
| ~~~~~~~~~
27 | }
28 | Bravo {
28 | }
29 | Bravo {

View File

@ -20,7 +20,8 @@ type NATOAlphabet = Alfa | Bravo | Charlie
fn method_not_exists() {
a := Alfa{}
match NATOAlphabet(a) as l {
l := NATOAlphabet(a)
match l {
Alfa, Charlie {
assert l.char == `a`
assert l.letter() == 'a'

View File

@ -96,7 +96,7 @@ pub fn (d Doc) stmt_name(stmt ast.Stmt) string {
match union stmt {
ast.FnDecl, ast.StructDecl, ast.EnumDecl, ast.InterfaceDecl { return stmt.name }
ast.TypeDecl { match union stmt {
ast.SumTypeDecl, ast.FnTypeDecl, ast.AliasTypeDecl, ast.UnionSumTypeDecl { return stmt.name }
ast.FnTypeDecl, ast.AliasTypeDecl, ast.UnionSumTypeDecl { return stmt.name }
} }
ast.ConstDecl { return '' } // leave it blank
else { return '' }

View File

@ -454,7 +454,7 @@ pub fn (mut f Fmt) stmt(node ast.Stmt) {
f.write('sql ')
f.expr(node.db_expr)
f.writeln(' {')
match node.kind as k {
match node.kind {
.insert {
f.writeln('\tinsert $node.object_var_name into ${util.strip_mod_name(node.table_name)}')
}
@ -544,26 +544,6 @@ pub fn (mut f Fmt) type_decl(node ast.TypeDecl) {
}
comments << node.comments
}
ast.SumTypeDecl {
if node.is_pub {
f.write('pub ')
}
f.write('type $node.name = ')
mut sum_type_names := []string{}
for t in node.sub_types {
sum_type_names << f.table.type_to_str(t)
}
sum_type_names.sort()
for i, name in sum_type_names {
f.write(name)
if i < sum_type_names.len - 1 {
f.write(' | ')
}
f.wrap_long_line(2, true)
}
// f.write(sum_type_names.join(' | '))
comments << node.comments
}
ast.UnionSumTypeDecl {
if node.is_pub {
f.write('pub ')
@ -1412,15 +1392,6 @@ pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
(it.is_expr || f.is_assign)
f.single_line_if = single_line
for i, branch in it.branches {
// Check `sum is T` smartcast
mut smartcast_as := false
if branch.cond is ast.InfixExpr {
if branch.cond.op == .key_is {
// left_as_name is either empty, branch.cond.left.str() or the `as` name
smartcast_as = branch.left_as_name.len > 0 &&
branch.cond.left.str() != branch.left_as_name
}
}
if i == 0 {
// first `if`
f.comments(branch.comments, {})
@ -1440,9 +1411,6 @@ pub fn (mut f Fmt) if_expr(it ast.IfExpr) {
f.write('mut ')
}
f.expr(branch.cond)
if smartcast_as {
f.write(' as $branch.left_as_name')
}
f.write(' ')
}
f.write('{')
@ -1560,7 +1528,6 @@ pub fn (mut f Fmt) call_expr(node ast.CallExpr) {
pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
f.write('match ')
// TODO: temporary, remove again
if it.is_union_match {
f.write('union ')
}
@ -1570,12 +1537,6 @@ pub fn (mut f Fmt) match_expr(it ast.MatchExpr) {
f.expr(it.cond)
if it.cond is ast.Ident {
f.it_name = it.cond.name
} else if it.cond is ast.SelectorExpr {
// `x.y as z`
// if ident.name != it.var_name && it.var_name != '' {
}
if it.var_name != '' && f.it_name != it.var_name {
f.write(' as $it.var_name')
}
f.writeln(' {')
f.indent++

View File

@ -4,7 +4,7 @@ struct IfExpr {
struct MatchExpr {
}
type Expr = IfExpr | MatchExpr
__type Expr = IfExpr | MatchExpr
fn sum_types(a []Expr) {
}

View File

@ -15,7 +15,7 @@ fn handle_users(users []User) {
fn (u &User) foo(u2 &User) {
}
type Expr = IfExpr | IntegerLiteral
__type Expr = IfExpr | IntegerLiteral
fn exprs(e []Expr) {
println(e.len)

View File

@ -6,17 +6,15 @@ mut:
struct S2 {
}
type Sum = S1 | S2
__type Sum = S1 | S2
fn f(sum Sum) {
if mut sum is S1 {
sum.i++
}
if sum is S1 as s1 {
if sum is S1 {
}
a := [sum]
if a[0] is S2 {
}
if a[0] is S2 as s2 {
}
}

View File

@ -1,11 +1,11 @@
// Sumtype
type FooBar = Bar | Foo
__type FooBar = Bar | Foo
pub type PublicBar = Bar | Foo | FooBar
pub __type PublicBar = Bar | Foo | FooBar
type Uint = byte | u16 | u32 | u64 // This should stay on the same line
__type Uint = byte | u16 | u32 | u64
type Float = f32 | f64
__type Float = f32 | f64
// Alias type
type MyInt = int

View File

@ -6,7 +6,7 @@
type Uint = u16 | u64
| u32
| byte // This should stay on the same line
| byte
type
Float =
f32 |

View File

@ -73,9 +73,6 @@ fn (mut g Gen) gen_str_for_type_with_styp(typ table.Type, styp string) string {
table.MultiReturn {
g.gen_str_for_multi_return(sym.info, styp, str_fn_name)
}
table.SumType {
g.gen_str_for_sum_type(sym.info, styp, str_fn_name)
}
table.UnionSumType {
g.gen_str_for_union_sum_type(sym.info, styp, str_fn_name)
}
@ -441,7 +438,7 @@ fn struct_auto_str_func(sym table.TypeSymbol, field_type table.Type, fn_name str
return '${fn_name}($obj)'
}
return 'indent_${fn_name}($obj, indent_count + 1)'
} else if sym.kind in [.array, .array_fixed, .map, .sum_type] {
} else if sym.kind in [.array, .array_fixed, .map, .union_sum_type] {
if has_custom_str {
return '${fn_name}(it->${c_name(field_name)})'
}
@ -485,50 +482,6 @@ fn (mut g Gen) gen_str_for_enum(info table.Enum, styp string, str_fn_name string
g.auto_str_funcs.writeln('}')
}
fn (mut g Gen) gen_str_for_sum_type(info table.SumType, styp string, str_fn_name string) {
mut gen_fn_names := map[string]string{}
for typ in info.variants {
sym := g.table.get_type_symbol(typ)
if !sym.has_method('str') {
field_styp := g.typ(typ)
field_fn_name := g.gen_str_for_type_with_styp(typ, field_styp)
gen_fn_names[field_styp] = field_fn_name
}
}
// _str() functions should have a single argument, the indenting ones take 2:
g.type_definitions.writeln('string ${str_fn_name}($styp x); // auto')
g.auto_str_funcs.writeln('string ${str_fn_name}($styp x) { return indent_${str_fn_name}(x, 0); }')
g.type_definitions.writeln('string indent_${str_fn_name}($styp x, int indent_count); // auto')
g.auto_str_funcs.writeln('string indent_${str_fn_name}($styp x, int indent_count) {')
mut clean_sum_type_v_type_name := styp.replace('__', '.')
if styp.ends_with('*') {
clean_sum_type_v_type_name = '&' + clean_sum_type_v_type_name.replace('*', '')
}
clean_sum_type_v_type_name = util.strip_main_name(clean_sum_type_v_type_name)
g.auto_str_funcs.writeln('\tswitch(x.typ) {')
for typ in info.variants {
mut value_fmt := '%.*s\\000'
if typ == table.string_type {
value_fmt = "\'$value_fmt\'"
}
typ_str := g.typ(typ)
mut func_name := if typ_str in gen_fn_names { gen_fn_names[typ_str] } else { g.gen_str_for_type_with_styp(typ,
typ_str) }
sym := g.table.get_type_symbol(typ)
if sym.kind == .struct_ {
func_name = 'indent_$func_name'
}
g.auto_str_funcs.write('\t\tcase $typ: return _STR("${clean_sum_type_v_type_name}($value_fmt)", 2, ${func_name}(*($typ_str*)x._object')
if sym.kind == .struct_ {
g.auto_str_funcs.write(', indent_count')
}
g.auto_str_funcs.writeln('));')
}
g.auto_str_funcs.writeln('\t\tdefault: return tos_lit("unknown sum type value");')
g.auto_str_funcs.writeln('\t}')
g.auto_str_funcs.writeln('}')
}
fn (mut g Gen) gen_str_for_union_sum_type(info table.UnionSumType, styp string, str_fn_name string) {
mut gen_fn_names := map[string]string{}
for typ in info.variants {

View File

@ -370,22 +370,6 @@ pub fn (mut g Gen) finish() {
pub fn (mut g Gen) write_typeof_functions() {
g.writeln('')
g.writeln('// >> typeof() support for sum types')
for typ in g.table.types {
if typ.kind == .sum_type {
sum_info := typ.info as table.SumType
tidx := g.table.find_type_idx(typ.name)
g.writeln('char * v_typeof_sumtype_${tidx}(int sidx) { /* $typ.name */ ')
g.writeln(' switch(sidx) {')
g.writeln(' case $tidx: return "${util.strip_main_name(typ.name)}";')
for v in sum_info.variants {
subtype := g.table.get_type_symbol(v)
g.writeln(' case $v: return "${util.strip_main_name(subtype.name)}";')
}
g.writeln(' default: return "unknown ${util.strip_main_name(typ.name)}";')
g.writeln(' }')
g.writeln('}')
}
}
for typ in g.table.types {
if typ.kind == .union_sum_type {
sum_info := typ.info as table.UnionSumType
@ -2293,7 +2277,7 @@ fn (mut g Gen) expr(node ast.Expr) {
g.expr(node.arg)
}
g.write(')')
} else if sym.kind in [.sum_type, .union_sum_type] {
} else if sym.kind == .union_sum_type {
g.expr_with_cast(node.expr, node.expr_type, node.typ)
} else if sym.kind == .struct_ && !node.typ.is_ptr() && !(sym.info as table.Struct).is_typedef {
styp := g.typ(node.typ)
@ -2649,14 +2633,7 @@ fn (mut g Gen) type_name(type_ table.Type) {
fn (mut g Gen) typeof_expr(node ast.TypeOf) {
sym := g.table.get_type_symbol(node.expr_type)
if sym.kind == .sum_type {
// When encountering a .sum_type, typeof() should be done at runtime,
// because the subtype of the expression may change:
sum_type_idx := node.expr_type.idx()
g.write('tos3( /* $sym.name */ v_typeof_sumtype_${sum_type_idx}( (')
g.expr(node.expr)
g.write(').typ ))')
} else if sym.kind == .union_sum_type {
if sym.kind == .union_sum_type {
// When encountering a .sum_type, typeof() should be done at runtime,
// because the subtype of the expression may change:
sum_type_idx := node.expr_type.idx()
@ -3098,7 +3075,7 @@ fn (mut g Gen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var str
}
g.write(cond_var)
// branch_sym := g.table.get_type_symbol(branch.typ)
if sym.kind in [.sum_type, .union_sum_type] {
if sym.kind == .union_sum_type {
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
g.write(dot_or_ptr)
g.write('typ == ')
@ -3113,25 +3090,6 @@ fn (mut g Gen) match_expr_sumtype(node ast.MatchExpr, is_expr bool, cond_var str
g.writeln(') {')
}
}
// g.writeln('/* M sum_type=$node.is_sum_type is_expr=$node.is_expr exp_type=${g.typ(node.expected_type)}*/')
if sym.kind != .union_sum_type && !branch.is_else && !node.is_expr {
// Use the nodes in the expr to generate `it` variable.
type_expr := branch.exprs[sumtype_index]
if type_expr !is ast.Type {
verror('match sum type')
}
it_type := g.typ((type_expr as ast.Type).typ)
// g.writeln('$it_type* it = ($it_type*)${tmp}.obj; // ST it')
g.write('\t$it_type* it = ($it_type*)')
g.write(cond_var)
dot_or_ptr := if node.cond_type.is_ptr() { '->' } else { '.' }
g.write(dot_or_ptr)
g.writeln('_object; // ST it')
if node.var_name.len > 0 {
// for now we just copy it
g.writeln('\t$it_type* $node.var_name = it;')
}
}
g.stmts(branch.stmts)
if g.inside_ternary == 0 {
g.write('}')
@ -3449,13 +3407,6 @@ fn (mut g Gen) match_sumtype_has_no_struct_and_contains(node ast.Ident) bool {
if expr is ast.Ident && node.name == (expr as ast.Ident).name {
info := g.match_sumtype_syms[i].info
match union info {
table.SumType {
for typ in info.variants {
if g.table.get_type_symbol(typ).kind == .struct_ {
return false
}
}
}
table.UnionSumType {
for typ in info.variants {
if g.table.get_type_symbol(typ).kind == .struct_ {
@ -3591,18 +3542,20 @@ fn (mut g Gen) if_expr(node ast.IfExpr) {
}
if branch.smartcast && branch.stmts.len > 0 {
infix := branch.cond as ast.InfixExpr
right_type := infix.right as ast.Type
left_type := infix.left_type
it_type := g.typ(right_type.typ)
g.write('\t$it_type* _sc_tmp_$branch.pos.pos = ($it_type*)')
g.expr(infix.left)
if left_type.is_ptr() {
g.write('->')
} else {
g.write('.')
if mut infix.left is ast.Ident {
right_type := infix.right as ast.Type
left_type := infix.left_type
it_type := g.typ(right_type.typ)
g.write('\t$it_type* _sc_tmp_$branch.pos.pos = ($it_type*)')
g.expr(infix.left)
if left_type.is_ptr() {
g.write('->')
} else {
g.write('.')
}
g.writeln('_object;')
g.writeln('\t$it_type* $infix.left.name = _sc_tmp_$branch.pos.pos;')
}
g.writeln('_object;')
g.writeln('\t$it_type* $branch.left_as_name = _sc_tmp_$branch.pos.pos;')
}
if needs_tmp_var {
g.stmts_with_tmp_var(branch.stmts, tmp)
@ -4640,19 +4593,7 @@ fn (mut g Gen) write_types(types []table.TypeSymbol) {
g.type_definitions.writeln('};\n')
}
table.Alias {
// table.Alias, table.SumType { TODO
}
table.SumType {
g.type_definitions.writeln('')
g.type_definitions.writeln('// Sum type $name = ')
for sv in typ.info.variants {
g.type_definitions.writeln('// | ${sv:4d} = ${g.typ(sv):-20s}')
}
g.type_definitions.writeln('typedef struct {')
g.type_definitions.writeln(' void* _object;')
g.type_definitions.writeln(' int typ;')
g.type_definitions.writeln('} $name;')
g.type_definitions.writeln('')
// table.Alias { TODO
}
table.UnionSumType {
g.typedefs.writeln('typedef struct $name $name;')
@ -4781,7 +4722,7 @@ fn (mut g Gen) gen_expr_to_string(expr ast.Expr, etype table.Type) ?bool {
g.write('")')
}
} else if sym_has_str_method || sym.kind in
[.array, .array_fixed, .map, .struct_, .multi_return, .sum_type] {
[.array, .array_fixed, .map, .struct_, .multi_return, .union_sum_type] {
is_p := typ.is_ptr()
val_type := if is_p { typ.deref() } else { typ }
str_fn_name := g.gen_str_for_type(val_type)
@ -5449,7 +5390,7 @@ fn (mut g Gen) type_default(typ_ table.Type) string {
else {}
}
return match sym.kind {
.interface_, .union_sum_type, .sum_type, .array_fixed, .multi_return { '{0}' }
.interface_, .union_sum_type, .array_fixed, .multi_return { '{0}' }
.alias { g.type_default((sym.info as table.Alias).parent_type) }
else { '0' }
}
@ -5604,23 +5545,7 @@ fn (mut g Gen) as_cast(node ast.AsCast) {
// g.insert_before('
styp := g.typ(node.typ)
expr_type_sym := g.table.get_type_symbol(node.expr_type)
if expr_type_sym.kind == .sum_type {
/*
g.write('*($styp*)')
g.expr(node.expr)
g.write('.obj')
*/
dot := if node.expr_type.is_ptr() { '->' } else { '.' }
g.write('/* as */ ($styp*)__as_cast((')
g.expr(node.expr)
g.write(')')
g.write(dot)
g.write('_object, (')
g.expr(node.expr)
g.write(')')
g.write(dot)
g.write('typ, /*expected:*/$node.typ)')
} else if expr_type_sym.kind == .union_sum_type {
if expr_type_sym.kind == .union_sum_type {
dot := if node.expr_type.is_ptr() { '->' } else { '.' }
g.write('/* as */ *($styp*)__as_cast((')
g.expr(node.expr)
@ -5652,7 +5577,7 @@ fn (mut g Gen) is_expr(node ast.InfixExpr) {
sub_sym := g.table.get_type_symbol(sub_type.typ)
g.write('_${c_name(sym.name)}_${c_name(sub_sym.name)}_index')
return
} else if sym.kind in [.sum_type, .union_sum_type] {
} else if sym.kind == .union_sum_type {
g.write('typ $eq ')
}
g.expr(node.right)
@ -5719,7 +5644,7 @@ fn (g &Gen) type_to_fmt(typ table.Type) string {
return '%g\\000' // g removes trailing zeros unlike %f
} else if sym.kind == .u64 {
return '%lld\\000'
} else if sym.kind == .sum_type {
} else if sym.kind == .union_sum_type {
return '%.*s\\000'
}
return '%d\\000'

View File

@ -366,8 +366,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
else {}
}
}
if left_sym.kind == .sum_type && node.name == 'type_name' {
g.write('tos3( /* $left_sym.name */ v_typeof_sumtype_${node.receiver_type}( (')
if left_sym.kind == .union_sum_type && node.name == 'type_name' {
g.write('tos3( /* $left_sym.name */ v_typeof_unionsumtype_${node.receiver_type}( (')
g.expr(node.left)
g.write(').typ ))')
return
@ -887,7 +887,7 @@ fn (mut g Gen) ref_or_deref_arg(arg ast.CallArg, expected_type table.Type) {
}
arg_typ_sym := g.table.get_type_symbol(arg.typ)
expected_deref_type := if expected_type.is_ptr() { expected_type.deref() } else { expected_type }
is_sum_type := g.table.get_type_symbol(expected_deref_type).kind == .sum_type
is_sum_type := g.table.get_type_symbol(expected_deref_type).kind == .union_sum_type
if !((arg_typ_sym.kind == .function) || is_sum_type) {
g.write('(voidptr)&/*qq*/')
}

View File

@ -257,10 +257,6 @@ pub fn (mut g JsGen) typ(t table.Type) string {
joined := types.join(', ')
styp = '[$joined]'
}
.sum_type {
// TODO: Implement sumtypes
styp = 'sym_type'
}
.union_sum_type {
// TODO: Implement sumtypes
styp = 'union_sym_type'
@ -1504,7 +1500,7 @@ fn (mut g JsGen) gen_struct_init(it ast.StructInit) {
fn (mut g JsGen) gen_typeof_expr(it ast.TypeOf) {
sym := g.table.get_type_symbol(it.expr_type)
if sym.kind == .sum_type {
if sym.kind == .union_sum_type {
// TODO: JS sumtypes not implemented yet
} else if sym.kind == .array_fixed {
fixed_info := sym.info as table.ArrayFixed

View File

@ -567,7 +567,7 @@ fn (mut p Parser) fn_args() ([]table.Param, bool, bool) {
fn (mut p Parser) check_fn_mutable_arguments(typ table.Type, pos token.Position) {
sym := p.table.get_type_symbol(typ)
if sym.kind !in [.array, .struct_, .map, .placeholder, .sum_type] && !typ.is_ptr() {
if sym.kind !in [.array, .struct_, .map, .placeholder, .union_sum_type] && !typ.is_ptr() {
p.error_with_pos('mutable arguments are only allowed for arrays, maps, and structs\n' +
'return values instead: `fn foo(mut n $sym.name) {` => `fn foo(n $sym.name) $sym.name {`',
pos)

View File

@ -6,7 +6,6 @@ module parser
import v.ast
import v.table
import v.token
import strings
fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
was_inside_if_expr := p.inside_if_expr
@ -121,22 +120,9 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
cond = p.expr(0)
}
comments << p.eat_comments()
mut left_as_name := ''
if mut cond is ast.InfixExpr {
// if sum is T
is_is_cast := cond.op == .key_is
is_ident := cond.left is ast.Ident
left_as_name = if is_comptime {
''
} else if is_is_cast && p.tok.kind == .key_as {
p.next()
p.check_name()
} else if is_ident {
ident := cond.left as ast.Ident
ident.name
} else {
''
}
if !is_is_cast && is_mut_name {
p.error_with_pos('remove unnecessary `mut`', mut_pos)
}
@ -156,7 +142,6 @@ fn (mut p Parser) if_expr(is_comptime bool) ast.IfExpr {
pos: start_pos.extend(end_pos)
body_pos: body_pos.extend(p.prev_tok.position())
comments: comments
left_as_name: left_as_name
is_mut_name: is_mut_name
}
comments = p.eat_comments()
@ -195,14 +180,8 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
if is_mut {
p.next()
}
cond_pos := p.tok.position()
cond := p.expr(0)
p.inside_match = false
mut var_name := ''
if p.tok.kind == .key_as {
p.next()
var_name = p.check_name()
}
no_lcbr := p.tok.kind != .lcbr
if !no_lcbr {
p.check(.lcbr)
@ -222,20 +201,6 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
} else if p.tok.kind == .name && !(p.tok.lit == 'C' &&
p.peek_tok.kind == .dot) && (p.tok.lit in table.builtin_type_names || p.tok.lit[0].is_capital() ||
(p.peek_tok.kind == .dot && p.peek_tok2.lit[0].is_capital())) {
if var_name.len == 0 {
match union cond {
ast.Ident {
// shadow match cond variable
var_name = cond.name
}
else {
// ast.SelectorExpr {
// p.error('expecting `as` (eg. `match user.attribute as user_attr`) when matching struct fields')
// }
// p.error('only variables can be used in sum types matches')
}
}
}
mut types := []table.Type{}
for {
// Sum type match
@ -251,52 +216,6 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
}
p.check(.comma)
}
if !is_union_match {
mut it_typ := table.void_type
if types.len == 1 {
it_typ = types[0]
} else {
// there is more than one types, so we must create a type aggregate
mut agg_name := strings.new_builder(20)
agg_name.write('(')
for i, typ in types {
if i > 0 {
agg_name.write(' | ')
}
type_str := p.table.type_to_str(typ)
agg_name.write(p.prepend_mod(type_str))
}
agg_name.write(')')
name := agg_name.str()
it_typ = p.table.register_type_symbol(table.TypeSymbol{
name: name
source_name: name
kind: .aggregate
mod: p.mod
info: table.Aggregate{
types: types
}
})
}
p.scope.register('it', ast.Var{
name: 'it'
typ: it_typ.to_ptr()
pos: cond_pos
is_used: true
is_mut: is_mut
})
if var_name.len > 0 {
// Register shadow variable or `as` variable with actual type
p.scope.register(var_name, ast.Var{
name: var_name
typ: it_typ.to_ptr()
pos: cond_pos
is_used: true
is_changed: true // TODO mut unchanged warning hack, remove
is_mut: is_mut
})
}
}
is_sum_type = true
} else {
// Expression match
@ -366,10 +285,9 @@ fn (mut p Parser) match_expr() ast.MatchExpr {
branches: branches
cond: cond
is_sum_type: is_sum_type
is_union_match: is_union_match
pos: pos
is_mut: is_mut
var_name: var_name
is_union_match: is_union_match
}
}

View File

@ -1999,17 +1999,17 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
}
prepend_mod_name := p.prepend_mod(name)
p.table.register_type_symbol(table.TypeSymbol{
kind: .sum_type
kind: .union_sum_type
name: prepend_mod_name
source_name: prepend_mod_name
mod: p.mod
info: table.SumType{
info: table.UnionSumType{
variants: sum_variants
}
is_public: is_pub
})
comments = p.eat_lineend_comments()
return ast.SumTypeDecl{
return ast.UnionSumTypeDecl{
name: name
is_pub: is_pub
sub_types: sum_variants

View File

@ -722,17 +722,7 @@ pub fn (mut table Table) register_fn_gen_type(fn_name string, typ Type) {
// so until fixed at least show v (not C) error `x(variant) = y(SumType*)`
pub fn (table &Table) sumtype_has_variant(parent Type, variant Type) bool {
parent_sym := table.get_type_symbol(parent)
if parent_sym.kind == .sum_type {
parent_info := parent_sym.info as SumType
for v in parent_info.variants {
if v.idx() == variant.idx() {
return true
}
if table.sumtype_has_variant(v, variant) {
return true
}
}
} else if parent_sym.kind == .union_sum_type {
if parent_sym.kind == .union_sum_type {
parent_info := parent_sym.info as UnionSumType
for v in parent_info.variants {
if v.idx() == variant.idx() {

View File

@ -16,7 +16,7 @@ import strings
pub type Type = int
pub __type TypeInfo = Aggregate | Alias | Array | ArrayFixed | Chan | Enum | FnType |
GenericStructInst | Interface | Map | MultiReturn | Struct | SumType | UnionSumType
GenericStructInst | Interface | Map | MultiReturn | Struct | UnionSumType
pub enum Language {
v
@ -404,7 +404,6 @@ pub enum Kind {
struct_
generic_struct_inst
multi_return
sum_type
union_sum_type
alias
enum_
@ -719,7 +718,6 @@ pub fn (k Kind) str() string {
.map { 'map' }
.chan { 'chan' }
.multi_return { 'multi_return' }
.sum_type { 'sum_type' }
.union_sum_type { 'union_sum_type' }
.alias { 'alias' }
.enum_ { 'enum' }
@ -843,11 +841,6 @@ pub mut:
value_type Type
}
pub struct SumType {
pub:
variants []Type
}
pub struct UnionSumType {
pub:
variants []Type

View File

@ -18,12 +18,12 @@ fn test_if_smartcast() {
fn test_mutable() {
mut x := Alphabet(Abc{'original'})
if x is Abc {
if mut x is Abc {
assert x.val == 'original'
x.val = 'changed'
assert x.val == 'changed'
}
if x is Abc {
if mut x is Abc {
assert x.val == 'changed'
}
}
@ -38,11 +38,9 @@ fn test_nested_if_smartcast() {
}
}
fn test_as_cast() {
x := Alphabet(Abc{'test'})
if x is Abc as test {
assert test.val == 'test'
}
struct MutContainer {
mut:
abc Alphabet
}
struct Container {
@ -50,29 +48,24 @@ struct Container {
}
fn test_mutable_with_struct() {
mut c := Container{Abc{'original'}}
if c.abc is Abc as abc {
assert abc.val == 'original'
mut mabc := abc
// NB: since `abc` is a pointer,
// `mabc` points to the same data:
assert mabc.val == 'original'
// Modifying `mabc`, modifies the data of abc too.
mabc.val = 'xyz'
assert abc.val == 'xyz'
mut c := MutContainer{Abc{'original'}}
if mut c.abc is Abc {
assert c.abc.val == 'original'
c.abc.val = 'xyz'
assert c.abc.val == 'xyz'
}
if c.abc is Abc as another {
if mut c.abc is Abc {
// NB: in this second smart cast, `another` is
// the same wrapped value, that was changed in
// the first smart cast:
assert another.val == 'xyz'
assert c.abc.val == 'xyz'
}
}
fn test_as_cast_with_struct() {
x := Container{Abc{'test'}}
if x.abc is Abc as test {
assert test.val == 'test'
if x.abc is Abc {
assert x.abc.val == 'test'
}
}
@ -113,19 +106,19 @@ fn test_mutability() {
}
mut cell := Cell{}
cell = cell_str
if cell is CellStr {
if mut cell is CellStr {
println('$cell.str')
}
cell = cell_itg
if cell is CellInt {
if mut cell is CellInt {
println('$cell.itg')
}
cell = cell_flt
if cell is CellFloat {
if mut cell is CellFloat {
println('$cell.flt')
}
cell = cell_u32
if cell is CellU32 {
if mut cell is CellU32 {
println('$cell.u')
}
}

View File

@ -11,7 +11,7 @@ const (
fn test_shadow() {
mut animal := Animal{}
animal = cat
match animal {
match mut animal {
Cat {
assert animal.name == cat.name
}
@ -24,9 +24,9 @@ fn test_shadow() {
fn test_as() {
mut animal := Animal{}
animal = dog
match animal as animal_kind {
match mut animal {
Dog {
assert animal_kind.name == dog.name
assert animal.name == dog.name
}
else{
assert false

View File

@ -205,7 +205,8 @@ type NATOAlphabet = Alfa | Bravo | Charlie
fn test_match_sumtype_multiple_types() {
a := Alfa{}
match NATOAlphabet(a) as l {
l := NATOAlphabet(a)
match l {
Alfa, Bravo {
assert l.char == `a`
// TODO make methods work
@ -216,7 +217,7 @@ fn test_match_sumtype_multiple_types() {
}
}
// test one branch
match NATOAlphabet(a) as l {
match l {
Alfa, Bravo, Charlie {
assert l.char == `a`
}

View File

@ -28,8 +28,7 @@ fn handle(e Expr) string {
}
match e {
IntegerLiteral {
assert it.val == '12'
// assert e.val == '12' // TODO
assert e.val == '12'
return 'int'
}
IfExpr {
@ -56,10 +55,10 @@ fn test_assignment_and_push() {
arr1 << expr
match arr1[0] {
IntegerLiteral {
arr1 << it
arr1 << arr1[0]
// should ref/dereference on assignent be made automatic?
// currently it is done for return stmt and fn args
expr1 = *it
expr1 = arr1[0]
}
else {}
}
@ -96,7 +95,7 @@ fn test_converting_down() {
mut res := []Sub2{cap: out.len}
for d in out {
match d {
Sub2 { res << it }
Sub2 { res << d }
else {}
}
}
@ -107,26 +106,6 @@ fn test_converting_down() {
}
fn test_nested_sumtype() {
mut a := Node{}
mut b := Node{}
a = StructDecl{pos: 1}
b = IfExpr{pos: 1}
match a {
StructDecl {
assert true
}
else {
assert false
}
}
// TODO: not working
// assert b is IfExpr
if b is IfExpr {
assert true
}
else {
assert false
}
c := Node(Expr(IfExpr{pos:1}))
if c is Expr {
if c is IfExpr {
@ -202,8 +181,8 @@ fn is_gt_nested(val string, dst Number) bool {
return val.int() > dst
}
// this branch should never been hit
else {
return val.int() < dst
else {
return val.int() < dst
}
}
}
@ -213,8 +192,8 @@ fn is_gt_nested(val string, dst Number) bool {
return dst < val.f64()
}
// this branch should never been hit
else {
return dst > val.f64()
else {
return dst > val.f64()
}
}
}
@ -255,7 +234,7 @@ 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_simple('3', 3.5)
assert is_gt_nested('3', 2)
assert !is_gt_nested('3', 5)
assert is_gt_nested('3', 1.2)

View File

@ -51,8 +51,8 @@ type MySumType = int | f32 | FooBar
pub fn (ms MySumType) str() string {
match ms {
int { return it.str() }
f32 { return it.str() }
int { return ms.str() }
f32 { return ms.str() }
//FooBar { return it.x.str() }
else { return 'unknown: ' + typeof(ms) }
}
@ -144,7 +144,7 @@ fn test_generic_type() {
assert type_name([v]) == '[]int'
assert type_name([[v]]) == '[][]int'
assert type_name(FooBar{}) == 'FooBar'
assert array_item_type([v]) == 'int'
assert array_item_type([[v]]) == '[]int'
//assert array_item_type([&v]) == '&int'