mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
all: inline sum types (#12912)
This commit is contained in:
parent
485b392cb3
commit
35282396ec
@ -1083,7 +1083,7 @@ pub:
|
||||
comments []Comment
|
||||
}
|
||||
|
||||
// New implementation of sum types
|
||||
// SumTypeDecl is the ast node for `type MySumType = string | int`
|
||||
pub struct SumTypeDecl {
|
||||
pub:
|
||||
name string
|
||||
|
@ -918,6 +918,7 @@ pub:
|
||||
pub mut:
|
||||
fields []StructField
|
||||
found_fields bool
|
||||
is_anon bool
|
||||
// generic sumtype support
|
||||
is_generic bool
|
||||
generic_types []Type
|
||||
@ -1048,6 +1049,10 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string]
|
||||
}
|
||||
else {}
|
||||
}
|
||||
} else if sym.info is SumType && (sym.info as SumType).is_anon {
|
||||
variant_names := sym.info.variants.map(t.shorten_user_defined_typenames(t.sym(it).name,
|
||||
import_aliases))
|
||||
res = '${variant_names.join(' | ')}'
|
||||
} else {
|
||||
res = t.shorten_user_defined_typenames(res, import_aliases)
|
||||
}
|
||||
@ -1089,7 +1094,7 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string]
|
||||
res = strings.repeat(`&`, nr_muls) + res
|
||||
}
|
||||
if typ.has_flag(.optional) {
|
||||
res = '?' + res
|
||||
res = '?$res'
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
13
vlib/v/fmt/tests/inline_sum_type_keep.vv
Normal file
13
vlib/v/fmt/tests/inline_sum_type_keep.vv
Normal file
@ -0,0 +1,13 @@
|
||||
import v.token
|
||||
|
||||
struct Foo {
|
||||
bar string | int
|
||||
}
|
||||
|
||||
interface Egg {
|
||||
milk string | int
|
||||
}
|
||||
|
||||
fn foo(bar string | int) int | string | token.Position {
|
||||
return 1
|
||||
}
|
@ -434,7 +434,12 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_
|
||||
g.type_definitions.writeln('static string indent_${str_fn_name}($styp x, int indent_count); // auto')
|
||||
mut fn_builder := strings.new_builder(512)
|
||||
fn_builder.writeln('static string indent_${str_fn_name}($styp x, int indent_count) {')
|
||||
mut clean_sum_type_v_type_name := styp.replace('__', '.')
|
||||
mut clean_sum_type_v_type_name := ''
|
||||
if info.is_anon {
|
||||
variant_names := info.variants.map(g.table.sym(it).name)
|
||||
clean_sum_type_v_type_name = '(${variant_names.join(' | ')})'
|
||||
} else {
|
||||
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('*', '')
|
||||
}
|
||||
@ -444,6 +449,7 @@ fn (mut g Gen) gen_str_for_union_sum_type(info ast.SumType, styp string, str_fn_
|
||||
'>'
|
||||
}
|
||||
clean_sum_type_v_type_name = util.strip_main_name(clean_sum_type_v_type_name)
|
||||
}
|
||||
fn_builder.writeln('\tswitch(x._typ) {')
|
||||
for typ in info.variants {
|
||||
typ_str := g.typ(typ)
|
||||
|
@ -539,6 +539,10 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
|
||||
}
|
||||
|
||||
fn (mut p Parser) fn_receiver(mut params []ast.Param, mut rec ReceiverParsingInfo) ? {
|
||||
p.inside_receiver_param = true
|
||||
defer {
|
||||
p.inside_receiver_param = false
|
||||
}
|
||||
lpar_pos := p.tok.position()
|
||||
p.next() // (
|
||||
is_shared := p.tok.kind == .key_shared
|
||||
|
@ -8,6 +8,10 @@ import v.ast
|
||||
import v.util
|
||||
import v.token
|
||||
|
||||
const (
|
||||
maximum_inline_sum_type_variants = 3
|
||||
)
|
||||
|
||||
pub fn (mut p Parser) parse_array_type(expecting token.Kind) ast.Type {
|
||||
p.check(expecting)
|
||||
// fixed array
|
||||
@ -283,9 +287,74 @@ pub fn (mut p Parser) parse_language() ast.Language {
|
||||
return language
|
||||
}
|
||||
|
||||
// parse_inline_sum_type parses the type and registers it in case the type is an anonymous sum type.
|
||||
// It also takes care of inline sum types where parse_type only parses a standalone type.
|
||||
pub fn (mut p Parser) parse_inline_sum_type() ast.Type {
|
||||
variants := p.parse_sum_type_variants()
|
||||
if variants.len > 1 {
|
||||
if variants.len > parser.maximum_inline_sum_type_variants {
|
||||
pos := variants[0].pos.extend(variants[variants.len - 1].pos)
|
||||
p.warn_with_pos('an inline sum type expects a maximum of $parser.maximum_inline_sum_type_variants types ($variants.len were given)',
|
||||
pos)
|
||||
}
|
||||
mut variant_names := variants.map(p.table.sym(it.typ).name)
|
||||
variant_names.sort()
|
||||
// deterministic name
|
||||
name := '_v_anon_sum_type_${variant_names.join('_')}'
|
||||
variant_types := variants.map(it.typ)
|
||||
prepend_mod_name := p.prepend_mod(name)
|
||||
mut idx := p.table.find_type_idx(prepend_mod_name)
|
||||
if idx > 0 {
|
||||
return ast.new_type(idx)
|
||||
}
|
||||
idx = p.table.register_type_symbol(ast.TypeSymbol{
|
||||
kind: .sum_type
|
||||
name: prepend_mod_name
|
||||
cname: util.no_dots(prepend_mod_name)
|
||||
mod: p.mod
|
||||
info: ast.SumType{
|
||||
is_anon: true
|
||||
variants: variant_types
|
||||
}
|
||||
})
|
||||
return ast.new_type(idx)
|
||||
} else if variants.len == 1 {
|
||||
return variants[0].typ
|
||||
}
|
||||
return ast.Type(0)
|
||||
}
|
||||
|
||||
// parse_sum_type_variants parses several types separated with a pipe and returns them as a list with at least one node.
|
||||
// If there is less than one node, it will add an error to the error list.
|
||||
pub fn (mut p Parser) parse_sum_type_variants() []ast.TypeNode {
|
||||
p.inside_sum_type = true
|
||||
defer {
|
||||
p.inside_sum_type = false
|
||||
}
|
||||
mut types := []ast.TypeNode{}
|
||||
for {
|
||||
type_start_pos := p.tok.position()
|
||||
typ := p.parse_type()
|
||||
// TODO: needs to be its own var, otherwise TCC fails because of a known stack error
|
||||
prev_tok := p.prev_tok
|
||||
type_end_pos := prev_tok.position()
|
||||
type_pos := type_start_pos.extend(type_end_pos)
|
||||
types << ast.TypeNode{
|
||||
typ: typ
|
||||
pos: type_pos
|
||||
}
|
||||
if p.tok.kind != .pipe {
|
||||
break
|
||||
}
|
||||
p.check(.pipe)
|
||||
}
|
||||
return types
|
||||
}
|
||||
|
||||
pub fn (mut p Parser) parse_type() ast.Type {
|
||||
// optional
|
||||
mut is_optional := false
|
||||
optional_pos := p.tok.position()
|
||||
if p.tok.kind == .question {
|
||||
line_nr := p.tok.line_nr
|
||||
p.next()
|
||||
@ -333,6 +402,10 @@ pub fn (mut p Parser) parse_type() ast.Type {
|
||||
p.error_with_pos('use `?` instead of `?void`', pos)
|
||||
return 0
|
||||
}
|
||||
sym := p.table.sym(typ)
|
||||
if is_optional && sym.info is ast.SumType && (sym.info as ast.SumType).is_anon {
|
||||
p.error_with_pos('an inline sum type cannot be optional', optional_pos.extend(p.prev_tok.position()))
|
||||
}
|
||||
}
|
||||
if is_optional {
|
||||
typ = typ.set_flag(.optional)
|
||||
@ -363,7 +436,6 @@ pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_d
|
||||
name = 'JS.$name'
|
||||
} else if p.peek_tok.kind == .dot && check_dot {
|
||||
// `module.Type`
|
||||
// /if !(p.tok.lit in p.table.imports) {
|
||||
mut mod := name
|
||||
mut mod_pos := p.tok.position()
|
||||
p.next()
|
||||
@ -394,7 +466,7 @@ pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_d
|
||||
p.error('imported types must start with a capital letter')
|
||||
return 0
|
||||
}
|
||||
} else if p.expr_mod != '' && !p.in_generic_params { // p.expr_mod is from the struct and not from the generic parameter
|
||||
} else if p.expr_mod != '' && !p.inside_generic_params { // p.expr_mod is from the struct and not from the generic parameter
|
||||
name = p.expr_mod + '.' + name
|
||||
} else if name in p.imported_symbols {
|
||||
name = p.imported_symbols[name]
|
||||
@ -402,7 +474,6 @@ pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_d
|
||||
// `Foo` in module `mod` means `mod.Foo`
|
||||
name = p.mod + '.' + name
|
||||
}
|
||||
// p.warn('get type $name')
|
||||
match p.tok.kind {
|
||||
.key_fn {
|
||||
// func
|
||||
@ -412,7 +483,8 @@ pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_d
|
||||
// array
|
||||
return p.parse_array_type(p.tok.kind)
|
||||
}
|
||||
.lpar {
|
||||
else {
|
||||
if p.tok.kind == .lpar && !p.inside_sum_type {
|
||||
// multiple return
|
||||
if is_ptr {
|
||||
p.error('parse_type: unexpected `&` before multiple returns')
|
||||
@ -420,8 +492,10 @@ pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_d
|
||||
}
|
||||
return p.parse_multi_return_type()
|
||||
}
|
||||
else {
|
||||
// no p.next()
|
||||
if ((p.peek_tok.kind == .dot && p.peek_token(3).kind == .pipe)
|
||||
|| p.peek_tok.kind == .pipe) && !p.inside_sum_type && !p.inside_receiver_param {
|
||||
return p.parse_inline_sum_type()
|
||||
}
|
||||
if name == 'map' {
|
||||
return p.parse_map_type()
|
||||
}
|
||||
@ -541,7 +615,7 @@ pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type {
|
||||
mut bs_cname := name
|
||||
start_pos := p.tok.position()
|
||||
p.next()
|
||||
p.in_generic_params = true
|
||||
p.inside_generic_params = true
|
||||
bs_name += '<'
|
||||
bs_cname += '_T_'
|
||||
mut concrete_types := []ast.Type{}
|
||||
@ -564,7 +638,7 @@ pub fn (mut p Parser) parse_generic_inst_type(name string) ast.Type {
|
||||
}
|
||||
concrete_types_pos := start_pos.extend(p.tok.position())
|
||||
p.check(.gt)
|
||||
p.in_generic_params = false
|
||||
p.inside_generic_params = false
|
||||
bs_name += '>'
|
||||
// fmt operates on a per-file basis, so is_instance might be not set correctly. Thus it's ignored.
|
||||
if (is_instance || p.pref.is_fmt) && concrete_types.len > 0 {
|
||||
|
@ -44,6 +44,17 @@ mut:
|
||||
inside_str_interp bool
|
||||
inside_array_lit bool
|
||||
inside_in_array bool
|
||||
inside_match bool // to separate `match A { }` from `Struct{}`
|
||||
inside_select bool // to allow `ch <- Struct{} {` inside `select`
|
||||
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
|
||||
inside_match_body bool // to fix eval not used TODO
|
||||
inside_unsafe bool
|
||||
inside_sum_type bool // to prevent parsing inline sum type again
|
||||
inside_asm_template bool
|
||||
inside_asm bool
|
||||
inside_defer bool
|
||||
inside_generic_params bool // indicates if parsing between `<` and `>` of a method/function
|
||||
inside_receiver_param bool // indicates if parsing the receiver parameter inside the first `(` and `)` of a method
|
||||
or_is_handled bool // ignore `or` in this expression
|
||||
builtin_mod bool // are we in the `builtin` module?
|
||||
mod string // current module name
|
||||
@ -60,11 +71,6 @@ mut:
|
||||
imported_symbols map[string]string
|
||||
is_amp bool // for generating the right code for `&Foo{}`
|
||||
returns bool
|
||||
inside_match bool // to separate `match A { }` from `Struct{}`
|
||||
inside_select bool // to allow `ch <- Struct{} {` inside `select`
|
||||
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
|
||||
inside_match_body bool // to fix eval not used TODO
|
||||
inside_unsafe bool
|
||||
is_stmt_ident bool // true while the beginning of a statement is an ident/selector
|
||||
expecting_type bool // `is Type`, expecting type
|
||||
errors []errors.Error
|
||||
@ -73,13 +79,9 @@ mut:
|
||||
vet_errors []vet.Error
|
||||
cur_fn_name string
|
||||
label_names []string
|
||||
in_generic_params bool // indicates if parsing between `<` and `>` of a method/function
|
||||
name_error bool // indicates if the token is not a name or the name is on another line
|
||||
n_asm int // controls assembly labels
|
||||
inside_asm_template bool
|
||||
inside_asm bool
|
||||
global_labels []string
|
||||
inside_defer bool
|
||||
comptime_if_cond bool
|
||||
defer_vars []ast.Ident
|
||||
should_abort bool // when too many errors/warnings/notices are accumulated, should_abort becomes true, and the parser should stop
|
||||
@ -3419,32 +3421,16 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
comments: comments
|
||||
}
|
||||
}
|
||||
first_type := p.parse_type() // need to parse the first type before we can check if it's `type A = X | Y`
|
||||
type_alias_pos := p.tok.position()
|
||||
if p.tok.kind == .pipe {
|
||||
mut type_end_pos := p.prev_tok.position()
|
||||
type_pos = type_pos.extend(type_end_pos)
|
||||
p.next()
|
||||
sum_variants << ast.TypeNode{
|
||||
typ: first_type
|
||||
pos: type_pos
|
||||
}
|
||||
sum_variants << p.parse_sum_type_variants()
|
||||
// type SumType = A | B | c
|
||||
for {
|
||||
type_pos = p.tok.position()
|
||||
variant_type := p.parse_type()
|
||||
// TODO: needs to be its own var, otherwise TCC fails because of a known stack error
|
||||
prev_tok := p.prev_tok
|
||||
type_end_pos = prev_tok.position()
|
||||
type_pos = type_pos.extend(type_end_pos)
|
||||
sum_variants << ast.TypeNode{
|
||||
typ: variant_type
|
||||
pos: type_pos
|
||||
if sum_variants.len > 1 {
|
||||
for variant in sum_variants {
|
||||
variant_sym := p.table.sym(variant.typ)
|
||||
// TODO: implement this check for error too
|
||||
if variant_sym.kind == .none_ {
|
||||
p.error_with_pos('named sum type cannot have none as its variant', variant.pos)
|
||||
return ast.AliasTypeDecl{}
|
||||
}
|
||||
if p.tok.kind != .pipe {
|
||||
break
|
||||
}
|
||||
p.check(.pipe)
|
||||
}
|
||||
variant_types := sum_variants.map(it.typ)
|
||||
prepend_mod_name := p.prepend_mod(name)
|
||||
@ -3481,7 +3467,8 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
p.error_with_pos('generic type aliases are not yet implemented', decl_pos_with_generics)
|
||||
return ast.AliasTypeDecl{}
|
||||
}
|
||||
parent_type := first_type
|
||||
// sum_variants will have only one element
|
||||
parent_type := sum_variants[0].typ
|
||||
parent_sym := p.table.sym(parent_type)
|
||||
pidx := parent_type.idx()
|
||||
p.check_for_impure_v(parent_sym.language, decl_pos)
|
||||
@ -3505,6 +3492,7 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||
return ast.AliasTypeDecl{}
|
||||
}
|
||||
if idx == pidx {
|
||||
type_alias_pos := sum_variants[0].pos
|
||||
p.error_with_pos('a type alias can not refer to itself: $name', decl_pos.extend(type_alias_pos))
|
||||
return ast.AliasTypeDecl{}
|
||||
}
|
||||
|
0
vlib/v/parser/tests/anon_sum_type_interface.out
Normal file
0
vlib/v/parser/tests/anon_sum_type_interface.out
Normal file
3
vlib/v/parser/tests/anon_sum_type_interface.vv
Normal file
3
vlib/v/parser/tests/anon_sum_type_interface.vv
Normal file
@ -0,0 +1,3 @@
|
||||
interface Foo {
|
||||
bar string | int
|
||||
}
|
5
vlib/v/parser/tests/anon_sum_type_multi_return_err.out
Normal file
5
vlib/v/parser/tests/anon_sum_type_multi_return_err.out
Normal file
@ -0,0 +1,5 @@
|
||||
vlib/v/parser/tests/anon_sum_type_multi_return_err.vv:1:24: error: invalid expression: unexpected token `|`
|
||||
1 | fn abc() (string, int) | string {
|
||||
| ^
|
||||
2 | return ''
|
||||
3 | }
|
3
vlib/v/parser/tests/anon_sum_type_multi_return_err.vv
Normal file
3
vlib/v/parser/tests/anon_sum_type_multi_return_err.vv
Normal file
@ -0,0 +1,3 @@
|
||||
fn abc() (string, int) | string {
|
||||
return ''
|
||||
}
|
5
vlib/v/parser/tests/anon_sum_type_receiver_err.out
Normal file
5
vlib/v/parser/tests/anon_sum_type_receiver_err.out
Normal file
@ -0,0 +1,5 @@
|
||||
vlib/v/parser/tests/anon_sum_type_receiver_err.vv:1:11: error: unexpected token `|`, expecting `)`
|
||||
1 | fn (x int | string) baz() {
|
||||
| ^
|
||||
2 | println('baz')
|
||||
3 | }
|
3
vlib/v/parser/tests/anon_sum_type_receiver_err.vv
Normal file
3
vlib/v/parser/tests/anon_sum_type_receiver_err.vv
Normal file
@ -0,0 +1,3 @@
|
||||
fn (x int | string) baz() {
|
||||
println('baz')
|
||||
}
|
0
vlib/v/parser/tests/anon_sum_type_struct.out
Normal file
0
vlib/v/parser/tests/anon_sum_type_struct.out
Normal file
3
vlib/v/parser/tests/anon_sum_type_struct.vv
Normal file
3
vlib/v/parser/tests/anon_sum_type_struct.vv
Normal file
@ -0,0 +1,3 @@
|
||||
struct Foo {
|
||||
bar string | int
|
||||
}
|
5
vlib/v/parser/tests/inline_sum_type_optional_err.out
Normal file
5
vlib/v/parser/tests/inline_sum_type_optional_err.out
Normal file
@ -0,0 +1,5 @@
|
||||
vlib/v/parser/tests/inline_sum_type_optional_err.vv:1:10: error: an inline sum type cannot be optional
|
||||
1 | fn foo() ?string | int {
|
||||
| ~~~~~~~~~~~~~
|
||||
2 | return 0
|
||||
3 | }
|
3
vlib/v/parser/tests/inline_sum_type_optional_err.vv
Normal file
3
vlib/v/parser/tests/inline_sum_type_optional_err.vv
Normal file
@ -0,0 +1,3 @@
|
||||
fn foo() ?string | int {
|
||||
return 0
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
vlib/v/parser/tests/inline_sum_type_return_type_too_many_variants.vv:4:6: warning: an inline sum type expects a maximum of 3 types (5 were given)
|
||||
2 |
|
||||
3 | struct Foo {
|
||||
4 | bar int | string | token.Position | bool | u32
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
5 | }
|
||||
6 |
|
||||
vlib/v/parser/tests/inline_sum_type_return_type_too_many_variants.vv:7:12: warning: an inline sum type expects a maximum of 3 types (5 were given)
|
||||
5 | }
|
||||
6 |
|
||||
7 | fn foo(arg int | string | token.Position | bool | u32) int | string | token.Position | bool | u32 {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
8 | return 1
|
||||
9 | }
|
||||
vlib/v/parser/tests/inline_sum_type_return_type_too_many_variants.vv:7:56: warning: an inline sum type expects a maximum of 3 types (5 were given)
|
||||
5 | }
|
||||
6 |
|
||||
7 | fn foo(arg int | string | token.Position | bool | u32) int | string | token.Position | bool | u32 {
|
||||
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
8 | return 1
|
||||
9 | }
|
@ -0,0 +1,9 @@
|
||||
import v.token
|
||||
|
||||
struct Foo {
|
||||
bar int | string | token.Position | bool | u32
|
||||
}
|
||||
|
||||
fn foo(arg int | string | token.Position | bool | u32) int | string | token.Position | bool | u32 {
|
||||
return 1
|
||||
}
|
3
vlib/v/parser/tests/named_sum_type_none_err.out
Normal file
3
vlib/v/parser/tests/named_sum_type_none_err.out
Normal file
@ -0,0 +1,3 @@
|
||||
vlib/v/parser/tests/named_sum_type_none_err.vv:1:34: error: named sum type cannot have none as its variant
|
||||
1 | type Abc = string | int | bool | none
|
||||
| ~~~~
|
1
vlib/v/parser/tests/named_sum_type_none_err.vv
Normal file
1
vlib/v/parser/tests/named_sum_type_none_err.vv
Normal file
@ -0,0 +1 @@
|
||||
type Abc = string | int | bool | none
|
5
vlib/v/parser/tests/option_sum_type_return_err.out
Normal file
5
vlib/v/parser/tests/option_sum_type_return_err.out
Normal file
@ -0,0 +1,5 @@
|
||||
vlib/v/parser/tests/option_sum_type_return_err.vv:1:21: error: an inline sum type cannot be optional
|
||||
1 | fn option_sumtype() ?string | int {
|
||||
| ~~~~~~~~~~~~~
|
||||
2 | return 0
|
||||
3 | }
|
3
vlib/v/parser/tests/option_sum_type_return_err.vv
Normal file
3
vlib/v/parser/tests/option_sum_type_return_err.vv
Normal file
@ -0,0 +1,3 @@
|
||||
fn option_sumtype() ?string | int {
|
||||
return 0
|
||||
}
|
41
vlib/v/tests/anon_sum_type_test.v
Normal file
41
vlib/v/tests/anon_sum_type_test.v
Normal file
@ -0,0 +1,41 @@
|
||||
fn returns_sumtype() int | string {
|
||||
return 1
|
||||
}
|
||||
|
||||
fn returns_sumtype_reverse() int | string {
|
||||
return 1
|
||||
}
|
||||
|
||||
fn test_stringification() {
|
||||
x := returns_sumtype()
|
||||
y := returns_sumtype_reverse()
|
||||
assert '$x' == '$y'
|
||||
}
|
||||
|
||||
struct Milk {
|
||||
egg int | string
|
||||
}
|
||||
|
||||
fn test_struct_with_inline_sumtype() {
|
||||
m := Milk{
|
||||
egg: 1
|
||||
}
|
||||
assert m.egg is int
|
||||
}
|
||||
|
||||
interface IMilk {
|
||||
egg int | string
|
||||
}
|
||||
|
||||
fn receive_imilk(milk IMilk) {}
|
||||
|
||||
fn test_interface_with_inline_sumtype() {
|
||||
m := Milk{
|
||||
egg: 1
|
||||
}
|
||||
receive_imilk(m)
|
||||
}
|
||||
|
||||
fn returns_sumtype_in_multireturn() (int | string, string) {
|
||||
return 1, ''
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
type MapValue = int | none
|
||||
|
||||
fn test_sum_type_with_none_type() {
|
||||
assert true
|
||||
}
|
Loading…
Reference in New Issue
Block a user