rue_compiler/compile/binding/
struct_binding.rs

1use 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}