cgen: fix generic type $else $if (#8339)
parent
9d1d35ebdc
commit
006a11454f
|
@ -312,6 +312,9 @@ pub fn (x Expr) str() string {
|
||||||
StringLiteral {
|
StringLiteral {
|
||||||
return '"$x.val"'
|
return '"$x.val"'
|
||||||
}
|
}
|
||||||
|
Type {
|
||||||
|
return 'Type($x.typ)'
|
||||||
|
}
|
||||||
TypeOf {
|
TypeOf {
|
||||||
return 'typeof($x.expr.str())'
|
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 nbranches_without_return := 0
|
||||||
mut should_skip := false // Whether the current branch should be skipped
|
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 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 {
|
for i in 0 .. node.branches.len {
|
||||||
mut branch := node.branches[i]
|
mut branch := node.branches[i]
|
||||||
if branch.cond is ast.ParExpr {
|
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
|
got_type := (branch.cond.right as ast.Type).typ
|
||||||
if left is ast.SelectorExpr {
|
if left is ast.SelectorExpr {
|
||||||
c.comptime_fields_type[left.expr.str()] = got_type
|
c.comptime_fields_type[left.expr.str()] = got_type
|
||||||
|
is_comptime_type_is_expr = true
|
||||||
} else if left is ast.Type {
|
} 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)
|
left_type := c.unwrap_generic(left.typ)
|
||||||
if left_type != got_type {
|
if left_type != got_type {
|
||||||
should_skip = true
|
should_skip = true
|
||||||
|
@ -4458,12 +4459,12 @@ pub fn (mut c Checker) if_expr(mut node ast.IfExpr) table.Type {
|
||||||
} else if should_skip {
|
} else if should_skip {
|
||||||
c.skip_flags = true
|
c.skip_flags = true
|
||||||
should_skip = false // Reset the value of `should_skip` for the next branch
|
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
|
found_branch = true // If a branch wasn't skipped, the rest must be
|
||||||
}
|
}
|
||||||
if !c.skip_flags || c.pref.output_cross_c {
|
if !c.skip_flags || c.pref.output_cross_c {
|
||||||
c.stmts(branch.stmts)
|
c.stmts(branch.stmts)
|
||||||
} else if !is_comptime_t_is_expr {
|
} else if !is_comptime_type_is_expr {
|
||||||
node.branches[i].stmts = []
|
node.branches[i].stmts = []
|
||||||
}
|
}
|
||||||
c.skip_flags = cur_skip_flags
|
c.skip_flags = cur_skip_flags
|
||||||
|
|
|
@ -155,13 +155,14 @@ fn (mut g Gen) comp_if(node ast.IfExpr) {
|
||||||
start_pos := g.out.len
|
start_pos := g.out.len
|
||||||
if i == node.branches.len - 1 && node.has_else {
|
if i == node.branches.len - 1 && node.has_else {
|
||||||
g.writeln('#else')
|
g.writeln('#else')
|
||||||
|
comp_if_stmts_skip = false
|
||||||
} else {
|
} else {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
g.write('#if ')
|
g.write('#if ')
|
||||||
} else {
|
} else {
|
||||||
g.write('#elif ')
|
g.write('#elif ')
|
||||||
}
|
}
|
||||||
g.comp_if_expr(branch.cond)
|
comp_if_stmts_skip = !g.comp_if_cond(branch.cond)
|
||||||
g.writeln('')
|
g.writeln('')
|
||||||
}
|
}
|
||||||
expr_str := g.out.last_n(g.out.len - start_pos).trim_space()
|
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 {
|
if should_create_scope {
|
||||||
g.writeln('{')
|
g.writeln('{')
|
||||||
}
|
}
|
||||||
if branch.cond is ast.InfixExpr {
|
if !comp_if_stmts_skip {
|
||||||
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) {
|
|
||||||
g.stmts(branch.stmts)
|
g.stmts(branch.stmts)
|
||||||
}
|
}
|
||||||
if should_create_scope {
|
if should_create_scope {
|
||||||
g.writeln('}')
|
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 = ''
|
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 {
|
match cond {
|
||||||
ast.BoolLiteral {
|
ast.BoolLiteral {
|
||||||
g.expr(cond)
|
g.expr(cond)
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
ast.ParExpr {
|
ast.ParExpr {
|
||||||
g.write('(')
|
g.write('(')
|
||||||
g.comp_if_expr(cond.expr)
|
is_cond_true := g.comp_if_cond(cond.expr)
|
||||||
g.write(')')
|
g.write(')')
|
||||||
|
return is_cond_true
|
||||||
}
|
}
|
||||||
ast.PrefixExpr {
|
ast.PrefixExpr {
|
||||||
g.write(cond.op.str())
|
g.write(cond.op.str())
|
||||||
g.comp_if_expr(cond.right)
|
return g.comp_if_cond(cond.right)
|
||||||
}
|
}
|
||||||
ast.PostfixExpr {
|
ast.PostfixExpr {
|
||||||
ifdef := g.comp_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
|
ifdef := g.comp_if_to_ifdef((cond.expr as ast.Ident).name, true) or {
|
||||||
verror(err)
|
verror(err)
|
||||||
return
|
return false
|
||||||
}
|
}
|
||||||
g.write('defined($ifdef)')
|
g.write('defined($ifdef)')
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
ast.InfixExpr {
|
ast.InfixExpr {
|
||||||
match cond.op {
|
match cond.op {
|
||||||
.and, .logical_or {
|
.and, .logical_or {
|
||||||
g.comp_if_expr(cond.left)
|
l := g.comp_if_cond(cond.left)
|
||||||
g.write(' $cond.op ')
|
g.write(' $cond.op ')
|
||||||
g.comp_if_expr(cond.right)
|
r := g.comp_if_cond(cond.right)
|
||||||
|
return l && r
|
||||||
}
|
}
|
||||||
.key_is, .not_is {
|
.key_is, .not_is {
|
||||||
left := cond.left
|
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
|
// this is only allowed for generics currently, otherwise blocked by checker
|
||||||
exp_type = g.unwrap_generic(left.typ)
|
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 {
|
.eq, .ne {
|
||||||
// TODO Implement `$if method.args.len == 1`
|
// TODO Implement `$if method.args.len == 1`
|
||||||
g.write('1')
|
g.write('1')
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
else {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ast.Ident {
|
ast.Ident {
|
||||||
ifdef := g.comp_if_to_ifdef(cond.name, false) or { 'true' } // handled in checker
|
ifdef := g.comp_if_to_ifdef(cond.name, false) or { 'true' } // handled in checker
|
||||||
g.write('defined($ifdef)')
|
g.write('defined($ifdef)')
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// should be unreachable, but just in case
|
// should be unreachable, but just in case
|
||||||
g.write('1')
|
g.write('1')
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,14 @@ fn test_generic_t_is3() {
|
||||||
assert res == GenericTIsTest{}
|
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() {
|
fn test_generic_t_is_with_else() {
|
||||||
res := generic_t_is_with_else<GenericTIsTest>('') or {
|
res := generic_t_is_with_else<GenericTIsTest>('') or {
|
||||||
assert false
|
assert false
|
||||||
|
@ -94,10 +102,25 @@ fn test_generic_t_is_with_else() {
|
||||||
assert str == 'test'
|
assert str == 'test'
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generic_t_is_with_else<T>(raw_data string) ?T {
|
fn generic_t_is_with_else_if<T>() []string {
|
||||||
$if T is string {
|
mut fields := []string{}
|
||||||
return raw_data
|
$for field in T.fields {
|
||||||
} $else {
|
$if field.typ is string {
|
||||||
return T{}
|
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