mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix generic type $else $if (#8339)
This commit is contained in:
parent
9d1d35ebdc
commit
006a11454f
@ -312,6 +312,9 @@ pub fn (x Expr) str() string {
|
||||
StringLiteral {
|
||||
return '"$x.val"'
|
||||
}
|
||||
Type {
|
||||
return 'Type($x.typ)'
|
||||
}
|
||||
TypeOf {
|
||||
return 'typeof($x.expr.str())'
|
||||
}
|
||||
|
@ -4361,7 +4361,7 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||
mut nbranches_without_return := 0
|
||||
mut should_skip := false // Whether the current branch should be skipped
|
||||
mut found_branch := false // Whether a matching branch was found- skip the rest
|
||||
mut is_comptime_t_is_expr := false // if `$if T is string`
|
||||
mut is_comptime_type_is_expr := false // if `$if T is string`
|
||||
for i in 0 .. node.branches.len {
|
||||
mut branch := node.branches[i]
|
||||
if branch.cond is ast.ParExpr {
|
||||
@ -4443,8 +4443,9 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||
got_type := (branch.cond.right as ast.Type).typ
|
||||
if left is ast.SelectorExpr {
|
||||
c.comptime_fields_type[left.expr.str()] = got_type
|
||||
is_comptime_type_is_expr = true
|
||||
} else if left is ast.Type {
|
||||
is_comptime_t_is_expr = true
|
||||
is_comptime_type_is_expr = true
|
||||
left_type := c.unwrap_generic(left.typ)
|
||||
if left_type != got_type {
|
||||
should_skip = true
|
||||
@ -4458,12 +4459,12 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||
} else if should_skip {
|
||||
c.skip_flags = true
|
||||
should_skip = false // Reset the value of `should_skip` for the next branch
|
||||
} else {
|
||||
} else if !is_comptime_type_is_expr {
|
||||
found_branch = true // If a branch wasn't skipped, the rest must be
|
||||
}
|
||||
if !c.skip_flags || c.pref.output_cross_c {
|
||||
c.stmts(branch.stmts)
|
||||
} else if !is_comptime_t_is_expr {
|
||||
} else if !is_comptime_type_is_expr {
|
||||
node.branches[i].stmts = []
|
||||
}
|
||||
c.skip_flags = cur_skip_flags
|
||||
|
@ -155,13 +155,14 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
|
||||
start_pos := g.out.len
|
||||
if i == node.branches.len - 1 && node.has_else {
|
||||
g.writeln('#else')
|
||||
comp_if_stmts_skip = false
|
||||
} else {
|
||||
if i == 0 {
|
||||
g.write('#if ')
|
||||
} else {
|
||||
g.write('#elif ')
|
||||
}
|
||||
g.comp_if_expr(branch.cond)
|
||||
comp_if_stmts_skip = !g.comp_if_cond(branch.cond)
|
||||
g.writeln('')
|
||||
}
|
||||
expr_str := g.out.last_n(g.out.len - start_pos).trim_space()
|
||||
@ -193,30 +194,12 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
|
||||
if should_create_scope {
|
||||
g.writeln('{')
|
||||
}
|
||||
if branch.cond is ast.InfixExpr {
|
||||
if branch.cond.op == .key_is {
|
||||
left := branch.cond.left
|
||||
got_type := (branch.cond.right as ast.Type).typ
|
||||
if left is ast.Type {
|
||||
left_type := g.unwrap_generic(left.typ)
|
||||
if left_type != got_type {
|
||||
comp_if_stmts_skip = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
is_else := node.has_else && i == node.branches.len - 1
|
||||
if !comp_if_stmts_skip || (comp_if_stmts_skip && is_else) {
|
||||
if !comp_if_stmts_skip {
|
||||
g.stmts(branch.stmts)
|
||||
}
|
||||
if should_create_scope {
|
||||
g.writeln('}')
|
||||
}
|
||||
if !comp_if_stmts_skip && branch.cond is ast.InfixExpr {
|
||||
if (branch.cond as ast.InfixExpr).op == .key_is {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
g.defer_ifdef = ''
|
||||
}
|
||||
@ -227,33 +210,37 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
|
||||
}
|
||||
}
|
||||
|
||||
fn (mut g Gen) comp_if_expr(cond ast.Expr) {
|
||||
fn (mut g Gen) comp_if_cond(cond ast.Expr) bool {
|
||||
match cond {
|
||||
ast.BoolLiteral {
|
||||
g.expr(cond)
|
||||
return true
|
||||
}
|
||||
ast.ParExpr {
|
||||
g.write('(')
|
||||
g.comp_if_expr(cond.expr)
|
||||
is_cond_true := g.comp_if_cond(cond.expr)
|
||||
g.write(')')
|
||||
return is_cond_true
|
||||
}
|
||||
ast.PrefixExpr {
|
||||
g.write(cond.op.str())
|
||||
g.comp_if_expr(cond.right)
|
||||
return g.comp_if_cond(cond.right)
|
||||
}
|
||||
ast.PostfixExpr {
|
||||
ifdef := g.comp_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
|
||||
verror(err)
|
||||
return
|
||||
return false
|
||||
}
|
||||
g.write('defined($ifdef)')
|
||||
return true
|
||||
}
|
||||
ast.InfixExpr {
|
||||
match cond.op {
|
||||
.and, .logical_or {
|
||||
g.comp_if_expr(cond.left)
|
||||
l := g.comp_if_cond(cond.left)
|
||||
g.write(' $cond.op ')
|
||||
g.comp_if_expr(cond.right)
|
||||
r := g.comp_if_cond(cond.right)
|
||||
return l && r
|
||||
}
|
||||
.key_is, .not_is {
|
||||
left := cond.left
|
||||
@ -268,23 +255,34 @@ fn (mut g Gen) comp_if_expr(cond ast.Expr) {
|
||||
// this is only allowed for generics currently, otherwise blocked by checker
|
||||
exp_type = g.unwrap_generic(left.typ)
|
||||
}
|
||||
op := if cond.op == .key_is { '==' } else { '!=' }
|
||||
g.write('$exp_type $op $got_type')
|
||||
|
||||
if cond.op == .key_is {
|
||||
g.write('$exp_type == $got_type')
|
||||
return exp_type == got_type
|
||||
} else {
|
||||
g.write('$exp_type !=$got_type')
|
||||
return exp_type != got_type
|
||||
}
|
||||
}
|
||||
.eq, .ne {
|
||||
// TODO Implement `$if method.args.len == 1`
|
||||
g.write('1')
|
||||
return true
|
||||
}
|
||||
else {
|
||||
return true
|
||||
}
|
||||
else {}
|
||||
}
|
||||
}
|
||||
ast.Ident {
|
||||
ifdef := g.comp_if_to_ifdef(cond.name, false) or { 'true' } // handled in checker
|
||||
g.write('defined($ifdef)')
|
||||
return true
|
||||
}
|
||||
else {
|
||||
// should be unreachable, but just in case
|
||||
g.write('1')
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +81,14 @@ fn test_generic_t_is3() {
|
||||
assert res == GenericTIsTest{}
|
||||
}
|
||||
|
||||
fn generic_t_is_with_else<T>(raw_data string) ?T {
|
||||
$if T is string {
|
||||
return raw_data
|
||||
} $else {
|
||||
return T{}
|
||||
}
|
||||
}
|
||||
|
||||
fn test_generic_t_is_with_else() {
|
||||
res := generic_t_is_with_else<GenericTIsTest>('') or {
|
||||
assert false
|
||||
@ -94,10 +102,25 @@ fn test_generic_t_is_with_else() {
|
||||
assert str == 'test'
|
||||
}
|
||||
|
||||
fn generic_t_is_with_else<T>(raw_data string) ?T {
|
||||
$if T is string {
|
||||
return raw_data
|
||||
} $else {
|
||||
return T{}
|
||||
fn generic_t_is_with_else_if<T>() []string {
|
||||
mut fields := []string{}
|
||||
$for field in T.fields {
|
||||
$if field.typ is string {
|
||||
fields << field.name
|
||||
} $else $if field.typ is int {
|
||||
fields << field.name
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
|
||||
struct User {
|
||||
name string
|
||||
age int
|
||||
}
|
||||
|
||||
fn test_generic_t_is_with_else_if() {
|
||||
x := generic_t_is_with_else_if<User>()
|
||||
assert x == ['name', 'age']
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user