cgen: properly support `typeof()`, sizeof(), ... in compile time `for` (#10896)
parent
12884e9eb7
commit
713a079684
|
@ -38,6 +38,7 @@ fn string_array_to_map(a []string) map[string]bool {
|
||||||
struct Gen {
|
struct Gen {
|
||||||
pref &pref.Preferences
|
pref &pref.Preferences
|
||||||
module_built string
|
module_built string
|
||||||
|
field_data_type ast.Type // cache her to avoid map lookups
|
||||||
mut:
|
mut:
|
||||||
table &ast.Table
|
table &ast.Table
|
||||||
out strings.Builder
|
out strings.Builder
|
||||||
|
@ -225,6 +226,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string {
|
||||||
module_built: module_built
|
module_built: module_built
|
||||||
timers: util.new_timers(timers_should_print)
|
timers: util.new_timers(timers_should_print)
|
||||||
inner_loop: &ast.EmptyStmt{}
|
inner_loop: &ast.EmptyStmt{}
|
||||||
|
field_data_type: ast.Type(table.find_type_idx('FieldData'))
|
||||||
}
|
}
|
||||||
g.timers.start('cgen init')
|
g.timers.start('cgen init')
|
||||||
for mod in g.table.modules {
|
for mod in g.table.modules {
|
||||||
|
@ -3422,7 +3424,8 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
g.select_expr(node)
|
g.select_expr(node)
|
||||||
}
|
}
|
||||||
ast.SizeOf {
|
ast.SizeOf {
|
||||||
node_typ := g.unwrap_generic(node.typ)
|
typ := if node.typ == g.field_data_type { g.comp_for_field_value.typ } else { node.typ }
|
||||||
|
node_typ := g.unwrap_generic(typ)
|
||||||
sym := g.table.get_type_symbol(node_typ)
|
sym := g.table.get_type_symbol(node_typ)
|
||||||
if sym.language == .v && sym.kind in [.placeholder, .any] {
|
if sym.language == .v && sym.kind in [.placeholder, .any] {
|
||||||
g.error('unknown type `$sym.name`', node.pos)
|
g.error('unknown type `$sym.name`', node.pos)
|
||||||
|
@ -3431,7 +3434,8 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
g.write('/*SizeOf*/ sizeof(${util.no_dots(styp)})')
|
g.write('/*SizeOf*/ sizeof(${util.no_dots(styp)})')
|
||||||
}
|
}
|
||||||
ast.IsRefType {
|
ast.IsRefType {
|
||||||
node_typ := g.unwrap_generic(node.typ)
|
typ := if node.typ == g.field_data_type { g.comp_for_field_value.typ } else { node.typ }
|
||||||
|
node_typ := g.unwrap_generic(typ)
|
||||||
sym := g.table.get_type_symbol(node_typ)
|
sym := g.table.get_type_symbol(node_typ)
|
||||||
if sym.language == .v && sym.kind in [.placeholder, .any] {
|
if sym.language == .v && sym.kind in [.placeholder, .any] {
|
||||||
g.error('unknown type `$sym.name`', node.pos)
|
g.error('unknown type `$sym.name`', node.pos)
|
||||||
|
@ -3495,7 +3499,8 @@ fn (mut g Gen) expr(node ast.Expr) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// T.name, typeof(expr).name
|
// T.name, typeof(expr).name
|
||||||
fn (mut g Gen) type_name(typ ast.Type) {
|
fn (mut g Gen) type_name(raw_type ast.Type) {
|
||||||
|
typ := if raw_type == g.field_data_type { g.comp_for_field_value.typ } else { raw_type }
|
||||||
sym := g.table.get_type_symbol(typ)
|
sym := g.table.get_type_symbol(typ)
|
||||||
mut s := ''
|
mut s := ''
|
||||||
if sym.kind == .function {
|
if sym.kind == .function {
|
||||||
|
@ -3511,7 +3516,12 @@ fn (mut g Gen) type_name(typ ast.Type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
||||||
sym := g.table.get_type_symbol(node.expr_type)
|
typ := if node.expr_type == g.field_data_type {
|
||||||
|
g.comp_for_field_value.typ
|
||||||
|
} else {
|
||||||
|
node.expr_type
|
||||||
|
}
|
||||||
|
sym := g.table.get_type_symbol(typ)
|
||||||
if sym.kind == .sum_type {
|
if sym.kind == .sum_type {
|
||||||
// When encountering a .sum_type, typeof() should be done at runtime,
|
// When encountering a .sum_type, typeof() should be done at runtime,
|
||||||
// because the subtype of the expression may change:
|
// because the subtype of the expression may change:
|
||||||
|
@ -3525,11 +3535,11 @@ fn (mut g Gen) typeof_expr(node ast.TypeOf) {
|
||||||
} else if sym.kind == .function {
|
} else if sym.kind == .function {
|
||||||
info := sym.info as ast.FnType
|
info := sym.info as ast.FnType
|
||||||
g.write('_SLIT("${g.fn_decl_str(info)}")')
|
g.write('_SLIT("${g.fn_decl_str(info)}")')
|
||||||
} else if node.expr_type.has_flag(.variadic) {
|
} else if typ.has_flag(.variadic) {
|
||||||
varg_elem_type_sym := g.table.get_type_symbol(g.table.value_type(node.expr_type))
|
varg_elem_type_sym := g.table.get_type_symbol(g.table.value_type(typ))
|
||||||
g.write('_SLIT("...${util.strip_main_name(varg_elem_type_sym.name)}")')
|
g.write('_SLIT("...${util.strip_main_name(varg_elem_type_sym.name)}")')
|
||||||
} else {
|
} else {
|
||||||
x := g.table.type_to_str(node.expr_type)
|
x := g.table.type_to_str(typ)
|
||||||
y := util.strip_main_name(x)
|
y := util.strip_main_name(x)
|
||||||
g.write('_SLIT("$y")')
|
g.write('_SLIT("$y")')
|
||||||
}
|
}
|
||||||
|
|
|
@ -64,6 +64,7 @@ fn test_comptime_for_with_if() {
|
||||||
|
|
||||||
fn test_comptime_for_fields() {
|
fn test_comptime_for_fields() {
|
||||||
println(@FN)
|
println(@FN)
|
||||||
|
mut fields_found := 0
|
||||||
$for field in App.fields {
|
$for field in App.fields {
|
||||||
println(' field: $field.name | ' + no_lines('$field'))
|
println(' field: $field.name | ' + no_lines('$field'))
|
||||||
$if field.typ is string {
|
$if field.typ is string {
|
||||||
|
@ -81,5 +82,19 @@ fn test_comptime_for_fields() {
|
||||||
if field.is_pub && field.is_mut {
|
if field.is_pub && field.is_mut {
|
||||||
assert field.name in ['g', 'h']
|
assert field.name in ['g', 'h']
|
||||||
}
|
}
|
||||||
|
if field.name == 'f' {
|
||||||
|
assert sizeof(field) == 8
|
||||||
|
assert isreftype(field) == false
|
||||||
|
// assert typeof(field) == 'u64'
|
||||||
|
assert typeof(field).name == 'u64'
|
||||||
|
fields_found++
|
||||||
|
}
|
||||||
|
if field.name == 'g' {
|
||||||
|
// assert typeof(field) == 'string'
|
||||||
|
assert typeof(field).name == 'string'
|
||||||
|
assert isreftype(field) == true
|
||||||
|
fields_found++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
assert fields_found == 2
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue