all: inline sum types (#12912)
parent
485b392cb3
commit
35282396ec
|
@ -1083,7 +1083,7 @@ pub:
|
||||||
comments []Comment
|
comments []Comment
|
||||||
}
|
}
|
||||||
|
|
||||||
// New implementation of sum types
|
// SumTypeDecl is the ast node for `type MySumType = string | int`
|
||||||
pub struct SumTypeDecl {
|
pub struct SumTypeDecl {
|
||||||
pub:
|
pub:
|
||||||
name string
|
name string
|
||||||
|
|
|
@ -918,6 +918,7 @@ pub:
|
||||||
pub mut:
|
pub mut:
|
||||||
fields []StructField
|
fields []StructField
|
||||||
found_fields bool
|
found_fields bool
|
||||||
|
is_anon bool
|
||||||
// generic sumtype support
|
// generic sumtype support
|
||||||
is_generic bool
|
is_generic bool
|
||||||
generic_types []Type
|
generic_types []Type
|
||||||
|
@ -1048,6 +1049,10 @@ pub fn (t &Table) type_to_str_using_aliases(typ Type, import_aliases map[string]
|
||||||
}
|
}
|
||||||
else {}
|
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 {
|
} else {
|
||||||
res = t.shorten_user_defined_typenames(res, import_aliases)
|
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
|
res = strings.repeat(`&`, nr_muls) + res
|
||||||
}
|
}
|
||||||
if typ.has_flag(.optional) {
|
if typ.has_flag(.optional) {
|
||||||
res = '?' + res
|
res = '?$res'
|
||||||
}
|
}
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,16 +434,22 @@ 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')
|
g.type_definitions.writeln('static string indent_${str_fn_name}($styp x, int indent_count); // auto')
|
||||||
mut fn_builder := strings.new_builder(512)
|
mut fn_builder := strings.new_builder(512)
|
||||||
fn_builder.writeln('static string indent_${str_fn_name}($styp x, int indent_count) {')
|
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 styp.ends_with('*') {
|
if info.is_anon {
|
||||||
clean_sum_type_v_type_name = '&' + clean_sum_type_v_type_name.replace('*', '')
|
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('*', '')
|
||||||
|
}
|
||||||
|
if clean_sum_type_v_type_name.contains('_T_') {
|
||||||
|
clean_sum_type_v_type_name =
|
||||||
|
clean_sum_type_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') +
|
||||||
|
'>'
|
||||||
|
}
|
||||||
|
clean_sum_type_v_type_name = util.strip_main_name(clean_sum_type_v_type_name)
|
||||||
}
|
}
|
||||||
if clean_sum_type_v_type_name.contains('_T_') {
|
|
||||||
clean_sum_type_v_type_name =
|
|
||||||
clean_sum_type_v_type_name.replace('Array_', '[]').replace('_T_', '<').replace('_', ', ') +
|
|
||||||
'>'
|
|
||||||
}
|
|
||||||
clean_sum_type_v_type_name = util.strip_main_name(clean_sum_type_v_type_name)
|
|
||||||
fn_builder.writeln('\tswitch(x._typ) {')
|
fn_builder.writeln('\tswitch(x._typ) {')
|
||||||
for typ in info.variants {
|
for typ in info.variants {
|
||||||
typ_str := g.typ(typ)
|
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) ? {
|
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()
|
lpar_pos := p.tok.position()
|
||||||
p.next() // (
|
p.next() // (
|
||||||
is_shared := p.tok.kind == .key_shared
|
is_shared := p.tok.kind == .key_shared
|
||||||
|
|
|
@ -8,6 +8,10 @@ import v.ast
|
||||||
import v.util
|
import v.util
|
||||||
import v.token
|
import v.token
|
||||||
|
|
||||||
|
const (
|
||||||
|
maximum_inline_sum_type_variants = 3
|
||||||
|
)
|
||||||
|
|
||||||
pub fn (mut p Parser) parse_array_type(expecting token.Kind) ast.Type {
|
pub fn (mut p Parser) parse_array_type(expecting token.Kind) ast.Type {
|
||||||
p.check(expecting)
|
p.check(expecting)
|
||||||
// fixed array
|
// fixed array
|
||||||
|
@ -283,9 +287,74 @@ pub fn (mut p Parser) parse_language() ast.Language {
|
||||||
return 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 {
|
pub fn (mut p Parser) parse_type() ast.Type {
|
||||||
// optional
|
// optional
|
||||||
mut is_optional := false
|
mut is_optional := false
|
||||||
|
optional_pos := p.tok.position()
|
||||||
if p.tok.kind == .question {
|
if p.tok.kind == .question {
|
||||||
line_nr := p.tok.line_nr
|
line_nr := p.tok.line_nr
|
||||||
p.next()
|
p.next()
|
||||||
|
@ -333,6 +402,10 @@ pub fn (mut p Parser) parse_type() ast.Type {
|
||||||
p.error_with_pos('use `?` instead of `?void`', pos)
|
p.error_with_pos('use `?` instead of `?void`', pos)
|
||||||
return 0
|
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 {
|
if is_optional {
|
||||||
typ = typ.set_flag(.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'
|
name = 'JS.$name'
|
||||||
} else if p.peek_tok.kind == .dot && check_dot {
|
} else if p.peek_tok.kind == .dot && check_dot {
|
||||||
// `module.Type`
|
// `module.Type`
|
||||||
// /if !(p.tok.lit in p.table.imports) {
|
|
||||||
mut mod := name
|
mut mod := name
|
||||||
mut mod_pos := p.tok.position()
|
mut mod_pos := p.tok.position()
|
||||||
p.next()
|
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')
|
p.error('imported types must start with a capital letter')
|
||||||
return 0
|
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
|
name = p.expr_mod + '.' + name
|
||||||
} else if name in p.imported_symbols {
|
} else if name in p.imported_symbols {
|
||||||
name = p.imported_symbols[name]
|
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`
|
// `Foo` in module `mod` means `mod.Foo`
|
||||||
name = p.mod + '.' + name
|
name = p.mod + '.' + name
|
||||||
}
|
}
|
||||||
// p.warn('get type $name')
|
|
||||||
match p.tok.kind {
|
match p.tok.kind {
|
||||||
.key_fn {
|
.key_fn {
|
||||||
// func
|
// func
|
||||||
|
@ -412,16 +483,19 @@ pub fn (mut p Parser) parse_any_type(language ast.Language, is_ptr bool, check_d
|
||||||
// array
|
// array
|
||||||
return p.parse_array_type(p.tok.kind)
|
return p.parse_array_type(p.tok.kind)
|
||||||
}
|
}
|
||||||
.lpar {
|
|
||||||
// multiple return
|
|
||||||
if is_ptr {
|
|
||||||
p.error('parse_type: unexpected `&` before multiple returns')
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
return p.parse_multi_return_type()
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// no p.next()
|
if p.tok.kind == .lpar && !p.inside_sum_type {
|
||||||
|
// multiple return
|
||||||
|
if is_ptr {
|
||||||
|
p.error('parse_type: unexpected `&` before multiple returns')
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return p.parse_multi_return_type()
|
||||||
|
}
|
||||||
|
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' {
|
if name == 'map' {
|
||||||
return p.parse_map_type()
|
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
|
mut bs_cname := name
|
||||||
start_pos := p.tok.position()
|
start_pos := p.tok.position()
|
||||||
p.next()
|
p.next()
|
||||||
p.in_generic_params = true
|
p.inside_generic_params = true
|
||||||
bs_name += '<'
|
bs_name += '<'
|
||||||
bs_cname += '_T_'
|
bs_cname += '_T_'
|
||||||
mut concrete_types := []ast.Type{}
|
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())
|
concrete_types_pos := start_pos.extend(p.tok.position())
|
||||||
p.check(.gt)
|
p.check(.gt)
|
||||||
p.in_generic_params = false
|
p.inside_generic_params = false
|
||||||
bs_name += '>'
|
bs_name += '>'
|
||||||
// fmt operates on a per-file basis, so is_instance might be not set correctly. Thus it's ignored.
|
// 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 {
|
if (is_instance || p.pref.is_fmt) && concrete_types.len > 0 {
|
||||||
|
|
|
@ -26,64 +26,66 @@ mut:
|
||||||
scanner &scanner.Scanner
|
scanner &scanner.Scanner
|
||||||
comments_mode scanner.CommentsMode = .skip_comments
|
comments_mode scanner.CommentsMode = .skip_comments
|
||||||
// see comment in parse_file
|
// see comment in parse_file
|
||||||
tok token.Token
|
tok token.Token
|
||||||
prev_tok token.Token
|
prev_tok token.Token
|
||||||
peek_tok token.Token
|
peek_tok token.Token
|
||||||
table &ast.Table
|
table &ast.Table
|
||||||
language ast.Language
|
language ast.Language
|
||||||
fn_language ast.Language // .c for `fn C.abcd()` declarations
|
fn_language ast.Language // .c for `fn C.abcd()` declarations
|
||||||
inside_vlib_file bool // true for all vlib/ files
|
inside_vlib_file bool // true for all vlib/ files
|
||||||
inside_test_file bool // when inside _test.v or _test.vv file
|
inside_test_file bool // when inside _test.v or _test.vv file
|
||||||
inside_if bool
|
inside_if bool
|
||||||
inside_if_expr bool
|
inside_if_expr bool
|
||||||
inside_ct_if_expr bool
|
inside_ct_if_expr bool
|
||||||
inside_or_expr bool
|
inside_or_expr bool
|
||||||
inside_for bool
|
inside_for bool
|
||||||
inside_fn bool // true even with implicit main
|
inside_fn bool // true even with implicit main
|
||||||
inside_unsafe_fn bool
|
inside_unsafe_fn bool
|
||||||
inside_str_interp bool
|
inside_str_interp bool
|
||||||
inside_array_lit bool
|
inside_array_lit bool
|
||||||
inside_in_array bool
|
inside_in_array bool
|
||||||
or_is_handled bool // ignore `or` in this expression
|
inside_match bool // to separate `match A { }` from `Struct{}`
|
||||||
builtin_mod bool // are we in the `builtin` module?
|
inside_select bool // to allow `ch <- Struct{} {` inside `select`
|
||||||
mod string // current module name
|
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
|
||||||
is_manualfree bool // true when `[manualfree] module abc`, makes *all* fns in the current .v file, opt out of autofree
|
inside_match_body bool // to fix eval not used TODO
|
||||||
has_globals bool // `[has_globals] module abc` - allow globals declarations, even without -enable-globals, in that single .v file __only__
|
inside_unsafe bool
|
||||||
is_generated bool // `[generated] module abc` - turn off compiler notices for that single .v file __only__.
|
inside_sum_type bool // to prevent parsing inline sum type again
|
||||||
attrs []ast.Attr // attributes before next decl stmt
|
inside_asm_template bool
|
||||||
expr_mod string // for constructing full type names in parse_type()
|
inside_asm bool
|
||||||
scope &ast.Scope
|
inside_defer bool
|
||||||
imports map[string]string // alias => mod_name
|
inside_generic_params bool // indicates if parsing between `<` and `>` of a method/function
|
||||||
ast_imports []ast.Import // mod_names
|
inside_receiver_param bool // indicates if parsing the receiver parameter inside the first `(` and `)` of a method
|
||||||
used_imports []string // alias
|
or_is_handled bool // ignore `or` in this expression
|
||||||
auto_imports []string // imports, the user does not need to specify
|
builtin_mod bool // are we in the `builtin` module?
|
||||||
imported_symbols map[string]string
|
mod string // current module name
|
||||||
is_amp bool // for generating the right code for `&Foo{}`
|
is_manualfree bool // true when `[manualfree] module abc`, makes *all* fns in the current .v file, opt out of autofree
|
||||||
returns bool
|
has_globals bool // `[has_globals] module abc` - allow globals declarations, even without -enable-globals, in that single .v file __only__
|
||||||
inside_match bool // to separate `match A { }` from `Struct{}`
|
is_generated bool // `[generated] module abc` - turn off compiler notices for that single .v file __only__.
|
||||||
inside_select bool // to allow `ch <- Struct{} {` inside `select`
|
attrs []ast.Attr // attributes before next decl stmt
|
||||||
inside_match_case bool // to separate `match_expr { }` from `Struct{}`
|
expr_mod string // for constructing full type names in parse_type()
|
||||||
inside_match_body bool // to fix eval not used TODO
|
scope &ast.Scope
|
||||||
inside_unsafe bool
|
imports map[string]string // alias => mod_name
|
||||||
is_stmt_ident bool // true while the beginning of a statement is an ident/selector
|
ast_imports []ast.Import // mod_names
|
||||||
expecting_type bool // `is Type`, expecting type
|
used_imports []string // alias
|
||||||
errors []errors.Error
|
auto_imports []string // imports, the user does not need to specify
|
||||||
warnings []errors.Warning
|
imported_symbols map[string]string
|
||||||
notices []errors.Notice
|
is_amp bool // for generating the right code for `&Foo{}`
|
||||||
vet_errors []vet.Error
|
returns bool
|
||||||
cur_fn_name string
|
is_stmt_ident bool // true while the beginning of a statement is an ident/selector
|
||||||
label_names []string
|
expecting_type bool // `is Type`, expecting type
|
||||||
in_generic_params bool // indicates if parsing between `<` and `>` of a method/function
|
errors []errors.Error
|
||||||
name_error bool // indicates if the token is not a name or the name is on another line
|
warnings []errors.Warning
|
||||||
n_asm int // controls assembly labels
|
notices []errors.Notice
|
||||||
inside_asm_template bool
|
vet_errors []vet.Error
|
||||||
inside_asm bool
|
cur_fn_name string
|
||||||
global_labels []string
|
label_names []string
|
||||||
inside_defer bool
|
name_error bool // indicates if the token is not a name or the name is on another line
|
||||||
comptime_if_cond bool
|
n_asm int // controls assembly labels
|
||||||
defer_vars []ast.Ident
|
global_labels []string
|
||||||
should_abort bool // when too many errors/warnings/notices are accumulated, should_abort becomes true, and the parser should stop
|
comptime_if_cond bool
|
||||||
codegen_text string
|
defer_vars []ast.Ident
|
||||||
|
should_abort bool // when too many errors/warnings/notices are accumulated, should_abort becomes true, and the parser should stop
|
||||||
|
codegen_text string
|
||||||
}
|
}
|
||||||
|
|
||||||
// for tests
|
// for tests
|
||||||
|
@ -3419,32 +3421,16 @@ fn (mut p Parser) type_decl() ast.TypeDecl {
|
||||||
comments: comments
|
comments: comments
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
first_type := p.parse_type() // need to parse the first type before we can check if it's `type A = X | Y`
|
sum_variants << p.parse_sum_type_variants()
|
||||||
type_alias_pos := p.tok.position()
|
// type SumType = A | B | c
|
||||||
if p.tok.kind == .pipe {
|
if sum_variants.len > 1 {
|
||||||
mut type_end_pos := p.prev_tok.position()
|
for variant in sum_variants {
|
||||||
type_pos = type_pos.extend(type_end_pos)
|
variant_sym := p.table.sym(variant.typ)
|
||||||
p.next()
|
// TODO: implement this check for error too
|
||||||
sum_variants << ast.TypeNode{
|
if variant_sym.kind == .none_ {
|
||||||
typ: first_type
|
p.error_with_pos('named sum type cannot have none as its variant', variant.pos)
|
||||||
pos: type_pos
|
return ast.AliasTypeDecl{}
|
||||||
}
|
|
||||||
// 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 p.tok.kind != .pipe {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
p.check(.pipe)
|
|
||||||
}
|
}
|
||||||
variant_types := sum_variants.map(it.typ)
|
variant_types := sum_variants.map(it.typ)
|
||||||
prepend_mod_name := p.prepend_mod(name)
|
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)
|
p.error_with_pos('generic type aliases are not yet implemented', decl_pos_with_generics)
|
||||||
return ast.AliasTypeDecl{}
|
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)
|
parent_sym := p.table.sym(parent_type)
|
||||||
pidx := parent_type.idx()
|
pidx := parent_type.idx()
|
||||||
p.check_for_impure_v(parent_sym.language, decl_pos)
|
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{}
|
return ast.AliasTypeDecl{}
|
||||||
}
|
}
|
||||||
if idx == pidx {
|
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))
|
p.error_with_pos('a type alias can not refer to itself: $name', decl_pos.extend(type_alias_pos))
|
||||||
return ast.AliasTypeDecl{}
|
return ast.AliasTypeDecl{}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
interface Foo {
|
||||||
|
bar string | int
|
||||||
|
}
|
|
@ -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 | }
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn abc() (string, int) | string {
|
||||||
|
return ''
|
||||||
|
}
|
|
@ -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 | }
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn (x int | string) baz() {
|
||||||
|
println('baz')
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
struct Foo {
|
||||||
|
bar string | int
|
||||||
|
}
|
|
@ -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 | }
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
||||||
|
| ~~~~
|
|
@ -0,0 +1 @@
|
||||||
|
type Abc = string | int | bool | none
|
|
@ -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 | }
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn option_sumtype() ?string | int {
|
||||||
|
return 0
|
||||||
|
}
|
|
@ -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