rukalang/elab/
elaborate_struct_lits.rs1use super::helpers::canonical_nominal_name;
2use super::prelude::*;
3use crate::syntax::ast::NamedExprField;
4
5impl Elaborator {
6 pub(super) fn elaborate_struct_lit_expr(
8 &mut self,
9 name: &mut String,
10 fields: &mut [NamedExprField],
11 expected: Option<&Ty>,
12 locals: &mut Vec<(String, Ty)>,
13 ) -> Result<Ty, ElabError> {
14 let template = self
15 .templates
16 .get(name)
17 .cloned()
18 .ok_or_else(|| ElabError::UnknownTypeConstructor { name: name.clone() })?;
19 let mut provided = BTreeMap::new();
20 for field in fields.iter() {
21 if provided.insert(field.name.clone(), ()).is_some() {
22 return Err(ElabError::DuplicateStructLiteralField {
23 name: name.clone(),
24 field: field.name.clone(),
25 });
26 }
27 }
28
29 let mut bindings = BTreeMap::new();
30 if let Some(Ty::Struct {
31 name: expected_name,
32 args,
33 }) = expected
34 && expected_name == name
35 && args.len() == template.type_params.len()
36 {
37 for (param, arg) in template.type_params.iter().zip(args.iter()) {
38 bindings.insert(param.clone(), arg.clone());
39 }
40 }
41
42 let type_params = template
43 .type_params
44 .iter()
45 .cloned()
46 .collect::<BTreeSet<_>>();
47 for field in &template.fields {
48 let field_expr = fields
49 .iter_mut()
50 .find(|item| item.name == field.name)
51 .ok_or_else(|| ElabError::MissingStructField {
52 name: name.clone(),
53 field: field.name.clone(),
54 })?;
55 let expected_field_ty = self
56 .resolve_type_expr(&field.ty, &bindings, &type_params, None)
57 .ok();
58 let actual_field_ty =
59 self.elaborate_expr(&mut field_expr.value, expected_field_ty.as_ref(), locals)?;
60 self.unify_struct_type_param_bindings(
61 &field.ty,
62 &actual_field_ty,
63 &type_params,
64 &mut bindings,
65 )?;
66 }
67
68 let mut args = Vec::with_capacity(template.type_params.len());
69 for param in &template.type_params {
70 args.push(
71 bindings
72 .get(param)
73 .cloned()
74 .ok_or_else(|| ElabError::StructTypeArgsNotInferred { name: name.clone() })?,
75 );
76 }
77
78 let struct_ty = Ty::Struct {
79 name: name.clone(),
80 args,
81 };
82 self.ensure_ty_instantiated(&struct_ty)?;
83 *name = canonical_nominal_name(&struct_ty);
84 Ok(struct_ty)
85 }
86}