rue_compiler/compile/expr/
struct_initializer.rs1use std::collections::HashMap;
2
3use log::debug;
4use rue_ast::{AstNode, AstStructInitializerExpr};
5use rue_diagnostic::DiagnosticKind;
6use rue_hir::{Declaration, Hir, SymbolPath, Value};
7use rue_types::{Pair, Type, Union};
8
9use crate::{Compiler, PathKind, PathResult, compile_expr, compile_path};
10
11pub fn compile_struct_initializer_expr(
12 ctx: &mut Compiler,
13 expr: &AstStructInitializerExpr,
14) -> Value {
15 let ty = if let Some(path) = expr.path()
16 && let PathResult::Type(ty) =
17 compile_path(ctx, path.syntax(), path.segments(), PathKind::Type)
18 {
19 ty
20 } else {
21 debug!("Unresolved struct initializer path");
22 ctx.builtins().unresolved.ty
23 };
24
25 ctx.reference(Declaration::Type(ty));
26
27 let semantic = rue_types::unwrap_semantic(ctx.types_mut(), ty, true);
28
29 let Type::Struct(struct_type) = ctx.ty(semantic).clone() else {
30 debug!("Unresolved struct initializer due to non struct type");
31 let name = ctx.type_name(ty);
32 ctx.diagnostic(expr.syntax(), DiagnosticKind::NonStructInitializer(name));
33 return ctx.builtins().unresolved.clone();
34 };
35
36 let mut expected_field_types = HashMap::new();
37 let mut current = struct_type.inner;
38
39 for field in &struct_type.fields {
40 let pairs = rue_types::extract_pairs(ctx.types_mut(), current, false);
41
42 if pairs.is_empty() {
43 break;
44 }
45
46 let first = if pairs.len() == 1 {
47 pairs[0].first
48 } else {
49 ctx.alloc_type(Type::Union(Union::new(
50 pairs.iter().map(|pair| pair.first).collect(),
51 )))
52 };
53
54 let rest = if pairs.len() == 1 {
55 pairs[0].rest
56 } else {
57 ctx.alloc_type(Type::Union(Union::new(
58 pairs.iter().map(|pair| pair.rest).collect(),
59 )))
60 };
61
62 expected_field_types.insert(field.clone(), first);
63 current = rest;
64 }
65
66 let mut fields = HashMap::new();
67
68 for field in expr.fields() {
69 let value = if let Some(expr) = field.expr() {
70 compile_expr(
71 ctx,
72 &expr,
73 field
74 .name()
75 .and_then(|name| expected_field_types.get(name.text()).copied()),
76 )
77 } else {
78 let Some(name) = field.name() else {
79 continue;
80 };
81
82 if let PathResult::Symbol(symbol, override_type) =
83 compile_path(ctx, field.syntax(), [name].into_iter(), PathKind::Symbol)
84 {
85 ctx.reference(Declaration::Symbol(symbol));
86
87 let ty = ctx.symbol_type(symbol);
88
89 let mut value = Value::new(ctx.alloc_hir(Hir::Reference(symbol)), ty)
90 .with_reference(SymbolPath {
91 symbol,
92 path: vec![],
93 });
94
95 if let Some(override_type) = override_type {
96 value = value.with_type(override_type);
97 }
98
99 value
100 } else {
101 debug!("Unresolved field path in struct initializer");
102 ctx.builtins().unresolved.clone()
103 }
104 };
105
106 let Some(name) = field.name() else {
107 continue;
108 };
109
110 if fields.insert(name.text().to_string(), value).is_some() {
111 ctx.diagnostic(
112 &name,
113 DiagnosticKind::DuplicateField(name.text().to_string()),
114 );
115 continue;
116 }
117
118 if !struct_type.fields.contains(name.text()) {
119 let type_name = ctx.type_name(ty);
120 ctx.diagnostic(
121 &name,
122 DiagnosticKind::UnknownField(name.text().to_string(), type_name),
123 );
124 }
125 }
126
127 let mut hir = ctx.builtins().nil.hir;
128 let mut list_type = ctx.builtins().nil.ty;
129
130 let mut missing_fields = vec![];
131
132 for (i, name) in struct_type.fields.into_iter().rev().enumerate() {
133 let value = if let Some(value) = fields.remove(&name) {
134 value
135 } else if let Some(value) = ctx.default_field(struct_type.semantic, &name) {
136 value
137 } else {
138 debug!("Unresolved struct initializer field");
139 missing_fields.push(name);
140 ctx.builtins().unresolved.clone()
141 };
142
143 if !struct_type.nil_terminated && i == 0 {
144 hir = value.hir;
145 list_type = value.ty;
146 } else {
147 hir = ctx.alloc_hir(Hir::Pair(value.hir, hir));
148 list_type = ctx.alloc_type(Type::Pair(Pair::new(value.ty, list_type)));
149 }
150 }
151
152 if !missing_fields.is_empty() {
153 let type_name = ctx.type_name(ty);
154 ctx.diagnostic(
155 expr.syntax(),
156 DiagnosticKind::MissingRequiredFields(type_name, missing_fields.join(", ")),
157 );
158 }
159
160 ctx.assign_type(expr.syntax(), list_type, struct_type.inner);
161
162 Value::new(hir, ty)
163}