Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/v2/00_core.dag
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,7 @@ type DeclaredFuncEnv {

type Node {
name: String
ident: Int
span: SourceSpan
ident_span: SourceSpan?
// Fractal composition -- operations, capabilities, items are all children
Expand Down
48 changes: 47 additions & 1 deletion src/v2/05_emit_rust.dag
Original file line number Diff line number Diff line change
Expand Up @@ -3550,7 +3550,44 @@ fn emit_typed_record_lit(type_name: String?, fields: List<Node>, parent_enum: St
} else { val_str }
concat(" ", emit_ident(name: f_name, target: Rust), ": ", field_val, ",")
)
let all_field_strs = field_strs
// Fill default values for fields defined on the type but not provided in source.
let provided_names = fields |> map(f => field_init_node_name_at(n: f, source_index: scope.type_env.source_index))
let provided_set = fold(provided_names, init: empty_map(), f: (acc, n) => map_insert(acc, n, true))
// Fill default values for struct fields not explicitly set in .dag source.
// Only emits defaults if ALL missing fields have known zero values — this avoids
// false positives from cross-module type name collisions in the summary registry.
let summary = lookup_emit_type_summary(emit_info: emit_info, type_name: tn)
let default_strs = match summary {
Some { value: s } =>
let fs = s.field_summaries
let ftm = s.field_type_map
let missing = map_keys(fs) |> filter(k => !emit_map_has(m: provided_set, key: k))
let all_defaultable = missing |> all(fname =>
let has_zv = match map_get(ftm, fname) {
Some { value: ft } => match rust_zero_value(type_name: ft) { Some { value: _ } => true, None => false }
None => false
}
has_zv || is_optional_struct_field(emit_info: emit_info, struct_name: tn, field_name: fname)
)
if all_defaultable {
missing |> flat_map(fname =>
if is_optional_struct_field(emit_info: emit_info, struct_name: tn, field_name: fname) {
[concat(" ", emit_ident(name: fname, target: Rust), ": None,")]
} else {
match map_get(ftm, fname) {
Some { value: ft } =>
match rust_zero_value(type_name: ft) {
Some { value: zv } => [concat(" ", emit_ident(name: fname, target: Rust), ": ", zv, ",")]
None => []
}
None => []
}
}
)
} else { [] }
None => []
}
let all_field_strs = concat(field_strs, default_strs)
let fields_str = all_field_strs |> join(separator: "\n")
let raw = concat(display_tn, " {\n", fields_str, "\n}")
// Rc wrapping is the caller's responsibility (data_decl_body, emit_typed_expr, etc.).
Expand All @@ -3561,6 +3598,15 @@ fn emit_typed_record_lit(type_name: String?, fields: List<Node>, parent_enum: St
}


// Zero-value for a Rust type, used to fill struct fields not set in .dag source.
// Returns none if the type has no obvious zero-value (caller must set it explicitly).
fn rust_zero_value(type_name: String) -> String? {
if type_name == "Int" { Some { value: "0" } }
else if type_name == "Bool" { Some { value: "false" } }
else if type_name == "String" { Some { value: concat("\"\"", ".to_string()") } }
else { none }
}

fn emit_typed_bin_op(op: BinOp, algebra_field: AlgebraFieldKind?, left: Node, right: Node, registry: Map<String, ItemInfo>, scope: InferScope, depth: Int, shared_types: Map<String, Bool>, emit_info: EmitGraphInfo) -> String {
let l_str = emit_typed_expr(texpr: left, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024)
let r_str = emit_typed_expr(texpr: right, registry: registry, scope: scope, depth: depth, shared_types: shared_types, emit_info: emit_info, fuel: 1024)
Expand Down
55 changes: 54 additions & 1 deletion src/v2/stage0/src/v2_compiler_emit_rust.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ pub fn type_variable_node(id: String) -> Rc<Node> {
has_non_tail_self_call: false,
match_pattern: None,
expr_data: Rc::new(ExprData::NoExprData),
ident: 0,
})
}

Expand Down Expand Up @@ -3626,7 +3627,43 @@ let field_val = if needs_wrap.clone() {
};
v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(" ".to_string(), emit_ident(f_name.clone(), RenderTarget::Rust)), ": ".to_string()), field_val.clone()), ",".to_string())
}); } __result });
let all_field_strs = field_strs;
let provided_names = Rc::new({ let mut __result = Vec::new(); for f in fields.clone().iter().cloned() { __result.push(field_init_node_name_at(f.clone(), scope.type_env.clone().source_index.clone())); } __result });
let provided_set = provided_names.iter().cloned().fold(v2_rt::rc_empty_map::<bool>(), |acc: Rc<HashMap<String, bool>>, n: String| v2_rt::rc_map_insert(acc.clone(), n.clone(), true));
let summary = lookup_emit_type_summary(emit_info.clone(), tn.clone());
let default_strs = match summary {
Some(s) => {
let fs = s.field_summaries.clone();
let ftm = s.field_type_map.clone();
let missing = Rc::new({ let mut __result = Vec::new(); for k in Rc::new(v2_rt::map_keys(&fs)).iter().cloned() { if !emit_map_has(provided_set.clone(), k.clone()) { __result.push(k); } } __result });
let all_defaultable = { let mut __all = true; for fname in missing.clone().iter().cloned() { if !({
let has_zv = match v2_rt::map_get(&ftm, fname.clone()) {
Some(ft) => match rust_zero_value(&ft) {
Some(_) => true,
None => false,
},
None => false,
};
(has_zv.clone() || is_optional_struct_field(emit_info.clone(), tn.clone(), fname.clone()))
}) { __all = false; break; } } __all };
if all_defaultable {
Rc::new({ let mut __result = Vec::new(); for fname in missing.clone().iter().cloned() { __result.extend((*if is_optional_struct_field(emit_info.clone(), tn.clone(), fname.clone()) {
Rc::new(vec![v2_rt::concat(v2_rt::concat(" ".to_string(), emit_ident(fname.clone(), RenderTarget::Rust)), ": None,".to_string())])
} else {
match v2_rt::map_get(&ftm, fname.clone()) {
Some(ft) => match rust_zero_value(&ft) {
Some(zv) => Rc::new(vec![v2_rt::concat(v2_rt::concat(v2_rt::concat(v2_rt::concat(" ".to_string(), emit_ident(fname.clone(), RenderTarget::Rust)), ": ".to_string()), zv.clone()), ",".to_string())]),
None => Rc::new(vec![]),
},
None => Rc::new(vec![]),
}
}).iter().cloned()); } __result })
} else {
Rc::new(vec![])
}
},
None => Rc::new(vec![]),
};
let all_field_strs = v2_rt::concat(field_strs, default_strs);
let fields_str = all_field_strs.join(&"\n".to_string());
let raw = v2_rt::concat(v2_rt::concat(v2_rt::concat(display_tn, " {\n".to_string()), fields_str), "\n}".to_string());
raw
Expand All @@ -3638,6 +3675,22 @@ raw
}
}

pub fn rust_zero_value(type_name: &String) -> Option<String> {
if (type_name.clone().as_str() == "Int".to_string().as_str()) {
Some("0".to_string())
} else {
if (type_name.clone().as_str() == "Bool".to_string().as_str()) {
Some("false".to_string())
} else {
if (type_name.clone().as_str() == "String".to_string().as_str()) {
Some(v2_rt::concat("\"\"".to_string(), ".to_string()".to_string()))
} else {
None
}
}
}
}

pub fn emit_typed_bin_op(op: &BinOp, algebra_field: Option<AlgebraFieldKind>, left: &Rc<Node>, right: &Rc<Node>, registry: &Rc<HashMap<String, Rc<ItemInfo>>>, scope: &Rc<InferScope>, depth: i64, shared_types: &Rc<HashMap<String, bool>>, emit_info: &Rc<EmitGraphInfo>) -> String {
{
let l_str = emit_typed_expr(left.clone(), registry.clone(), &scope, depth.clone(), shared_types.clone(), emit_info.clone(), 1024);
Expand Down
Loading
Loading