default struct fields
This commit is contained in:
@@ -4471,12 +4471,19 @@ infer_compound_expr :: proc(
|
||||
}
|
||||
return value
|
||||
}
|
||||
fields := types.fields_for(store, value)
|
||||
item, item_ok := types.node(store, value)
|
||||
initialized := make([]bool, len(fields), checker.allocator)
|
||||
defer delete(initialized, checker.allocator)
|
||||
for keyed in expr.args {
|
||||
keyed_expr := checker.ast_module.exprs[keyed]
|
||||
if keyed_expr.left == ast.INVALID_EXPR {
|
||||
continue
|
||||
}
|
||||
slot, field, ok := find_struct_field_slot(checker, value, keyed_expr.name)
|
||||
if ok && item_ok {
|
||||
initialized[slot-int(item.field_start)] = true
|
||||
}
|
||||
if !ok || !is_inferred_record_field(checker, slot) {
|
||||
_ = infer_nested_expr(checker, keyed_expr.left, locals, pkg, file, demanded, local_types)
|
||||
continue
|
||||
@@ -4491,6 +4498,19 @@ infer_compound_expr :: proc(
|
||||
)
|
||||
}
|
||||
}
|
||||
if item_ok && item.kind == .Struct && !item.tuple {
|
||||
for field, index in fields {
|
||||
if initialized[index] {
|
||||
continue
|
||||
}
|
||||
if field_default, ok := find_struct_field_default(checker, value, symbol.Id(field.name)); ok {
|
||||
_ = infer_nested_expr(
|
||||
checker, field_default.expr, nil, field_default.pkg, field_default.file,
|
||||
demanded, expected=field.type,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return value
|
||||
case .Keyed:
|
||||
return infer_nested_expr(checker, expr.left, locals, pkg, file, demanded, local_types)
|
||||
@@ -6098,6 +6118,27 @@ infer_all :: proc(checker: ^Checker) {
|
||||
checker.record_field_demands_dirty = false
|
||||
spec_count := len(checker.specs)
|
||||
|
||||
for field_default in checker.ast_module.struct_field_defaults {
|
||||
slot, field, ok := find_struct_field_slot(checker, field_default.record, field_default.field)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
expected := field.type if is_runtime_type(checker, field.type) else types.INVALID
|
||||
inferred := infer_expr(
|
||||
checker, field_default.expr, nil, field_default.pkg, field_default.file,
|
||||
expected=expected,
|
||||
)
|
||||
_ = record_field_expr_candidate(
|
||||
checker, slot, field_default.expr, inferred, nil, field_default.pkg, field_default.file,
|
||||
)
|
||||
if is_runtime_type(checker, checker.module.types.fields[slot].type) {
|
||||
_ = record_demand(
|
||||
checker, field_default.expr, checker.module.types.fields[slot].type,
|
||||
nil, nil, field_default.pkg, field_default.file,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Backward demands: a global pushes its own (declared or already-resolved) type
|
||||
// onto open numeric slots reachable through names and numeric arithmetic.
|
||||
for global, index in checker.ast_module.globals {
|
||||
@@ -6753,6 +6794,21 @@ find_struct_field :: proc(checker: ^Checker, struct_type: types.Type, name: symb
|
||||
return 0, {}, false
|
||||
}
|
||||
|
||||
find_struct_field_default :: proc(
|
||||
checker: ^Checker,
|
||||
struct_type: types.Type,
|
||||
name: symbol.Id,
|
||||
) -> (ast.Struct_Field_Default, bool) {
|
||||
resolved := types.resolve_alias(struct_type, &checker.module.types)
|
||||
for field_default in checker.ast_module.struct_field_defaults {
|
||||
if types.resolve_alias(field_default.record, &checker.module.types) == resolved &&
|
||||
field_default.field == name {
|
||||
return field_default, true
|
||||
}
|
||||
}
|
||||
return {}, false
|
||||
}
|
||||
|
||||
find_tuple_field :: proc(checker: ^Checker, tuple_type: types.Type, index: u64) -> (int, types.Field, bool) {
|
||||
item, ok := types.node(&checker.module.types, tuple_type)
|
||||
if !ok || item.kind != .Struct || !item.tuple || index >= u64(item.field_count) {
|
||||
@@ -7895,6 +7951,17 @@ build_compound_expr :: proc(
|
||||
if values[index] != hir.INVALID_EXPR {
|
||||
continue
|
||||
}
|
||||
if field_default, ok := find_struct_field_default(checker, struct_type, symbol.Id(field.name)); ok {
|
||||
values[index] = build_nested_expr(
|
||||
checker, field_default.expr, nil, global_reads, calls,
|
||||
field.type, field_default.pkg, field_default.file,
|
||||
)
|
||||
values[index] = coerce_expr(
|
||||
checker, values[index], field.type,
|
||||
checker.ast_module.exprs[field_default.expr].span,
|
||||
)
|
||||
continue
|
||||
}
|
||||
id := source.addf(checker.diagnostics, expr.span, "missing initializer for struct field '%s'", symbol_text(checker, symbol.Id(field.name)))
|
||||
delete(values, checker.allocator)
|
||||
return invalid_hir_expr(checker, expr.span, id, struct_type)
|
||||
|
||||
Reference in New Issue
Block a user