mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
compiler: allow a type to be used as a variant of multiple sum types
This commit is contained in:
parent
bc3d1eaf6e
commit
c4e83faa57
@ -850,6 +850,7 @@ fn (p mut Parser) type_decl() {
|
||||
mut idx := 0
|
||||
mut done := false
|
||||
mut ctype_names := []string
|
||||
mut sum_variants := []string
|
||||
for {
|
||||
// p.tok == .pipe {
|
||||
idx++
|
||||
@ -862,14 +863,17 @@ fn (p mut Parser) type_decl() {
|
||||
if p.pass == .main {
|
||||
// Update the type's parent
|
||||
// println('child=$child_type_name parent=$name')
|
||||
mut t := p.find_type(child_type_name)
|
||||
t := p.find_type(child_type_name)
|
||||
if t.name == '' {
|
||||
p.error('unknown type `$child_type_name`')
|
||||
}
|
||||
t.parent = name
|
||||
p.table.rewrite_type(t)
|
||||
p.cgen.consts << '#define SumType_$child_type_name $idx // DEF2'
|
||||
p.cgen.consts << '#define SumType_${name}_$child_type_name $idx // DEF2'
|
||||
ctype_names << child_type_name
|
||||
sum_variants << if p.mod in ['builtin', 'main'] || child_type_name in builtin_types {
|
||||
child_type_name
|
||||
} else {
|
||||
p.prepend_mod(child_type_name)
|
||||
}
|
||||
}
|
||||
if done {
|
||||
break
|
||||
@ -882,10 +886,7 @@ fn (p mut Parser) type_decl() {
|
||||
// p.fgen_nl()
|
||||
}
|
||||
}
|
||||
if p.pass == .decl {
|
||||
p.table.sum_types << name
|
||||
// println(p.table.sum_types)
|
||||
}
|
||||
p.table.sum_types[name] = sum_variants
|
||||
// Register the actual sum type
|
||||
// println('registering sum $name')
|
||||
p.table.register_type(Type{
|
||||
|
@ -66,11 +66,10 @@ fn (p mut Parser) bool_expression() string {
|
||||
// e.g. `return InfixExpr{}` in a function expecting `Expr`
|
||||
if expected != typ && expected in p.table.sum_types { // TODO perf
|
||||
//p.warn('SUM CAST exp=$expected typ=$typ p.exp=$p.expected_type')
|
||||
T := p.table.find_type(typ)
|
||||
if T.parent == expected {
|
||||
if typ in p.table.sum_types[expected] {
|
||||
p.cgen.set_placeholder(start_ph, '/*SUM TYPE CAST2*/ ($expected) { .obj = memdup( &($typ[]) { ')
|
||||
tt := typ.all_after('_') // TODO
|
||||
p.gen('}, sizeof($typ) ), .typ = SumType_${tt} }')//${val}_type }')
|
||||
p.gen('}, sizeof($typ) ), .typ = SumType_${expected}_${tt} }')//${val}_type }')
|
||||
}
|
||||
}
|
||||
// `as` cast
|
||||
@ -90,10 +89,8 @@ fn (p mut Parser) key_as(typ string, start_ph int) string {
|
||||
p.error('casting `$typ` to `$cast_typ` is not needed')
|
||||
}
|
||||
if typ in p.table.sum_types {
|
||||
T := p.table.find_type(cast_typ)
|
||||
if T.parent != typ {
|
||||
p.error('cannot cast `$typ` to `$cast_typ`. `$cast_typ` is not a variant of `$typ`' +
|
||||
'parent=$T.parent')
|
||||
if !(cast_typ in p.table.sum_types[typ]) {
|
||||
p.error('cannot cast `$typ` to `$cast_typ`. `$cast_typ` is not a variant of `$typ`')
|
||||
}
|
||||
p.cgen.set_placeholder(start_ph, '*($cast_typ*)')
|
||||
p.gen('.obj')
|
||||
@ -102,7 +99,7 @@ fn (p mut Parser) key_as(typ string, start_ph int) string {
|
||||
sum_type:= p.cgen.cur_line.all_after('*) (').replace('.obj', '.typ')
|
||||
|
||||
n := cast_typ.all_after('__')
|
||||
p.cgen.insert_before('if (($sum_type != SumType_$n) {
|
||||
p.cgen.insert_before('if (($sum_type != SumType_${typ}_$n) {
|
||||
puts("runtime error: $p.file_name:$p.scanner.line_nr cannot cast sum type `$typ` to `$n`");
|
||||
exit(1);
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ fn (p mut Parser) match_statement(is_expr bool) string {
|
||||
if is_sum_type {
|
||||
sum_child_type = p.get_type2().name
|
||||
tt := sum_child_type.all_after('_')
|
||||
p.gen('SumType_$tt')
|
||||
p.gen('SumType_${typ}_$tt')
|
||||
// println('got child $sum_child_type')
|
||||
p.register_var(Var{
|
||||
name: 'it'
|
||||
|
@ -22,7 +22,7 @@ pub mut:
|
||||
max_field_len map[string]int // for vfmt: max_field_len['Parser'] == 12
|
||||
generic_struct_params map[string][]string
|
||||
tuple_variants map[string][]string // enum( Bool(BoolExpr) )
|
||||
sum_types []string
|
||||
sum_types map[string][]string // SumType -> [Variants]
|
||||
}
|
||||
|
||||
struct VargAccess {
|
||||
@ -191,6 +191,8 @@ const (
|
||||
float_types = ['f32', 'f64']
|
||||
reserved_type_param_names = ['R', 'S', 'T', 'U', 'W']
|
||||
pointer_types = ['byte*', 'byteptr', 'char*', 'charptr', 'void*', 'voidptr', 'voidptr*', 'intptr']
|
||||
builtin_types = ['int', 'i8', 'char', 'byte', 'i16', 'u16', 'u32', 'i64', 'u64',
|
||||
'f64', 'f32', 'byteptr', 'charptr', 'voidptr', 'intptr', 'string', 'ustring']
|
||||
)
|
||||
|
||||
fn is_number_type(typ string) bool {
|
||||
@ -745,8 +747,7 @@ fn (p mut Parser) check_types2(got_, expected_ string, throw bool) bool {
|
||||
// Sum type
|
||||
if expected in p.table.sum_types {
|
||||
//println('checking sum')
|
||||
child := p.table.find_type(got)
|
||||
if child.parent == expected {
|
||||
if got in p.table.sum_types[expected] {
|
||||
//println('yep $expected')
|
||||
return true
|
||||
}
|
||||
|
@ -20,7 +20,9 @@ fn test_person_str() {
|
||||
|
||||
struct Foo {}
|
||||
|
||||
type Expr = Foo | BoolExpr | BinExpr | UnaryExpr
|
||||
type Expr = Foo | BoolExpr | BinExpr | UnaryExpr | DeclExprA | DeclExprB
|
||||
|
||||
type DeclExpr = DeclExprA | DeclExprB
|
||||
|
||||
struct BoolExpr {
|
||||
foo int
|
||||
@ -31,6 +33,14 @@ struct BinExpr {
|
||||
name string
|
||||
}
|
||||
|
||||
struct DeclExprA {
|
||||
name string
|
||||
}
|
||||
|
||||
struct DeclExprB {
|
||||
name string
|
||||
}
|
||||
|
||||
fn expr1() Expr {
|
||||
mut e := Expr{}
|
||||
e = BinExpr{'binexpr'}
|
||||
@ -46,11 +56,14 @@ struct UnaryExpr {
|
||||
|
||||
}
|
||||
|
||||
|
||||
fn handle_expr(e Expr) {
|
||||
|
||||
}
|
||||
|
||||
fn handle_decl_expr(de DeclExpr) {
|
||||
|
||||
}
|
||||
|
||||
fn parse_bool() BoolExpr {
|
||||
return BoolExpr{}
|
||||
}
|
||||
@ -64,6 +77,10 @@ fn test_sum_type_cast() {
|
||||
fn test_sum_types() {
|
||||
b := parse_bool()
|
||||
handle_expr(b)
|
||||
|
||||
de := DeclExprA{}
|
||||
handle_expr(de)
|
||||
handle_decl_expr(de)
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user