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 let len = struct_binding.fields().count();
25
26 for (i, field) in struct_binding.fields().enumerate() {
27 let Some(name) = field.name() else {
28 continue;
29 };
30
31 if let Some(spread) = field.spread() {
32 if i != len - 1 {
33 ctx.diagnostic(&spread, DiagnosticKind::NonFinalSpread);
34 }
35
36 let binding_symbol = ctx.alloc_symbol(Symbol::Binding(BindingSymbol {
37 name: None,
38 value: reference.clone(),
39 inline: true,
40 }));
41
42 ctx.push_declaration(Declaration::Symbol(binding_symbol));
43
44 ctx.reference(Declaration::Symbol(symbol), None);
45
46 create_binding_for_identifier(ctx, binding_symbol, &name);
47
48 ctx.pop_declaration();
49
50 continue;
51 }
52
53 specified_fields.insert(name.text().to_string());
54
55 let value = match compile_field(ctx, reference.clone(), &Field::Named(name.text())) {
56 FieldResult::Value(value) => value,
57 FieldResult::Unknown => {
58 debug!("Unresolved field access due to unknown field");
59 let type_name = ctx.type_name(reference.ty);
60 ctx.diagnostic(
61 &name,
62 DiagnosticKind::UnknownField(name.text().to_string(), type_name),
63 );
64 ctx.builtins().unresolved.clone()
65 }
66 FieldResult::Error => {
67 debug!("Unresolved field access due to missing field in underlying struct type");
68 let type_name = ctx.type_name(reference.ty);
69 ctx.diagnostic(
70 &name,
71 DiagnosticKind::MissingField(name.text().to_string(), type_name),
72 );
73 ctx.builtins().unresolved.clone()
74 }
75 };
76
77 let field_type = value.ty;
78
79 let binding_symbol = ctx.alloc_symbol(Symbol::Binding(BindingSymbol {
80 name: None,
81 value,
82 inline: true,
83 }));
84
85 ctx.push_declaration(Declaration::Symbol(binding_symbol));
86
87 ctx.reference(Declaration::Symbol(symbol), None);
88
89 if let Some(binding) = field.binding() {
90 create_binding(ctx, binding_symbol, &binding);
91
92 ctx.add_syntax(
93 SyntaxItemKind::FieldReference(SyntaxField {
94 name: name.text().to_string(),
95 container: ty,
96 ty: field_type,
97 }),
98 name.text_range(),
99 );
100 } else {
101 create_binding_for_identifier(ctx, binding_symbol, &name);
102 }
103
104 ctx.pop_declaration();
105 }
106
107 ctx.add_syntax(
108 SyntaxItemKind::CompletionContext(CompletionContext::StructFields {
109 ty,
110 specified_fields: Some(specified_fields),
111 }),
112 struct_binding.syntax().text_range(),
113 );
114}