cgen: properly support `typeof()`, sizeof(), ... in compile time `for` (#10896)
							parent
							
								
									12884e9eb7
								
							
						
					
					
						commit
						713a079684
					
				| 
						 | 
					@ -36,8 +36,9 @@ 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