cgen: properly support `typeof()`, sizeof(), ... in compile time `for` (#10896)

pull/10353/head
Uwe Krüger 2021-07-21 22:43:30 +02:00 committed by GitHub
parent 12884e9eb7
commit 713a079684
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 9 deletions

View File

@ -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")')
} }

View File

@ -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
}