@@ -1190,7 +1190,6 @@ impl Codegen {
11901190 self.declare_rt("knot_record_field_by_index", &[p, p], &[p]);
11911191 self.declare_rt("knot_record_from_pairs", &[p, p], &[p]);
11921192 self.declare_rt("knot_record_update", &[p], &[p]);
1193− self.declare_rt("knot_record_update_batch", &[p, p, p], &[p]);
11941193
11951194 // Relation operations
11961195 self.declare_rt("knot_relation_empty", &[], &[p]);
@@ -4349,34 +4348,6 @@ impl Codegen {
43494348 }
43504349 }
43514350
4352− ast::ExprKind::RecordUpdate { base, fields } => {
4353− let base_val = self.compile_expr(builder, base, env, db);
4354− let n = fields.len();
4355− // Compile and sort update fields for batch merge
4356− let mut compiled: Vec<(&str, Value)> = Vec::with_capacity(n);
4357− for f in fields {
4358− let val = self.compile_expr(builder, &f.value, env, db);
4359− compiled.push((&f.name, val));
4360− }
4361− compiled.sort_by_key(|(name, _)| *name);
4362−
4363− let ptr_bytes = self.ptr_type.bytes() as i32;
4364− let slot_size = (3 * n as u32) * ptr_bytes as u32;
4365− let slot = builder.create_sized_stack_slot(
4366− StackSlotData::new(StackSlotKind::ExplicitSlot, slot_size, 3),
4367− );
4368− for (i, (name, val)) in compiled.iter().enumerate() {
4369− let (key_ptr, key_len) = self.string_ptr(builder, name);
4370− let base_off = (i as i32) * (3 * ptr_bytes);
4371− builder.ins().stack_store(key_ptr, slot, base_off);
4372− builder.ins().stack_store(key_len, slot, base_off + ptr_bytes);
4373− builder.ins().stack_store(*val, slot, base_off + 2 * ptr_bytes);
4374− }
4375− let data_ptr = builder.ins().stack_addr(self.ptr_type, slot, 0);
4376− let count = builder.ins().iconst(self.ptr_type, n as i64);
4377− self.call_rt(builder, "knot_record_update_batch", &[base_val, data_ptr, count])
4378− }
4379−
43804351 ast::ExprKind::FieldAccess { expr, field } => {
43814352 // `base.todo` — the unimplemented hole, reached through the
43824353 // `base` namespace. Dispatch-only (no `base` record field holds
@@ -5809,12 +5780,6 @@ impl Codegen {
58095780 Record(fields) => fields
58105781 .iter()
58115782 .all(|f| self.collect_direct_write_targets(&f.value, out)),
5812− RecordUpdate { base, fields } => {
5813− self.collect_direct_write_targets(base, out)
5814− && fields
5815− .iter()
5816− .all(|f| self.collect_direct_write_targets(&f.value, out))
5817− }
58185783 List(items) => items
58195784 .iter()
58205785 .all(|e| self.collect_direct_write_targets(e, out)),
@@ -9581,9 +9546,7 @@ impl Codegen {
95819546 matches!(&expr.node, ast::ExprKind::Var(n) if n == "base")
95829547 && builtins.contains(field.as_str())
95839548 }
9584− ast::ExprKind::Record(_)
9585− | ast::ExprKind::RecordUpdate { .. }
9586− | ast::ExprKind::List(_) => false,
9549+ ast::ExprKind::Record(_) | ast::ExprKind::List(_) => false,
95879550 _ => false,
95889551 }
95899552 }
@@ -9786,10 +9749,6 @@ impl Codegen {
97869749 ast::ExprKind::Record(fields) => fields
97879750 .iter()
97889751 .any(|f| Self::expr_contains_writes(&f.value, write_fns, known_fns, passthrough_fns)),
9789− ast::ExprKind::RecordUpdate { base, fields } => {
9790− Self::expr_contains_writes(base, write_fns, known_fns, passthrough_fns)
9791− || fields.iter().any(|f| Self::expr_contains_writes(&f.value, write_fns, known_fns, passthrough_fns))
9792− }
97939752 ast::ExprKind::FieldAccess { expr, .. } => {
97949753 Self::expr_contains_writes(expr, write_fns, known_fns, passthrough_fns)
97959754 }
@@ -12430,10 +12389,6 @@ impl Codegen {
1243012389 ast::ExprKind::Record(fields) => {
1243112390 fields.iter().any(|f| Self::references_source(&f.value, source_name))
1243212391 }
12433− ast::ExprKind::RecordUpdate { base, fields } => {
12434− Self::references_source(base, source_name)
12435− || fields.iter().any(|f| Self::references_source(&f.value, source_name))
12436− }
1243712392 ast::ExprKind::FieldAccess { expr, .. } => Self::references_source(expr, source_name),
1243812393 ast::ExprKind::List(elems) => {
1243912394 elems.iter().any(|e| Self::references_source(e, source_name))
@@ -15839,10 +15794,6 @@ fn expr_has_user_calls(expr: &ast::Expr, user_fns: &HashMap<String, (FuncId, usi
1583915794 ast::ExprKind::Record(fields) => {
1584015795 fields.iter().any(|f| expr_has_user_calls(&f.value, user_fns))
1584115796 }
15842− ast::ExprKind::RecordUpdate { base, fields } => {
15843− expr_has_user_calls(base, user_fns)
15844− || fields.iter().any(|f| expr_has_user_calls(&f.value, user_fns))
15845− }
1584615797 ast::ExprKind::FieldAccess { expr, .. } => expr_has_user_calls(expr, user_fns),
1584715798 ast::ExprKind::Lambda { body, .. } => expr_has_user_calls(body, user_fns),
1584815799 ast::ExprKind::Annot { expr, .. } => expr_has_user_calls(expr, user_fns),
@@ -15891,12 +15842,6 @@ fn expr_references_var(expr: &ast::Expr, var_name: &str) -> bool {
1589115842 .any(|p| matches!(&p.node, ast::PatKind::Var(n) if n == var_name));
1589215843 !rebinds && expr_references_var(body, var_name)
1589315844 }
15894− ast::ExprKind::RecordUpdate { base, fields } => {
15895− expr_references_var(base, var_name)
15896− || fields
15897− .iter()
15898− .any(|f| expr_references_var(&f.value, var_name))
15899− }
1590015845 ast::ExprKind::TimeUnitLit { value, .. } => expr_references_var(value, var_name),
1590115846 ast::ExprKind::Annot { expr, .. } => expr_references_var(expr, var_name),
1590215847 ast::ExprKind::Refine(inner) => expr_references_var(inner, var_name),
@@ -17351,16 +17296,6 @@ fn beta_reduce_inner(
1735117296 })
1735217297 .collect(),
1735317298 ),
17354− RecordUpdate { base, fields } => RecordUpdate {
17355− base: Box::new(beta_reduce_inner(base, fun_bodies, let_bindings, visited, fuel)),
17356− fields: fields
17357− .iter()
17358− .map(|f| ast::Field {
17359− name: f.name.clone(),
17360− value: beta_reduce_inner(&f.value, fun_bodies, let_bindings, visited, fuel),
17361− })
17362− .collect(),
17363− },
1736417299 List(items) => List(
1736517300 items
1736617301 .iter()
@@ -17457,18 +17392,6 @@ fn substitute_inner(
1745717392 })
1745817393 .collect::<Option<Vec<_>>>()?,
1745917394 ),
17460− RecordUpdate { base, fields } => RecordUpdate {
17461− base: Box::new(substitute_inner(base, var, value, value_fv)?),
17462− fields: fields
17463− .iter()
17464− .map(|f| {
17465− substitute_inner(&f.value, var, value, value_fv).map(|v| ast::Field {
17466− name: f.name.clone(),
17467− value: v,
17468− })
17469− })
17470− .collect::<Option<Vec<_>>>()?,
17471− },
1747217395 List(items) => List(
1747317396 items
1747417397 .iter()
@@ -17524,10 +17447,6 @@ fn expr_mentions_var(expr: &ast::Expr, var: &str) -> bool {
1752417447 | DataCtor { .. } | SourceDecl { .. } | SubsetConstraint { .. } | RouteDecl { .. } | RouteCompositeDecl { .. } => false,
1752517448 ViewDecl { body, .. } | DerivedDecl { body, .. } => expr_mentions_var(body, var),
1752617449 Record(fields) => fields.iter().any(|f| expr_mentions_var(&f.value, var)),
17527− RecordUpdate { base, fields } => {
17528− expr_mentions_var(base, var)
17529− || fields.iter().any(|f| expr_mentions_var(&f.value, var))
17530− }
1753117450 FieldAccess { expr: e, .. } => expr_mentions_var(e, var),
1753217451 List(items) => items.iter().any(|e| expr_mentions_var(e, var)),
1753317452 Lambda { body, .. } => expr_mentions_var(body, var),
@@ -17615,12 +17534,6 @@ fn collect_free_vars_set(expr: &ast::Expr, bound: &HashSet<String>, free: &mut H
1761517534 collect_free_vars_set(&f.value, bound, free);
1761617535 }
1761717536 }
17618− RecordUpdate { base, fields } => {
17619− collect_free_vars_set(base, bound, free);
17620− for f in fields {
17621− collect_free_vars_set(&f.value, bound, free);
17622− }
17623− }
1762417537 List(items) => {
1762517538 for e in items {
1762617539 collect_free_vars_set(e, bound, free);
@@ -18566,10 +18479,6 @@ fn expr_contains_derived_ref(expr: &ast::Expr, name: &str) -> bool {
1856618479 ast::ExprKind::Record(fields) => {
1856718480 fields.iter().any(|f| expr_contains_derived_ref(&f.value, name))
1856818481 }
18569− ast::ExprKind::RecordUpdate { base, fields } => {
18570− expr_contains_derived_ref(base, name)
18571− || fields.iter().any(|f| expr_contains_derived_ref(&f.value, name))
18572− }
1857318482 ast::ExprKind::FieldAccess { expr, .. } => expr_contains_derived_ref(expr, name),
1857418483 ast::ExprKind::List(elems) => elems.iter().any(|e| expr_contains_derived_ref(e, name)),
1857518484 ast::ExprKind::Lambda { body, .. } => expr_contains_derived_ref(body, name),
@@ -18680,12 +18589,6 @@ fn collect_free_vars(expr: &ast::Expr, bound: &HashSet<&str>, free: &mut Vec<Str
1868018589 collect_free_vars(&f.value, bound, free);
1868118590 }
1868218591 }
18683− ast::ExprKind::RecordUpdate { base, fields } => {
18684− collect_free_vars(base, bound, free);
18685− for f in fields {
18686− collect_free_vars(&f.value, bound, free);
18687− }
18688− }
1868918592 ast::ExprKind::FieldAccess { expr, .. } => {
1869018593 collect_free_vars(expr, bound, free);
1869118594 }
@@ -18858,9 +18761,6 @@ pub(crate) fn expr_refs_var(expr: &ast::Expr, var: &str) -> bool {
1885818761 })
1885918762 }
1886018763 ast::ExprKind::Record(fields) => fields.iter().any(|f| expr_refs_var(&f.value, var)),
18861− ast::ExprKind::RecordUpdate { base, fields } => {
18862− expr_refs_var(base, var) || fields.iter().any(|f| expr_refs_var(&f.value, var))
18863− }
1886418764 ast::ExprKind::List(elems) => elems.iter().any(|e| expr_refs_var(e, var)),
1886518765 ast::ExprKind::Do(stmts) => {
1886618766 for stmt in stmts {
@@ -18969,10 +18869,6 @@ fn expr_uses_var_as_value(expr: &ast::Expr, var: &str) -> bool {
1896918869 }
1897018870 // `{p | age: 1}` rebuilds the whole record `p`, so the base is a value
1897118871 // use even though field names appear next to it.
18972− ast::ExprKind::RecordUpdate { base, fields } => {
18973− expr_uses_var_as_value(base, var)
18974− || fields.iter().any(|f| expr_uses_var_as_value(&f.value, var))
18975− }
1897618872 ast::ExprKind::List(elems) => {
1897718873 elems.iter().any(|e| expr_uses_var_as_value(e, var))
1897818874 }
@@ -19283,13 +19179,6 @@ fn pretty_expr(expr: &ast::Expr) -> String {
1928319179 .collect();
1928419180 format!("{{{}}}", fs.join(", "))
1928519181 }
19286− ast::ExprKind::RecordUpdate { base, fields } => {
19287− let fs: Vec<String> = fields
19288− .iter()
19289− .map(|f| format!("{}: {}", f.name, pretty_expr(&f.value)))
19290− .collect();
19291− format!("{{{} | {}}}", pretty_expr(base), fs.join(", "))
19292− }
1929319182 ast::ExprKind::FieldAccess { expr, field } => {
1929419183 format!("{}.{}", pretty_expr(expr), field)
1929519184 }