rue_compiler/compile/binding/
struct_binding.rs1use std::collections::HashSet;
2
3use log::debug;
4use rue_ast::{AstNode, AstStructBinding};
5use rue_diagnostic::DiagnosticKind;
6use rue_hir::{BindingSymbol, Declaration, Hir, Symbol, SymbolId, SymbolPath, Value};
7
8use crate::{
9 Compiler, CompletionContext, Field, FieldResult, SyntaxField, SyntaxItemKind, compile_field,
10 create_binding, create_binding_for_identifier,
11};
12
13pub fn create_struct_binding(
14 ctx: &mut Compiler,
15 symbol: SymbolId,
16 struct_binding: &AstStructBinding,
17) {
18 let ty = ctx.symbol_type(symbol);
19 let reference = Value::new(ctx.alloc_hir(Hir::Reference(symbol)), ty)
20 .with_reference(SymbolPath::new(symbol, vec![]));
21
22 let mut specified_fields = HashSet::new();
23
24 for field in struct_binding.fields() {
25 let Some(name) = field.name() else {
26 continue;
27 };
28
29 specified_fields.insert(name.text().to_string());
30
31 let value = match compile_field(ctx, reference.clone(), &Field::Named(name.text())) {
32 FieldResult::Value(value) => value,
33 FieldResult::Unknown => {
34 debug!("Unresolved field access due to unknown field");
35 let type_name = ctx.type_name(reference.ty);
36 ctx.diagnostic(
37 &name,
38 DiagnosticKind::UnknownField(name.text().to_string(), type_name),
39 );
40 ctx.builtins().unresolved.clone()
41 }
42 FieldResult::Error => {
43 debug!("Unresolved field access due to missing field in underlying struct type");
44 let type_name = ctx.type_name(reference.ty);
45 ctx.diagnostic(
46 &name,
47 DiagnosticKind::MissingField(name.text().to_string(), type_name),
48 );
49 ctx.builtins().unresolved.clone()
50 }
51 };
52
53 let field_type = value.ty;
54
55 let binding_symbol = ctx.alloc_symbol(Symbol::Binding(BindingSymbol {
56 name: None,
57 value,
58 inline: true,
59 }));
60
61 ctx.push_declaration(Declaration::Symbol(binding_symbol));
62
63 ctx.reference(Declaration::Symbol(symbol), None);
64
65 if let Some(binding) = field.binding() {
66 create_binding(ctx, binding_symbol, &binding);
67
68 ctx.add_syntax(
69 SyntaxItemKind::FieldReference(SyntaxField {
70 name: name.text().to_string(),
71 container: ty,
72 ty: field_type,
73 }),
74 name.text_range(),
75 );
76 } else {
77 create_binding_for_identifier(ctx, binding_symbol, &name);
78 }
79
80 ctx.pop_declaration();
81 }
82
83 ctx.add_syntax(
84 SyntaxItemKind::CompletionContext(CompletionContext::StructFields {
85 ty,
86 specified_fields: Some(specified_fields),
87 }),
88 struct_binding.syntax().text_range(),
89 );
90}