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 { | ||||
| 	pref         &pref.Preferences | ||||
| 	module_built string | ||||
| 	pref            &pref.Preferences | ||||
| 	module_built    string | ||||
| 	field_data_type ast.Type // cache her to avoid map lookups
 | ||||
| mut: | ||||
| 	table                  &ast.Table | ||||
| 	out                    strings.Builder | ||||
|  | @ -225,6 +226,7 @@ pub fn gen(files []&ast.File, table &ast.Table, pref &pref.Preferences) string { | |||
| 		module_built: module_built | ||||
| 		timers: util.new_timers(timers_should_print) | ||||
| 		inner_loop: &ast.EmptyStmt{} | ||||
| 		field_data_type: ast.Type(table.find_type_idx('FieldData')) | ||||
| 	} | ||||
| 	g.timers.start('cgen init') | ||||
| 	for mod in g.table.modules { | ||||
|  | @ -3422,7 +3424,8 @@ fn (mut g Gen) expr(node ast.Expr) { | |||
| 			g.select_expr(node) | ||||
| 		} | ||||
| 		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) | ||||
| 			if sym.language == .v && sym.kind in [.placeholder, .any] { | ||||
| 				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)})') | ||||
| 		} | ||||
| 		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) | ||||
| 			if sym.language == .v && sym.kind in [.placeholder, .any] { | ||||
| 				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
 | ||||
| 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) | ||||
| 	mut s := '' | ||||
| 	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) { | ||||
| 	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 { | ||||
| 		// When encountering a .sum_type, typeof() should be done at runtime,
 | ||||
| 		// 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 { | ||||
| 		info := sym.info as ast.FnType | ||||
| 		g.write('_SLIT("${g.fn_decl_str(info)}")') | ||||
| 	} else if node.expr_type.has_flag(.variadic) { | ||||
| 		varg_elem_type_sym := g.table.get_type_symbol(g.table.value_type(node.expr_type)) | ||||
| 	} else if typ.has_flag(.variadic) { | ||||
| 		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)}")') | ||||
| 	} else { | ||||
| 		x := g.table.type_to_str(node.expr_type) | ||||
| 		x := g.table.type_to_str(typ) | ||||
| 		y := util.strip_main_name(x) | ||||
| 		g.write('_SLIT("$y")') | ||||
| 	} | ||||
|  |  | |||
|  | @ -64,6 +64,7 @@ fn test_comptime_for_with_if() { | |||
| 
 | ||||
| fn test_comptime_for_fields() { | ||||
| 	println(@FN) | ||||
| 	mut fields_found := 0 | ||||
| 	$for field in App.fields { | ||||
| 		println('  field: $field.name | ' + no_lines('$field')) | ||||
| 		$if field.typ is string { | ||||
|  | @ -81,5 +82,19 @@ fn test_comptime_for_fields() { | |||
| 		if field.is_pub && field.is_mut { | ||||
| 			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