on master help sign in
Remove the full keyword; *rel = expr handles both write forms

full *rel = expr (a full table replacement, FullSet) is redundant — the *rel = expr form (Set) already handles the full replace when the value does not reference *rel. Remove the full keyword, the FullSet AST variant, the typechecker must-reference error, and the codegen FullSet arm. The *rel = expr form disambiguates by shape: a referencing expr is a read-modify-write; a non-referencing expr is a full replace. All tests/examples updated. Suite 291/0.

commit376ce5a4ee8e016e574338f3e8a8697fce03aff9 authoriko <mail@iko.soy> dateTue 1 Sep 2026, 10:38 (1 month ago) parentc50d621
40 files changed+150−408
crates/knot-compiler/src/base.rs+1−1 crates/knot-compiler/src/codegen.rs+15−67 crates/knot-compiler/src/desugar.rs+7−7 crates/knot-compiler/src/infer.rs+7−84 crates/knot-compiler/src/nonterm.rs+1−1 crates/knot-compiler/src/sql_lint.rs+2−6 crates/knot-compiler/src/stratify.rs+1−1 crates/knot-compiler/src/types.rs+2−2 crates/knot-compiler/src/unused.rs+1−5 crates/knot-jit/tests/concurrency.rs+2−2 crates/knot-jit/tests/constraints.rs+5−5 crates/knot-jit/tests/extract.rs+2−2 crates/knot-jit/tests/literal_pushdown.rs+7−7 crates/knot-jit/tests/migration.rs+2−2 crates/knot-jit/tests/migration_corner.rs+40−40 crates/knot-jit/tests/persistence.rs+19−19 crates/knot-jit/tests/refinements.rs+2−2 crates/knot-jit/tests/views.rs+4−4 crates/knot-lsp/src/defs.rs+1−1 crates/knot-lsp/src/folding.rs+1−1 crates/knot-lsp/src/selection_range.rs+1−1 crates/knot-lsp/src/semantic_tokens.rs+1−1 crates/knot-lsp/src/utils.rs+1−2 crates/knot/src/ast.rs−3 crates/knot/src/format.rs+2−24 crates/knot/src/lexer.rs−4 crates/knot/src/parser.rs−91 examples/arith_aggregate.knot+1−1 examples/constraints.knot+2−2 examples/fold_stream.knot+1−1 examples/groupby.knot+1−1 examples/hello.knot+1−1 examples/inline_pushdown.knot+1−1 examples/let_pushdown.knot+1−1 examples/migrate.knot+1−1 examples/nested.knot+1−1 examples/query_opt.knot+2−2 examples/recursive.knot+1−1 examples/showcase.knot+9−9 examples/stm_row_filter.knot+1−1
crates/knot-compiler/src/base.rs+1−1
@@ -396,7 +396,7 @@ fn shift_expr_spans(e: &mut ast::Expr, offset: usize) {
396396 shift_stmt_spans(s, offset);
397397 }
398398 }
399− Set { target, value } | FullSet { target, value } => {
399+ Set { target, value } => {
400400 shift_expr_spans(target, offset);
401401 shift_expr_spans(value, offset);
402402 }
crates/knot-compiler/src/codegen.rs+15−67
@@ -6080,53 +6080,7 @@ impl<M: cranelift_module::Module> Codegen<M> {
60806080 }
60816081 }
60826082
6083− ast::ExprKind::FullSet { target, value } => {
6084− if let ast::ExprKind::SourceRef { name, .. } = &target.node {
6085− let schema = self.source_schemas.get(name).cloned().unwrap_or_default();
6086−
6087− // Single-value source (`Person *owner`, `Int 1 *counter`):
6088− // wrap the bare value as a one-row `[{_value: val}]` relation
6089− // and write it. (`scalar_sources` are the scalar subset;
6090− // single-value covers records and ADTs too.)
6091− if self.scalar_sources.contains(name) || self.single_value_sources.contains(name) {
6092− let val = self.compile_set_value_expr(builder, value, env, db);
6093− // Validate refinements on the raw value (wrap as [val] for the check)
6094− if self.source_refinements.contains_key(name) {
6095− let singleton =
6096− self.call_rt(builder, "knot_relation_singleton", &[val]);
6097− self.emit_refinement_checks(builder, name, singleton, env, db);
6098− }
6099− let wrapped = self.call_rt(builder, "knot_scalar_source_wrap", &[val]);
6100− let (name_ptr, name_len) = self.string_ptr(builder, name);
6101− let (schema_ptr, schema_len) = self.string_ptr(builder, &schema);
6102− self.call_rt_void(
6103− builder,
6104− "knot_source_write",
6105− &[db, name_ptr, name_len, schema_ptr, schema_len, wrapped],
6106− );
6107− return self.call_rt(builder, "knot_value_unit", &[]);
6108− }
6109−
6110− let val = self.compile_set_value_expr(builder, value, env, db);
6111− self.emit_refinement_checks(builder, name, val, env, db);
6112− let (name_ptr, name_len) = self.string_ptr(builder, name);
6113− let (schema_ptr, schema_len) = self.string_ptr(builder, &schema);
6114− self.call_rt_void(
6115− builder,
6116− "knot_source_write",
6117− &[db, name_ptr, name_len, schema_ptr, schema_len, val],
6118− );
6119− self.call_rt(builder, "knot_value_unit", &[])
6120− } else {
6121− self.push_codegen_error(
6122− builder,
6123− target.span,
6124− "codegen: replace target must be a source reference",
6125− )
6126− }
6127− }
6128−
6129− ast::ExprKind::Atomic(inner) => {
6083+ast::ExprKind::Atomic(inner) => {
61306084 let is_nested = self.atomic_retry_block.is_some();
61316085 // Whether the body might issue a SQL write (Set/FullSet,
61326086 // direct or via a user fn). If not, the SAVEPOINT can be
@@ -6414,7 +6368,7 @@ impl<M: cranelift_module::Module> Codegen<M> {
64146368 };
64156369 match &expr.node {
64166370 ast::ExprKind::NameOf(_) => false,
6417− Set { target, value } | FullSet { target, value } => {
6371+ Set { target, value } => {
64186372 let target_ok = match &target.node {
64196373 SourceRef { name, .. } => {
64206374 out.push(name.clone());
@@ -10306,7 +10260,7 @@ impl<M: cranelift_module::Module> Codegen<M> {
1030610260 // Only writes (`set`/`full =`) and `atomic` are effects. `full`
1030710261 // is a viewer-only tag with no semantic effect.
1030810262 ast::ExprKind::SourceRef { .. } => false,
10309− ast::ExprKind::Set { .. } | ast::ExprKind::FullSet { .. } => true,
10263+ ast::ExprKind::Set { .. } => true,
1031010264 ast::ExprKind::Atomic(_) => true,
1031110265 ast::ExprKind::App { func, arg } => {
1031210266 Self::expr_contains_io(func, builtins, io_fns)
@@ -10515,7 +10469,7 @@ impl<M: cranelift_module::Module> Codegen<M> {
1051510469 }
1051610470 };
1051710471 match &expr.node {
10518− ast::ExprKind::Set { .. } | ast::ExprKind::FullSet { .. } => true,
10472+ ast::ExprKind::Set { .. } => true,
1051910473 ast::ExprKind::Atomic(inner) => {
1052010474 Self::expr_contains_writes(inner, write_fns, known_fns, passthrough_fns)
1052110475 }
@@ -10669,7 +10623,7 @@ impl<M: cranelift_module::Module> Codegen<M> {
1066910623 // A query over a source/derived is a pure, lazy `[T]` — NOT IO.
1067010624 // `full` is a viewer-only tag with no semantic effect.
1067110625 ast::ExprKind::SourceRef { .. } => false,
10672− ast::ExprKind::Set { .. } | ast::ExprKind::FullSet { .. } => true,
10626+ ast::ExprKind::Set { .. } => true,
1067310627 ast::ExprKind::Atomic(_) => true,
1067410628 ast::ExprKind::BinOp { lhs, rhs, .. } => {
1067510629 self.expr_is_io_scoped(lhs, scopes) || self.expr_is_io_scoped(rhs, scopes)
@@ -10810,7 +10764,7 @@ impl<M: cranelift_module::Module> Codegen<M> {
1081010764 // as the relation value itself.
1081110765 ast::ExprKind::SourceRef { .. } => false,
1081210766 // Writes and atomic blocks must not run at `let` time.
10813− ast::ExprKind::Set { .. } | ast::ExprKind::FullSet { .. } => true,
10767+ ast::ExprKind::Set { .. } => true,
1081410768 ast::ExprKind::Atomic(_) => true,
1081510769 ast::ExprKind::BinOp { lhs, rhs, .. } => {
1081610770 self.expr_has_external_io(lhs) || self.expr_has_external_io(rhs)
@@ -11050,7 +11004,6 @@ impl<M: cranelift_module::Module> Codegen<M> {
1105011004 let is_io_computation = matches!(
1105111005 &expr.node,
1105211006 ast::ExprKind::Set { .. }
11053− | ast::ExprKind::FullSet { .. }
1105411007 | ast::ExprKind::Atomic(_)
1105511008 | ast::ExprKind::Do(_)
1105611009 | ast::ExprKind::Case { .. }
@@ -12247,7 +12200,6 @@ impl<M: cranelift_module::Module> Codegen<M> {
1224712200 | ast::ExprKind::List(_)
1224812201 | ast::ExprKind::Do(_)
1224912202 | ast::ExprKind::Set { .. }
12250− | ast::ExprKind::FullSet { .. }
1225112203 ) || self.expr_is_known_relation(expr);
1225212204 if is_known_relation {
1225312205 val
@@ -12699,7 +12651,7 @@ impl<M: cranelift_module::Module> Codegen<M> {
1269912651 self.call_rt_void(builder, "knot_relation_push", &[result, val]);
1270012652 } else if matches!(
1270112653 &expr.node,
12702− ast::ExprKind::Set { .. } | ast::ExprKind::FullSet { .. }
12654+ ast::ExprKind::Set { .. }
1270312655 ) {
1270412656 // Compile set inside do block
1270512657 let _ = self.compile_expr(builder, expr, env, db);
@@ -13417,7 +13369,7 @@ impl<M: cranelift_module::Module> Codegen<M> {
1341713369 ast::StmtKind::GroupBy { key } => Self::references_source(key, source_name),
1341813370 ast::StmtKind::Expr(e) => Self::references_source(e, source_name),
1341913371 }),
13420− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
13372+ ast::ExprKind::Set { target, value } => {
1342113373 Self::references_source(target, source_name)
1342213374 || Self::references_source(value, source_name)
1342313375 }
@@ -18790,7 +18742,6 @@ fn beta_reduce_inner(
1879018742 | Case { .. }
1879118743 | Do(_)
1879218744 | Set { .. }
18793− | FullSet { .. }
1879418745 | Atomic(_)
1879518746 | TimeUnitLit { .. }
1879618747 | Annot { .. }
@@ -18920,7 +18871,7 @@ fn substitute_inner(
1892018871 // matchers then compiled the broken AST, panicking with
1892118872 // "codegen: undefined variable" or silently capturing a same-named
1892218873 // in-scope variable.
18923− Case { .. } | Do(_) | Set { .. } | FullSet { .. } | Atomic(_) | Serve { .. } => {
18874+ Case { .. } | Do(_) | Set { .. } | Atomic(_) | Serve { .. } => {
1892418875 if expr_mentions_var(expr, var) {
1892518876 return None;
1892618877 }
@@ -18975,7 +18926,7 @@ fn expr_mentions_var(expr: &ast::Expr, var: &str) -> bool {
1897518926 || arms.iter().any(|a| expr_mentions_var(&a.body, var))
1897618927 }
1897718928 Do(stmts) => in_stmts(stmts),
18978− Set { target, value } | FullSet { target, value } => {
18929+ Set { target, value } => {
1897918930 expr_mentions_var(target, var) || expr_mentions_var(value, var)
1898018931 }
1898118932 Atomic(inner) | Refine(inner) => expr_mentions_var(inner, var),
@@ -19098,7 +19049,7 @@ fn collect_free_vars_set(expr: &ast::Expr, bound: &HashSet<String>, free: &mut H
1909819049 }
1909919050 }
1910019051 }
19101− Set { target, value } | FullSet { target, value } => {
19052+ Set { target, value } => {
1910219053 collect_free_vars_set(target, bound, free);
1910319054 collect_free_vars_set(value, bound, free);
1910419055 }
@@ -20315,7 +20266,7 @@ fn collect_free_vars(expr: &ast::Expr, bound: &HashSet<&str>, free: &mut Vec<Str
2031520266 }
2031620267 }
2031720268 }
20318− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
20269+ ast::ExprKind::Set { target, value } => {
2031920270 collect_free_vars(target, bound, free);
2032020271 collect_free_vars(value, bound, free);
2032120272 }
@@ -20454,7 +20405,7 @@ pub(crate) fn expr_refs_var(expr: &ast::Expr, var: &str) -> bool {
2045420405 }
2045520406 false
2045620407 }
20457− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
20408+ ast::ExprKind::Set { target, value } => {
2045820409 expr_refs_var(target, var) || expr_refs_var(value, var)
2045920410 }
2046020411 ast::ExprKind::Atomic(inner) | ast::ExprKind::Refine(inner) => expr_refs_var(inner, var),
@@ -20565,7 +20516,7 @@ fn expr_uses_var_as_value(expr: &ast::Expr, var: &str) -> bool {
2056520516 }
2056620517 false
2056720518 }
20568− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
20519+ ast::ExprKind::Set { target, value } => {
2056920520 expr_uses_var_as_value(target, var) || expr_uses_var_as_value(value, var)
2057020521 }
2057120522 ast::ExprKind::Atomic(inner) | ast::ExprKind::Refine(inner) => {
@@ -20881,10 +20832,7 @@ fn pretty_expr(expr: &ast::Expr) -> String {
2088120832 ast::ExprKind::Set { target, value } => {
2088220833 format!("{} = {}", pretty_expr(target), pretty_expr(value))
2088320834 }
20884− ast::ExprKind::FullSet { target, value } => {
20885− format!("full {} = {}", pretty_expr(target), pretty_expr(value))
20886− }
20887− ast::ExprKind::Atomic(e) => format!("atomic ({})", pretty_expr(e)),
20835+ast::ExprKind::Atomic(e) => format!("atomic ({})", pretty_expr(e)),
2088820836 ast::ExprKind::TimeUnitLit { value, .. } => pretty_expr(value),
2088920837 ast::ExprKind::Annot { expr, .. } => pretty_expr(expr),
2089020838 ast::ExprKind::Refine(inner) => format!("refine {}", pretty_expr(inner)),
crates/knot-compiler/src/desugar.rs+7−7
@@ -167,7 +167,7 @@ fn walk_expr_children_read(expr: &Expr, f: &mut impl FnMut(&Expr)) {
167167 }
168168 }
169169 }
170− ExprKind::Set { target, value } | ExprKind::FullSet { target, value } => {
170+ ExprKind::Set { target, value } => {
171171 f(target);
172172 f(value);
173173 }
@@ -310,7 +310,7 @@ fn collect_fun_bodies<'a>(
310310 }
311311 }
312312 }
313− ExprKind::Set { target, value } | ExprKind::FullSet { target, value } => {
313+ ExprKind::Set { target, value } => {
314314 collect_fun_bodies(target, fun_bodies, fun_sig_io);
315315 collect_fun_bodies(value, fun_bodies, fun_sig_io);
316316 }
@@ -404,7 +404,7 @@ fn expr_contains_io(expr: &Expr, builtins: &HashSet<&str>, io_fns: &HashSet<Stri
404404 match &expr.node {
405405 ExprKind::Var(name) => builtins.contains(name.as_str()) || io_fns.contains(name.as_str()),
406406 ExprKind::SourceRef { .. } => true,
407− ExprKind::Set { .. } | ExprKind::FullSet { .. } => true,
407+ ExprKind::Set { .. } => true,
408408 ExprKind::Atomic(_) => true,
409409 ExprKind::TimeUnitLit { value, .. } => expr_contains_io(value, builtins, io_fns),
410410 ExprKind::Annot { expr, .. } => expr_contains_io(expr, builtins, io_fns),
@@ -630,7 +630,7 @@ fn walk_expr_children(expr: &mut Expr, f: &mut impl FnMut(&mut Expr)) {
630630 }
631631 }
632632 }
633− ExprKind::Set { target, value } | ExprKind::FullSet { target, value } => {
633+ ExprKind::Set { target, value } => {
634634 f(target);
635635 f(value);
636636 }
@@ -658,7 +658,7 @@ fn desugar_expr(expr: &mut Expr, io_fns: &IoFns, source_vars: &HashSet<String>)
658658 // First, recurse into sub-expressions (bottom-up).
659659 // We handle Set/FullSet specially to avoid desugaring their value do blocks.
660660 match &mut expr.node {
661− ExprKind::Set { target, value } | ExprKind::FullSet { target, value } => {
661+ ExprKind::Set { target, value } => {
662662 desugar_expr(target, io_fns, source_vars);
663663 // Don't desugar the top-level do block of a set value,
664664 // but DO recurse into its sub-expressions.
@@ -791,7 +791,7 @@ fn recurse_into_children(expr: &mut Expr, io_fns: &IoFns, source_vars: &HashSet<
791791 ExprKind::Do(stmts) => {
792792 desugar_do_stmts(stmts, io_fns, source_vars);
793793 }
794− ExprKind::Set { target, value } | ExprKind::FullSet { target, value } => {
794+ ExprKind::Set { target, value } => {
795795 desugar_expr(target, io_fns, source_vars);
796796 desugar_expr(value, io_fns, source_vars);
797797 }
@@ -1201,7 +1201,7 @@ fn expr_is_io(expr: &Expr, io_fns: &HashSet<String>) -> bool {
12011201 || io_fns.contains(name.as_str())
12021202 }
12031203 ExprKind::SourceRef { .. } => true,
1204− ExprKind::Set { .. } | ExprKind::FullSet { .. } => true,
1204+ ExprKind::Set { .. } => true,
12051205 ExprKind::Atomic(_) => true,
12061206 ExprKind::BinOp { lhs, rhs, .. } => expr_is_io(lhs, io_fns) || expr_is_io(rhs, io_fns),
12071207 ExprKind::UnaryOp { operand, .. } => expr_is_io(operand, io_fns),
crates/knot-compiler/src/infer.rs+7−84
@@ -7580,87 +7580,10 @@ impl Infer {
75807580 let prev_suppress = self.suppress_refine_intro.replace(source_refined);
75817581 self.check_expr(value, &target_inner);
75827582 self.suppress_refine_intro = prev_suppress;
7583− if let ast::ExprKind::SourceRef { name, .. } = &target.node {
7584− // `set` is a read-modify-write only when the value actually
7585− // reads the source. Relations require that reference (it's
7586− // enforced below), so a valid relation `set` genuinely
7587− // reads. But a scalar `*counter = 5` that references nothing
7588− // reads nothing.
7589− let references = value_references_source(
7590− value,
7591− name,
7592− &self.source_var_binds,
7593− &self.let_bindings,
7594− );
7595− // Require `full *rel = ...` when the value is a full
7596− // replacement (doesn't reference *rel directly or via a
7597− // local alias `xs <- *rel`). Skip views and scalar
7598− // sources where the distinction is meaningless.
7599− let is_view = self.view_names.contains(name);
7600− let is_relation = matches!(self.source_types.get(name), Some(Ty::Relation(_)));
7601− if !is_view && is_relation && !references {
7602− self.error(
7603− format!(
7604− "`*{name} = ...` must reference `*{name}` \
7605− (directly or via a `<- *{name}` bind); \
7606− use `full *{name} = ...` for a full replacement"
7607− ),
7608− expr.span,
7609− );
7610− }
7611− }
7612− Ty::IO(Box::new(Ty::unit()))
7613− }
7614−
7615− ast::ExprKind::FullSet { target, value } => {
7616− let target_ty = self.infer_expr(target);
7617− let target_applied = self.apply(&target_ty);
7618− let unwrap_io = |ty: &Ty| match ty {
7619− Ty::IO(inner) => (**inner).clone(),
7620− other => other.clone(),
7621− };
7622− let target_inner = unwrap_io(&target_applied);
7623− // See the `Set` arm: writes are runtime-validated, so suppress
7624− // the refined-introduction check for this structural unify —
7625− // but only for the source's own refinements, not refined
7626− // function parameters used inside the value.
7627− let source_refined = self.refined_names_in(&target_inner);
7628− let prev_suppress = self.suppress_refine_intro.replace(source_refined);
7629− self.check_expr(value, &target_inner);
7630− self.suppress_refine_intro = prev_suppress;
7631− if let ast::ExprKind::SourceRef { name, .. } = &target.node {
7632− // Reject `full *rel = ...` when the value references
7633− // `*rel` (directly, via a `<- *rel` bind, or via a let
7634− // binding that ultimately reads from `*rel`) — `set`
7635− // would produce the same final state more efficiently.
7636− // Skip views and scalar sources where the distinction
7637− // is meaningless.
7638− let is_view = self.view_names.contains(name);
7639− let is_relation = matches!(self.source_types.get(name), Some(Ty::Relation(_)));
7640− if !is_view
7641− && is_relation
7642− && value_references_source(
7643− value,
7644− name,
7645− &self.source_var_binds,
7646− &self.let_bindings,
7647− )
7648− {
7649− self.error(
7650− format!(
7651− "`full *{name} = ...` is unnecessary when \
7652− the value references `*{name}` \
7653− (directly or via a `<- *{name}` bind); \
7654− use `*{name} = ...` instead"
7655− ),
7656− expr.span,
7657− );
7658− }
7659− }
76607583 Ty::IO(Box::new(Ty::unit()))
76617584 }
76627585
7663− ast::ExprKind::Atomic(inner) => {
7586+ast::ExprKind::Atomic(inner) => {
76647587 let prev = self.in_atomic;
76657588 self.in_atomic = true;
76667589 let inner_ty = self.infer_expr(inner);
@@ -9592,7 +9515,7 @@ impl Infer {
95929515 // A query over a source/derived is a pure, lazy `[T]` — NOT IO.
95939516 // Only writes (`set`/`full =`) and `atomic` are effects.
95949517 ast::ExprKind::SourceRef { .. } => false,
9595− ast::ExprKind::Set { .. } | ast::ExprKind::FullSet { .. } => true,
9518+ ast::ExprKind::Set { .. } => true,
95969519 ast::ExprKind::Atomic(_) => true,
95979520 ast::ExprKind::BinOp { lhs, rhs, .. } => {
95989521 self.expr_is_io_prescan(lhs) || self.expr_is_io_prescan(rhs)
@@ -13844,7 +13767,7 @@ fn value_references_source_inner(
1384413767 value_references_source_inner(e, source_name, aliases, let_bindings, visited)
1384513768 }
1384613769 }),
13847− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
13770+ ast::ExprKind::Set { target, value } => {
1384813771 value_references_source_inner(target, source_name, aliases, let_bindings, visited)
1384913772 || value_references_source_inner(value, source_name, aliases, let_bindings, visited)
1385013773 }
@@ -15406,7 +15329,7 @@ fn walk_expr_children_mut(expr: &mut ast::Expr, f: &mut impl FnMut(&mut ast::Exp
1540615329 }
1540715330 }
1540815331 }
15409− Set { target, value } | FullSet { target, value } => {
15332+ Set { target, value } => {
1541015333 f(target);
1541115334 f(value);
1541215335 }
@@ -15481,7 +15404,7 @@ pub(crate) fn subst_var(expr: &mut ast::Expr, var: &str, replacement: &ast::Expr
1548115404 }
1548215405 }
1548315406 }
15484− Set { target, value } | FullSet { target, value } => {
15407+ Set { target, value } => {
1548515408 subst_var(target, var, replacement);
1548615409 subst_var(value, var, replacement);
1548715410 }
@@ -15573,7 +15496,7 @@ pub(crate) fn walk_exprs_read<'a>(e: &'a ast::Expr, f: &mut impl FnMut(&'a ast::
1557315496 }
1557415497 }
1557515498 }
15576− Set { target, value } | FullSet { target, value } => {
15499+ Set { target, value } => {
1557715500 walk_exprs_read(target, f);
1557815501 walk_exprs_read(value, f);
1557915502 }
@@ -15721,7 +15644,7 @@ fn for_each_data_ctor_scoped<'a>(
1572115644 }
1572215645 }
1572315646 }
15724− Set { target, value } | FullSet { target, value } => {
15647+ Set { target, value } => {
1572515648 walk(target, d, f);
1572615649 walk(value, d, f);
1572715650 }
crates/knot-compiler/src/nonterm.rs+1−1
@@ -233,7 +233,7 @@ fn collect_unguarded_calls<'a>(
233233 }
234234 }
235235 }
236− Set { target, value } | FullSet { target, value } => {
236+ Set { target, value } => {
237237 collect_unguarded_calls(target, defs, caller_name, caller, out);
238238 collect_unguarded_calls(value, defs, caller_name, caller, out);
239239 }
crates/knot-compiler/src/sql_lint.rs+2−6
@@ -93,11 +93,7 @@ fn lint_expr(
9393 lint_expr(value, source_schemas, views, fun_bodies, diags);
9494 }
9595 }
96− ExprKind::FullSet { target, value } => {
97− lint_expr(target, source_schemas, views, fun_bodies, diags);
98− lint_expr(value, source_schemas, views, fun_bodies, diags);
99− }
100− ExprKind::Do(stmts) => {
96+ExprKind::Do(stmts) => {
10197 lint_do_block(stmts, source_schemas, views, diags);
10298 for stmt in stmts {
10399 lint_stmt(stmt, source_schemas, views, fun_bodies, diags);
@@ -958,7 +954,7 @@ fn references_source(expr: &Expr, source_name: &str) -> bool {
958954 references_source(scrutinee, source_name)
959955 || arms.iter().any(|a| references_source(&a.body, source_name))
960956 }
961− ExprKind::Set { target, value } | ExprKind::FullSet { target, value } => {
957+ ExprKind::Set { target, value } => {
962958 references_source(target, source_name) || references_source(value, source_name)
963959 }
964960 ExprKind::Annot { expr, .. } => references_source(expr, source_name),
crates/knot-compiler/src/stratify.rs+1−1
@@ -438,7 +438,7 @@ fn collect_edges(
438438 ast::ExprKind::Atomic(inner) => {
439439 collect_edges(inner, polarity, node_names, env, partial_diffs, diff_wrappers, out);
440440 }
441− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
441+ ast::ExprKind::Set { target, value } => {
442442 collect_edges(target, polarity, node_names, env, partial_diffs, diff_wrappers, out);
443443 collect_edges(value, polarity, node_names, env, partial_diffs, diff_wrappers, out);
444444 }
crates/knot-compiler/src/types.rs+2−2
@@ -430,7 +430,7 @@ fn walk_exprs(e: &Expr, f: &mut impl FnMut(&Expr)) {
430430 }
431431 }
432432 }
433− ExprKind::Set { target, value } | ExprKind::FullSet { target, value } => {
433+ ExprKind::Set { target, value } => {
434434 walk_exprs(target, f);
435435 walk_exprs(value, f);
436436 }
@@ -565,7 +565,7 @@ fn collect_type_and_data_refs<'a>(
565565 }
566566 }
567567 }
568− ExprKind::Set { target, value } | ExprKind::FullSet { target, value } => {
568+ ExprKind::Set { target, value } => {
569569 collect_type_and_data_refs(target, aliases, data_decls);
570570 collect_type_and_data_refs(value, aliases, data_decls);
571571 }
crates/knot-compiler/src/unused.rs+1−5
@@ -291,11 +291,7 @@ fn walk_expr(e: &Expr, r: &mut Refs) {
291291 walk_expr(target, r);
292292 walk_expr(value, r);
293293 }
294− ExprKind::FullSet { target, value } => {
295− walk_expr(target, r);
296− walk_expr(value, r);
297− }
298− ExprKind::Atomic(inner) => walk_expr(inner, r),
294+ExprKind::Atomic(inner) => walk_expr(inner, r),
299295 ExprKind::TimeUnitLit { value, .. } => walk_expr(value, r),
300296 ExprKind::Annot { expr, ty } => {
301297 walk_expr(expr, r);
crates/knot-jit/tests/concurrency.rs+2−2
@@ -78,9 +78,9 @@ C {n (Int 1)}
7878Rel C *cs
7979}
8080(|
81− full *cs = [{n 1}]
81+ *cs = [{n 1}]
8282 base.fork (atomic |
83− full *cs = [{n 2}]
83+ *cs = [{n 2}]
8484 base.println (base.show (9223372036854775807 + 1))
8585 yield {})
8686 base.sleep 300
crates/knot-jit/tests/constraints.rs+5−5
@@ -14,8 +14,8 @@ Rel {customer Text amount (Int 1)} *orders
1414*orders.customer <= *people.name
1515}
1616(|
17− full *people = [{name "Alice" age 30 email "a@x"} {name "Bob" age 25 email "b@x"}]
18− full *orders = [{customer "Alice" amount 100}]
17+ *people = [{name "Alice" age 30 email "a@x"} {name "Bob" age 25 email "b@x"}]
18+ *orders = [{customer "Alice" amount 100}]
1919 base.println (base.show (base.count *orders))
2020 yield {})"#,
2121 // count is a one-element relation now (Rel Int), so it shows as [1].
@@ -36,8 +36,8 @@ Rel {customer Text amount (Int 1)} *orders
3636*orders.customer <= *people.name
3737}
3838(|
39− full *people = [{name "Alice" age 30 email "a@x"}]
40− full *orders = [{customer "Nobody" amount 100}]
39+ *people = [{name "Alice" age 30 email "a@x"}]
40+ *orders = [{customer "Nobody" amount 100}]
4141 base.println "wrote"
4242 yield {})"#,
4343 dir.path(),
@@ -67,7 +67,7 @@ Rel Person *people
6767*people <= *people.email
6868}
6969(|
70− full *people = [{name "A" email "dup@x"} {name "B" email "dup@x"}]
70+ *people = [{name "A" email "dup@x"} {name "B" email "dup@x"}]
7171 base.println "wrote"
7272 yield {})"#,
7373 dir.path(),
crates/knot-jit/tests/extract.rs+2−2
@@ -370,7 +370,7 @@ V1 {name Text age (Int 1)}
370370Rel V1 *people
371371}
372372(|
373− full *people = [{name "a" age 30} {name "b" age 25}]
373+ *people = [{name "a" age 30} {name "b" age 25}]
374374 rows <- *people
375375 base.println (base.extract rows)
376376 yield {})"#,
@@ -389,7 +389,7 @@ Shape Circle {radius (Float 1)} Rect {w (Float 1)}
389389Rel Shape *shapes
390390}
391391(|
392− full *shapes = [(Shape.Circle {radius 1.5}) (Shape.Rect {w 2.0})]
392+ *shapes = [(Shape.Circle {radius 1.5}) (Shape.Rect {w 2.0})]
393393 rows <- *shapes
394394 base.println (base.extract rows)
395395 yield {})"#,
crates/knot-jit/tests/literal_pushdown.rs+7−7
@@ -53,7 +53,7 @@ fn record_literal_cross_join_pushes_down() {
5353fn mixed_comprehension_correct_rows() {
5454 let (stdout, _stderr, code) = e2e::run_program(
5555 "xcj",
56− "with {\nPerson {name Text age (Int 1)}\nRel Person *people\npairs (|\n p <- *people\n x <- [100 200]\n yield {name p.name n (p.age + x)})\n}\n(| full *people = [{name \"a\" age 30}]; base.println (base.show pairs); yield {})\n",
56+ "with {\nPerson {name Text age (Int 1)}\nRel Person *people\npairs (|\n p <- *people\n x <- [100 200]\n yield {name p.name n (p.age + x)})\n}\n(| *people = [{name \"a\" age 30}]; base.println (base.show pairs); yield {})\n",
5757 );
5858 assert_eq!(code, 0);
5959 // Cross product: the one person × the two literal scalars.
@@ -67,7 +67,7 @@ fn where_over_literal_column_pushes_down() {
6767 // a SQL WHERE (not materialize).
6868 let stderr = build_stderr(
6969 "wlc",
70− "with {\nPerson {name Text age (Int 1)}\nRel Person *people\nfiltered (|\n p <- *people\n x <- [100 200]\n where x > 150\n yield {name p.name n (p.age + x)})\n}\n(| full *people = [{name \"a\" age 30}]; base.println (base.show filtered); yield {})\n",
70+ "with {\nPerson {name Text age (Int 1)}\nRel Person *people\nfiltered (|\n p <- *people\n x <- [100 200]\n where x > 150\n yield {name p.name n (p.age + x)})\n}\n(| *people = [{name \"a\" age 30}]; base.println (base.show filtered); yield {})\n",
7171 );
7272 assert!(
7373 !stderr.contains("in-memory table read"),
@@ -75,7 +75,7 @@ fn where_over_literal_column_pushes_down() {
7575 );
7676 let (stdout, _, code) = e2e::run_program(
7777 "wlc",
78− "with {\nPerson {name Text age (Int 1)}\nRel Person *people\nfiltered (|\n p <- *people\n x <- [100 200]\n where x > 150\n yield {name p.name n (p.age + x)})\n}\n(| full *people = [{name \"a\" age 30}]; base.println (base.show filtered); yield {})\n",
78+ "with {\nPerson {name Text age (Int 1)}\nRel Person *people\nfiltered (|\n p <- *people\n x <- [100 200]\n where x > 150\n yield {name p.name n (p.age + x)})\n}\n(| *people = [{name \"a\" age 30}]; base.println (base.show filtered); yield {})\n",
7979 );
8080 assert_eq!(code, 0);
8181 // Only x=200 survives (200 > 150), so n = 30 + 200 = 230.
@@ -89,7 +89,7 @@ fn literal_column_arithmetic_stays_int() {
8989 // Int (not the float fallback), so the result renders as integers.
9090 let (stdout, _, code) = e2e::run_program(
9191 "lci",
92− "with {\nPerson {name Text age (Int 1)}\nRel Person *people\npairs (|\n p <- *people\n x <- [100 200]\n yield {name p.name n (p.age + x)})\n}\n(| full *people = [{name \"a\" age 30}]; base.println (base.show (base.map (\\r -> r.n) pairs)); yield {})\n",
92+ "with {\nPerson {name Text age (Int 1)}\nRel Person *people\npairs (|\n p <- *people\n x <- [100 200]\n yield {name p.name n (p.age + x)})\n}\n(| *people = [{name \"a\" age 30}]; base.println (base.show (base.map (\\r -> r.n) pairs)); yield {})\n",
9393 );
9494 assert_eq!(code, 0);
9595 // Integers, not floats (a float mistype would render 130.0 / 230.0).
@@ -103,7 +103,7 @@ fn union_source_and_literal_pushes_down() {
103103 // literal is an inline subquery — a single UNION query, no materialization.
104104 let stderr = build_stderr(
105105 "usl",
106− "with {\nPerson {name Text age (Int 1)}\nRel Person *people\n}\n(| full *people = [{name \"a\" age 30}]; base.println (base.show (base.union *people [{name \"c\" age 50}])); yield {})\n",
106+ "with {\nPerson {name Text age (Int 1)}\nRel Person *people\n}\n(| *people = [{name \"a\" age 30}]; base.println (base.show (base.union *people [{name \"c\" age 50}])); yield {})\n",
107107 );
108108 assert!(
109109 !stderr.contains("in-memory table read"),
@@ -111,7 +111,7 @@ fn union_source_and_literal_pushes_down() {
111111 );
112112 let (stdout, _, code) = e2e::run_program(
113113 "usl",
114− "with {\nPerson {name Text age (Int 1)}\nRel Person *people\n}\n(| full *people = [{name \"a\" age 30}]; base.println (base.show (base.union *people [{name \"c\" age 50}])); yield {})\n",
114+ "with {\nPerson {name Text age (Int 1)}\nRel Person *people\n}\n(| *people = [{name \"a\" age 30}]; base.println (base.show (base.union *people [{name \"c\" age 50}])); yield {})\n",
115115 );
116116 assert_eq!(code, 0);
117117 assert!(stdout.contains("{age 30 name a}") && stdout.contains("{age 50 name c}"),
@@ -124,7 +124,7 @@ fn inter_source_and_literal_pushes_down() {
124124 // in SQL.
125125 let (stdout, _, code) = e2e::run_program(
126126 "isl",
127− "with {\nPerson {name Text age (Int 1)}\nRel Person *people\n}\n(| full *people = [{name \"a\" age 30} {name \"b\" age 10}]; base.println (base.show (base.inter *people [{name \"a\" age 30} {name \"c\" age 50}])); yield {})\n",
127+ "with {\nPerson {name Text age (Int 1)}\nRel Person *people\n}\n(| *people = [{name \"a\" age 30} {name \"b\" age 10}]; base.println (base.show (base.inter *people [{name \"a\" age 30} {name \"c\" age 50}])); yield {})\n",
128128 );
129129 assert_eq!(code, 0);
130130 // Only {a 30} is in both.
crates/knot-jit/tests/migration.rs+2−2
@@ -42,7 +42,7 @@ PersonV1 {name Text}
4242Rel PersonV1 *people
4343}
4444(|
45− full *people = [{name "Alice"}]
45+ *people = [{name "Alice"}]
4646 yield {})"#;
4747
4848const V2_PENDING: &str = r#"with {
@@ -348,7 +348,7 @@ V1 {name Text}
348348Rel V1 *people
349349}
350350(|
351− full *people = [{name "alice"} {name "bob"}]
351+ *people = [{name "alice"} {name "bob"}]
352352 rows <- *people
353353 base.println (base.show rows)
354354 yield {})"#;
crates/knot-jit/tests/migration_corner.rs+40−40
@@ -68,7 +68,7 @@ V1 {name Text}
6868Rel V1 *people
6969}
7070(|
71− full *people = [{name "a"} {name "b"}]
71+ *people = [{name "a"} {name "b"}]
7272 yield {})"#;
7373 let v2 = r#"with {
7474V1 {name Text}
@@ -100,7 +100,7 @@ V1 {name Text age (Int 1)}
100100Rel V1 *people
101101}
102102(|
103− full *people = [{name "a" age 5}]
103+ *people = [{name "a" age 5}]
104104 yield {})"#;
105105 let v2 = r#"with {
106106V1 {name Text age (Int 1)}
@@ -132,7 +132,7 @@ V1 {name Text}
132132Rel V1 *people
133133}
134134(|
135− full *people = [{name "a"}]
135+ *people = [{name "a"}]
136136 yield {})"#;
137137 let v2 = r#"with {
138138V1 {name Text}
@@ -164,7 +164,7 @@ V1 {a Text b (Int 1)}
164164Rel V1 *r
165165}
166166(|
167− full *r = [{a "x" b 1}]
167+ *r = [{a "x" b 1}]
168168 yield {})"#;
169169 let v2 = r#"with {
170170V1 {a Text b (Int 1)}
@@ -199,7 +199,7 @@ V1 {name Text tags (Rel Text)}
199199Rel V1 *people
200200}
201201(|
202− full *people = [{name "a" tags ["x" "y"]}]
202+ *people = [{name "a" tags ["x" "y"]}]
203203 yield {})"#;
204204 let v2 = r#"with {
205205V1 {name Text tags (Rel Text)}
@@ -233,7 +233,7 @@ V1 {name Text pets (Rel Pet)}
233233Rel V1 *people
234234}
235235(|
236− full *people = [{name "a" pets [{name "pup" legs 4}]}]
236+ *people = [{name "a" pets [{name "pup" legs 4}]}]
237237 yield {})"#;
238238 let v2 = r#"with {
239239Pet {name Text legs (Int 1)}
@@ -267,7 +267,7 @@ V1 {name Text grid (Rel (Rel (Int 1)))}
267267Rel V1 *r
268268}
269269(|
270− full *r = [{name "a" grid [[1 2] [3]]}]
270+ *r = [{name "a" grid [[1 2] [3]]}]
271271 yield {})"#;
272272 let v2 = r#"with {
273273V1 {name Text grid (Rel (Rel (Int 1)))}
@@ -300,7 +300,7 @@ V1 {name Text addr Addr}
300300Rel V1 *people
301301}
302302(|
303− full *people = [{name "a" addr {city "x"}}]
303+ *people = [{name "a" addr {city "x"}}]
304304 yield {})"#;
305305 let v2 = r#"with {
306306Addr {city Text}
@@ -336,7 +336,7 @@ V1 {name Text addr Addr}
336336Rel V1 *people
337337}
338338(|
339− full *people = [{name "a" addr {city "x"}}]
339+ *people = [{name "a" addr {city "x"}}]
340340 yield {})"#;
341341 let v2 = r#"with {
342342Addr {city Text}
@@ -373,7 +373,7 @@ V1 {name Text sh Shape}
373373Rel V1 *es
374374}
375375(|
376− full *es = [{name "a" sh (Shape.Circle {radius 3})}]
376+ *es = [{name "a" sh (Shape.Circle {radius 3})}]
377377 yield {})"#;
378378 let v2 = r#"with {
379379Shape Circle {radius (Int 1)} Point {}
@@ -409,7 +409,7 @@ Ev Ping {} Msg {text Text}
409409Rel Ev *evs
410410}
411411(|
412− full *evs = [(Ev.Ping {}) (Ev.Msg {text "hi"})]
412+ *evs = [(Ev.Ping {}) (Ev.Msg {text "hi"})]
413413 yield {})"#;
414414 let v2 = r#"with {
415415Ev Ping {} Msg {text Text}
@@ -476,7 +476,7 @@ V1 {name Text}
476476Rel V1 *people
477477}
478478(|
479− full *people = [{name "a"} {name "b"} {name "c"} {name "d"}]
479+ *people = [{name "a"} {name "b"} {name "c"} {name "d"}]
480480 yield {})"#;
481481 let v2 = r#"with {
482482V1 {name Text}
@@ -511,7 +511,7 @@ V1 {name Text}
511511Rel V1 *r
512512}
513513(|
514− full *r = [{name "x"}]
514+ *r = [{name "x"}]
515515 yield {})"#;
516516 let v2 = r#"with {
517517V1 {name Text}
@@ -567,7 +567,7 @@ V1 {name Text}
567567Rel V1 *people
568568}
569569(|
570− full *people = [{name "a"}]
570+ *people = [{name "a"}]
571571 yield {})"#;
572572 let v2 = r#"with {
573573V1 {name Text}
@@ -600,7 +600,7 @@ V1 {name Text tags (Rel Text)}
600600Rel V1 *people
601601}
602602(|
603− full *people = [{name "a" tags ["x"]}]
603+ *people = [{name "a" tags ["x"]}]
604604 yield {})"#;
605605 let v2 = r#"with {
606606V1 {name Text tags (Rel Text)}
@@ -633,7 +633,7 @@ V1 {name Text tags (Rel Text)}
633633Rel V1 *people
634634}
635635(|
636− full *people = [{name "a" tags ["x"]}]
636+ *people = [{name "a" tags ["x"]}]
637637 yield {})"#;
638638 let v2 = r#"with {
639639V1 {name Text tags (Rel Text)}
@@ -669,8 +669,8 @@ W {id (Int 1)}
669669Rel W *widgets
670670}
671671(|
672− full *people = [{name "a"}]
673− full *widgets = [{id 1}]
672+ *people = [{name "a"}]
673+ *widgets = [{id 1}]
674674 yield {})"#;
675675 let v2 = r#"with {
676676V1 {name Text}
@@ -711,8 +711,8 @@ W {id (Int 1)}
711711Rel W *widgets
712712}
713713(|
714− full *people = [{name "a"}]
715− full *widgets = [{id 1}]
714+ *people = [{name "a"}]
715+ *widgets = [{id 1}]
716716 yield {})"#;
717717 let v2 = r#"with {
718718V1 {name Text}
@@ -744,7 +744,7 @@ V1 {name Text col Color}
744744Rel V1 *es
745745}
746746(|
747− full *es = [{name "a" col (Color.Red {})}]
747+ *es = [{name "a" col (Color.Red {})}]
748748 yield {})"#;
749749 let v2 = r#"with {
750750Color Red {} Green {}
@@ -778,7 +778,7 @@ V1 {name Text}
778778Rel V1 *people
779779}
780780(|
781− full *people = [{name "a"}]
781+ *people = [{name "a"}]
782782 yield {})"#;
783783 let v2 = r#"with {
784784V1 {name Text}
@@ -810,7 +810,7 @@ V1 {n (Int 1)}
810810Rel V1 *r
811811}
812812(|
813− full *r = [{n 5}]
813+ *r = [{n 5}]
814814 yield {})"#;
815815 let v2 = r#"with {
816816Shape Circle {radius (Int 1)} Point {}
@@ -848,7 +848,7 @@ Rel V1 *people
848848*people <= *people.name
849849}
850850(|
851− full *people = [{name "a"}]
851+ *people = [{name "a"}]
852852 yield {})"#;
853853 let v2 = r#"with {
854854V1 {name Text}
@@ -885,7 +885,7 @@ V1 {name Text}
885885Rel V1 *people
886886}
887887(|
888− full *people = [{name "a"}]
888+ *people = [{name "a"}]
889889 yield {})"#;
890890 let v2 = r#"with {
891891V1 {name Text}
@@ -936,7 +936,7 @@ V1 {name Text}
936936Rel V1 *people
937937}
938938(|
939− full *people = [{name "a"}]
939+ *people = [{name "a"}]
940940 yield {})"#;
941941 build_and_run(&dir, "mig_noop", v1);
942942 lock_in_dir(dir.path(), "mig_noop");
@@ -980,7 +980,7 @@ V1 {name Text nick (Maybe Text)}
980980Rel V1 *people
981981}
982982(|
983− full *people = [{name "a" nick (Maybe.Just {value "al"})} {name "b" nick (Maybe.Nothing {})}]
983+ *people = [{name "a" nick (Maybe.Just {value "al"})} {name "b" nick (Maybe.Nothing {})}]
984984 yield {})"#;
985985 let v2 = r#"with {
986986V1 {name Text nick (Maybe Text)}
@@ -1015,7 +1015,7 @@ V1 {name Text score (Float 1)}
10151015Rel V1 *r
10161016}
10171017(|
1018− full *r = [{name "a" score 1.5}]
1018+ *r = [{name "a" score 1.5}]
10191019 yield {})"#;
10201020 let v2 = r#"with {
10211021V1 {name Text score (Float 1)}
@@ -1052,7 +1052,7 @@ V1 {name Text inner Inner}
10521052Rel V1 *r
10531053}
10541054(|
1055− full *r = [{name "a" inner {shapes [(Shape.Point {})]}}]
1055+ *r = [{name "a" inner {shapes [(Shape.Point {})]}}]
10561056 yield {})"#;
10571057 let v2 = r#"with {
10581058Shape Circle {radius (Int 1)} Point {}
@@ -1091,7 +1091,7 @@ V1 {name Text addr Addr}
10911091Rel V1 *people
10921092}
10931093(|
1094− full *people = [{name "a" addr {city "x" zip 100}}]
1094+ *people = [{name "a" addr {city "x" zip 100}}]
10951095 yield {})"#;
10961096 let v2 = r#"with {
10971097Addr {city Text zip (Int 1)}
@@ -1125,7 +1125,7 @@ V1 {old Text}
11251125Rel V1 *r
11261126}
11271127(|
1128− full *r = [{old "x"}]
1128+ *r = [{old "x"}]
11291129 yield {})"#;
11301130 let v2 = r#"with {
11311131V1 {old Text}
@@ -1164,8 +1164,8 @@ Rel V1 *pets
11641164*pets.email <= *owners.email
11651165}
11661166(|
1167− full *owners = [{email "a@x"}]
1168− full *pets = [{email "a@x"}]
1167+ *owners = [{email "a@x"}]
1168+ *pets = [{email "a@x"}]
11691169 yield {})"#;
11701170 let v2 = r#"with {
11711171Owner {email Text}
@@ -1207,8 +1207,8 @@ Rel V1 *pets
12071207*pets.email <= *owners.email
12081208}
12091209(|
1210− full *owners = [{email "a@x"}]
1211− full *pets = [{email "a@x"}]
1210+ *owners = [{email "a@x"}]
1211+ *pets = [{email "a@x"}]
12121212 yield {})"#;
12131213 let v2 = r#"with {
12141214Owner {email Text}
@@ -1269,7 +1269,7 @@ V1 {name Text}
12691269Rel V1 *people
12701270}
12711271(|
1272− full *people = [{name "a"}]
1272+ *people = [{name "a"}]
12731273 yield {})"#;
12741274 let v2 = r#"with {
12751275V1 {name Text}
@@ -1302,7 +1302,7 @@ V1 {name (Maybe Text)}
13021302Rel V1 *people
13031303}
13041304(|
1305− full *people = [{name (Maybe.Just {value "a"})} {name (Maybe.Nothing {})}]
1305+ *people = [{name (Maybe.Just {value "a"})} {name (Maybe.Nothing {})}]
13061306 yield {})"#;
13071307 let v2 = r#"with {
13081308V1 {name (Maybe Text)}
@@ -1338,7 +1338,7 @@ V1 {age (Int 1)}
13381338Rel V1 *r
13391339}
13401340(|
1341− full *r = [{age 5}]
1341+ *r = [{age 5}]
13421342 yield {})"#;
13431343 let v2 = r#"with {
13441344V1 {age (Int 1)}
@@ -1371,7 +1371,7 @@ V1 {n (Int 1)}
13711371Rel V1 *r
13721372}
13731373(|
1374− full *r = [{n 7}]
1374+ *r = [{n 7}]
13751375 yield {})"#;
13761376 let v2 = r#"with {
13771377V1 {n (Int 1)}
@@ -1405,7 +1405,7 @@ Ev Ping {} Msg {text Text}
14051405Rel Ev *evs
14061406}
14071407(|
1408− full *evs = [(Ev.Ping {}) (Ev.Msg {text "hi"})]
1408+ *evs = [(Ev.Ping {}) (Ev.Msg {text "hi"})]
14091409 yield {})"#;
14101410 let v2 = r#"with {
14111411Ev Ping {} Msg {text Text}
crates/knot-jit/tests/persistence.rs+19−19
@@ -14,7 +14,7 @@ Todo {owner Text done (Int 1)}
1414Rel Todo *todos
1515}
1616(|
17− full *todos = [{owner "x" done 0} {owner "x" done 1} {owner "y" done 0}]
17+ *todos = [{owner "x" done 0} {owner "x" done 1} {owner "y" done 0}]
1818 groups <- (|
1919 t <- *todos
2020 where t.done == 0
@@ -37,7 +37,7 @@ C {n (Int 1)}
3737Rel C *cs
3838}
3939(|
40− full *cs = [{n 1} {n 2} {n 3}]
40+ *cs = [{n 1} {n 2} {n 3}]
4141 rows <- *cs
4242 base.println (base.show (base.count rows))
4343 base.println (base.show (base.sum (base.map (\c -> c.n) rows)))
@@ -135,7 +135,7 @@ Account {name Text balance (Int 1)}
135135Rel Account *accounts
136136}
137137(|
138− full *accounts = [{name "from" balance 100} {name "to" balance 0}]
138+ *accounts = [{name "from" balance 100} {name "to" balance 0}]
139139 _ <- atomic |
140140 rows <- *accounts
141141 *accounts = base.map (\a ->
@@ -165,7 +165,7 @@ Shape Circle {radius (Int 1)} Square {side (Int 1)} Point {}
165165Rel Shape *shapes
166166}
167167(|
168− full *shapes = [Shape.Circle {radius 3} Shape.Square {side 2} Shape.Point {}]
168+ *shapes = [Shape.Circle {radius 3} Shape.Square {side 2} Shape.Point {}]
169169 rows <- *shapes
170170 base.println (base.show rows)
171171 yield {})"#,
@@ -191,7 +191,7 @@ Entry {name Text sh Shape}
191191Rel Entry *es
192192}
193193(|
194− full *es = [{name "a" sh (Shape.Circle {radius 3})} {name "b" sh (Shape.Point {})}]
194+ *es = [{name "a" sh (Shape.Circle {radius 3})} {name "b" sh (Shape.Point {})}]
195195 rows <- *es
196196 base.println (base.show rows)
197197 yield {})"#,
@@ -213,7 +213,7 @@ Entry {name Text sh Shape}
213213Rel Entry *es
214214}
215215(|
216− full *es = [{name "a" sh (Shape.Circle {radius 3})} {name "b" sh (Shape.Circle {radius 3})} {name "c" sh (Shape.Point {})}]
216+ *es = [{name "a" sh (Shape.Circle {radius 3})} {name "b" sh (Shape.Circle {radius 3})} {name "c" sh (Shape.Point {})}]
217217 yield {})"#,
218218 dir.path(),
219219 );
@@ -251,7 +251,7 @@ Entry {name Text addr {city Text zip (Int 1)}}
251251Rel Entry *es
252252}
253253(|
254− full *es = [{name "a" addr {city "paris" zip 75001}}]
254+ *es = [{name "a" addr {city "paris" zip 75001}}]
255255 yield {})"#,
256256 dir.path(),
257257 );
@@ -288,7 +288,7 @@ Entry {name Text tags (Rel Text)}
288288Rel Entry *es
289289}
290290(|
291− full *es = [{name "a" tags ["x" "y"]} {name "b" tags ["y" "z"]}]
291+ *es = [{name "a" tags ["x" "y"]} {name "b" tags ["y" "z"]}]
292292 yield {})"#,
293293 dir.path(),
294294 );
@@ -335,7 +335,7 @@ Entry {name Text sh Shape}
335335Rel Entry *es
336336}
337337(|
338− full *es = [{name "a" sh (Shape.Circle {tags [{value "x"} {value "y"}] radius 5})}]
338+ *es = [{name "a" sh (Shape.Circle {tags [{value "x"} {value "y"}] radius 5})}]
339339 rows <- *es
340340 base.println (base.show rows)
341341 yield {})"#,
@@ -354,7 +354,7 @@ Entry {name Text sh Shape}
354354Rel Entry *es
355355}
356356(|
357− full *es = [{name "a" sh (Shape.Circle {tags [{value "x"}] radius 5})}]
357+ *es = [{name "a" sh (Shape.Circle {tags [{value "x"}] radius 5})}]
358358 yield {})"#,
359359 dir.path(),
360360 );
@@ -395,7 +395,7 @@ Entry {name Text grid (Rel (Rel (Int 1)))}
395395Rel Entry *es
396396}
397397(|
398− full *es = [{name "a" grid [[1 2] [3]]}]
398+ *es = [{name "a" grid [[1 2] [3]]}]
399399 rows <- *es
400400 base.println (base.show rows)
401401 yield {})"#,
@@ -417,7 +417,7 @@ Entry {name Text sh Shape}
417417Rel Entry *es
418418}
419419(|
420− full *es = [{name "a" sh (Shape.Circle {radius 3})}]
420+ *es = [{name "a" sh (Shape.Circle {radius 3})}]
421421 yield {})"#,
422422 dir.path(),
423423 );
@@ -455,8 +455,8 @@ Entry {name Text sh Shape}
455455Rel Entry *es
456456}
457457(|
458− full *es = [{name "a" sh (Shape.Circle {radius 3})}]
459− full *es = [{name "b" sh (Shape.Point {})}]
458+ *es = [{name "a" sh (Shape.Circle {radius 3})}]
459+ *es = [{name "b" sh (Shape.Point {})}]
460460 yield {})"#,
461461 dir.path(),
462462 );
@@ -492,7 +492,7 @@ C {n (Int 1)}
492492Rel C *cs
493493}
494494(|
495− full *cs = [{n 42}]
495+ *cs = [{n 42}]
496496 yield {})"#,
497497 dir.path(),
498498 );
@@ -518,7 +518,7 @@ Rel C *cs
518518
519519/// A function value can't be persisted. A source whose element type contains a
520520/// function field must be a **compile error**, not a runtime crash: the schema
521−/// catch-all used to type it `fn:text`, then `full *rs = [{f (\n -> n)}]`
521+/// catch-all used to type it `fn:text`, then `*rs = [{f (\n -> n)}]`
522522/// aborted the process with `cannot convert Function to SQL`. Nested functions
523523/// (inside a record/variant payload) must also be rejected — they used to
524524/// serialize to a dead display string that crashed on call.
@@ -531,7 +531,7 @@ R {name Text f (Int 1 -> Int 1)}
531531Rel R *rs
532532}
533533(|
534− full *rs = [{name "x" f (\n -> n + 1)}]
534+ *rs = [{name "x" f (\n -> n + 1)}]
535535 yield {})"#;
536536 let src_path = dir.join("fnfield.knot");
537537 std::fs::write(&src_path, src).unwrap();
@@ -566,7 +566,7 @@ R {name Text f S}
566566Rel R *rs
567567}
568568(|
569− full *rs = [{name "x" f (S.Wrap {g (\n -> n)})}]
569+ *rs = [{name "x" f (S.Wrap {g (\n -> n)})}]
570570 yield {})"#;
571571 let src_path = dir.join("fnadt.knot");
572572 std::fs::write(&src_path, src).unwrap();
@@ -604,7 +604,7 @@ E {n (Int 1)}
604604Rel E *emps
605605}
606606(|
607− full *emps = [{n 9223372036854775807} {n 1}]
607+ *emps = [{n 9223372036854775807} {n 1}]
608608 base.println (base.show (*emps |> base.map (\e -> e.n) |> base.sum))
609609 yield {})"#,
610610 dir.path(),
crates/knot-jit/tests/refinements.rs+2−2
@@ -89,7 +89,7 @@ Nat Int 1 \x -> x >= 0
8989Rel {name Text age Nat} *people
9090}
9191(|
92− full *people = [{name "a" age (0 - 5)}]
92+ *people = [{name "a" age (0 - 5)}]
9393 base.println "wrote"
9494 yield {})"#,
9595 dir.path(),
@@ -116,7 +116,7 @@ Nat Int 1 \x -> x >= 0
116116Rel {name Text age Nat} *people
117117}
118118(|
119− full *people = [{name "a" age 30}]
119+ *people = [{name "a" age 30}]
120120 base.println (base.show (base.count *people))
121121 yield {})"#,
122122 // count is a one-element relation now (Rel Int), so it shows as [1].
crates/knot-jit/tests/views.rs+4−4
@@ -16,7 +16,7 @@ directReports (|
1616 yield {manager m.manager report m.report})
1717}
1818(|
19− full *manages = [{manager "A" report "B"} {manager "A" report "C"} {manager "B" report "D"}]
19+ *manages = [{manager "A" report "B"} {manager "A" report "C"} {manager "B" report "D"}]
2020 base.println (base.show (base.count directReports))
2121 yield {})"#,
2222 "\"3\"\n{}",
@@ -36,10 +36,10 @@ doubled (|
3636 yield {n (r.n * 2)})
3737}
3838(|
39− full *items = [{n 1}]
39+ *items = [{n 1}]
4040 a <- base.run [] doubled
4141 base.println (base.show a)
42− full *items = [{n 5}]
42+ *items = [{n 5}]
4343 b <- base.run [] doubled
4444 base.println (base.show b)
4545 yield {})"#,
@@ -58,7 +58,7 @@ amounts (|
5858 yield {amount r.amount})
5959}
6060(|
61− full *sales = [{region "x" amount 10} {region "y" amount 20} {region "x" amount 5}]
61+ *sales = [{region "x" amount 10} {region "y" amount 20} {region "x" amount 5}]
6262 base.println (base.show {sum (base.sum (| r <- amounts; yield r.amount))})
6363 yield {})"#,
6464 // a query field iterated in an aggregate comprehension over the source
crates/knot-lsp/src/defs.rs+1−1
@@ -485,7 +485,7 @@ impl<'a> DefResolver<'a> {
485485 }
486486 ast::ExprKind::UnaryOp { operand, .. } => self.resolve_expr(operand),
487487 ast::ExprKind::Atomic(e) => self.resolve_expr(e),
488− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
488+ ast::ExprKind::Set { target, value } => {
489489 self.resolve_expr(target);
490490 self.resolve_expr(value);
491491 }
crates/knot-lsp/src/folding.rs+1−1
@@ -130,7 +130,7 @@ fn collect_folding_ranges_expr(expr: &ast::Expr, source: &str, ranges: &mut Vec<
130130 ast::ExprKind::UnaryOp { operand, .. } => {
131131 collect_folding_ranges_expr(operand, source, ranges);
132132 }
133− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
133+ ast::ExprKind::Set { target, value } => {
134134 collect_folding_ranges_expr(target, source, ranges);
135135 collect_folding_ranges_expr(value, source, ranges);
136136 }
crates/knot-lsp/src/selection_range.rs+1−1
@@ -149,7 +149,7 @@ fn collect_containing_spans(expr: &ast::Expr, offset: usize, spans: &mut Vec<Spa
149149 ast::ExprKind::Atomic(e) | ast::ExprKind::Refine(e) => {
150150 collect_containing_spans(e, offset, spans);
151151 }
152− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
152+ ast::ExprKind::Set { target, value } => {
153153 collect_containing_spans(target, offset, spans);
154154 collect_containing_spans(value, offset, spans);
155155 }
crates/knot-lsp/src/semantic_tokens.rs+1−1
@@ -511,7 +511,7 @@ impl<'a> TokenCollector<'a> {
511511 }
512512 }
513513 ast::ExprKind::Atomic(e) | ast::ExprKind::Refine(e) => self.visit_expr(e),
514− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
514+ ast::ExprKind::Set { target, value } => {
515515 // Highlight mutation targets distinctly. We re-emit the target
516516 // span with a MUTATION modifier overlaying whatever inner type
517517 // visit_expr would assign.
crates/knot-lsp/src/utils.rs+1−2
@@ -424,7 +424,6 @@ pub fn collect_keyword_operator_positions(tokens: &[knot::lexer::Token]) -> Vec<
424424 let tok_type = match &token.kind {
425425 TokenKind::Where
426426 | TokenKind::Not
427− | TokenKind::Full
428427 | TokenKind::Atomic
429428 | TokenKind::With
430429 | TokenKind::Refine
@@ -510,7 +509,7 @@ pub fn recurse_expr<F: FnMut(&ast::Expr)>(expr: &ast::Expr, mut f: F) {
510509 }
511510 }
512511 ast::ExprKind::Atomic(e) | ast::ExprKind::Refine(e) => f(e),
513− ast::ExprKind::Set { target, value } | ast::ExprKind::FullSet { target, value } => {
512+ ast::ExprKind::Set { target, value } => {
514513 f(target);
515514 f(value);
516515 }
crates/knot/src/ast.rs−3
@@ -263,9 +263,6 @@ pub enum ExprKind {
263263 /// `*rel = expr` — update a source relation (must match an optimized pattern).
264264 Set { target: Box<Expr>, value: Box<Expr> },
265265
266− /// `full *rel = expr` — full table replacement (DELETE + INSERT).
267− FullSet { target: Box<Expr>, value: Box<Expr> },
268−
269266 /// `atomic expr` — transactional boundary.
270267 Atomic(Box<Expr>),
271268
crates/knot/src/format.rs+2−24
@@ -592,7 +592,7 @@ fn forces_multiline(e: &Expr) -> bool {
592592 ExprKind::Do(_) | ExprKind::Case { .. } => true,
593593 ExprKind::Lambda { body, .. } => forces_multiline(body),
594594 ExprKind::App { func, arg } => forces_multiline(func) || forces_multiline(arg),
595− ExprKind::Set { value, .. } | ExprKind::FullSet { value, .. } => forces_multiline(value),
595+ ExprKind::Set { value, .. } => forces_multiline(value),
596596 // A record carrying an embedded declaration — a type-first sig
597597 // (`Type name`), a source decl (`Rel T *name`), or a `type`/`data`
598598 // alias — must render as a block: inline, the declaration merges with
@@ -785,14 +785,6 @@ fn render_expr_inline(e: &Expr, parent: Prec) -> String {
785785 );
786786 paren_if(parent > Prec::Lowest, s)
787787 }
788− ExprKind::FullSet { target, value } => {
789− let s = format!(
790− "full {} = {}",
791− render_expr_inline(target, Prec::App),
792− render_expr_inline(value, Prec::Lowest)
793− );
794− paren_if(parent > Prec::Lowest, s)
795− }
796788 ExprKind::Atomic(inner) => {
797789 let s = format!("atomic {}", render_expr_inline(inner, Prec::App));
798790 paren_if(parent > Prec::Lowest, s)
@@ -1044,8 +1036,7 @@ fn annot_inner_needs_parens(e: &Expr, inline: bool) -> bool {
10441036 ExprKind::Lambda { .. }
10451037 | ExprKind::Atomic(_)
10461038 | ExprKind::Refine(_)
1047− | ExprKind::Set { .. }
1048− | ExprKind::FullSet { .. } => true,
1039+ | ExprKind::Set { .. } => true,
10491040 // Last case arm body / do statement / serve handler is also parsed
10501041 // with `parse_expr`, but the inline renderers already wrap these in
10511042 // parens unconditionally.
@@ -1129,19 +1120,6 @@ fn render_expr_block(p: &mut Printer, e: &Expr, parent: Prec) {
11291120 p.write(")");
11301121 }
11311122 }
1132− ExprKind::FullSet { target, value } => {
1133− let need_parens = parent > Prec::Lowest;
1134− if need_parens {
1135− p.write("(");
1136− }
1137− p.write("full ");
1138− render_expr(p, target, Prec::App);
1139− p.write(" = ");
1140− render_expr(p, value, Prec::Lowest);
1141− if need_parens {
1142− p.write(")");
1143− }
1144− }
11451123 ExprKind::Atomic(inner) => {
11461124 let need_parens = parent > Prec::Lowest;
11471125 if need_parens {
crates/knot/src/lexer.rs−4
@@ -22,7 +22,6 @@ pub enum TokenKind {
2222 // Keywords
2323 Where,
2424 Not,
25− Full,
2625 Atomic,
2726 With,
2827 Refine,
@@ -103,7 +102,6 @@ impl TokenKind {
103102 TokenKind::Upper(_) => "type name",
104103 TokenKind::Where => "'where'",
105104 TokenKind::Not => "'not'",
106− TokenKind::Full => "'full'",
107105 TokenKind::Atomic => "'atomic'",
108106 TokenKind::With => "'with'",
109107 TokenKind::Refine => "'refine'",
@@ -158,7 +156,6 @@ impl TokenKind {
158156 match self {
159157 TokenKind::Where => Some("where"),
160158 TokenKind::Not => Some("not"),
161− TokenKind::Full => Some("full"),
162159 TokenKind::Atomic => Some("atomic"),
163160 TokenKind::With => Some("with"),
164161 TokenKind::Refine => Some("refine"),
@@ -545,7 +542,6 @@ impl<'src> Lexer<'src> {
545542 if first.is_ascii_lowercase() || first == b'_' {
546543 match text {
547544 "where" => return TokenKind::Where,
548− "full" => return TokenKind::Full,
549545 "atomic" => return TokenKind::Atomic,
550546 "with" => return TokenKind::With,
551547 "refine" => return TokenKind::Refine,
crates/knot/src/parser.rs−91
@@ -622,7 +622,6 @@ impl Parser {
622622 Ok((n, tok.span))
623623 }
624624 TokenKind::Where
625− | TokenKind::Full
626625 | TokenKind::Atomic
627626 | TokenKind::With
628627 | TokenKind::Refine
@@ -1402,53 +1401,6 @@ impl Parser {
14021401 Some(target)
14031402 }
14041403 }
1405− TokenKind::Full => {
1406− // `full *rel = expr` is a replace-set expression. So is
1407− // `full db.*rel = expr` (a source-field on a record-var:
1408− // `Lower` `.` `StarIdent`). `full` only marks a WRITE; a bare
1409− // `*rel` read needs no marker. Otherwise `full` is a regular
1410− // identifier.
1411− let mut offset = 1;
1412− while self.peek_ahead(offset) == &TokenKind::Newline {
1413− offset += 1;
1414− }
1415− let next = self.peek_ahead(offset);
1416− // `db.*rel` — a record-var target whose field is a source.
1417− let is_record_source_target = matches!(next, TokenKind::Lower(_))
1418− && self.peek_ahead(offset + 1) == &TokenKind::Dot
1419− && matches!(self.peek_ahead(offset + 2), TokenKind::StarIdent(_));
1420− if is_record_source_target {
1421− let replace_start = self.span();
1422− self.advance(); // consume `full`
1423− self.skip_newlines();
1424− self.parse_set_with_start(true, replace_start)
1425− } else if next == &TokenKind::Star || matches!(next, TokenKind::StarIdent(_)) {
1426− // `full` before a source marks a write (`full *rel = expr`).
1427− // A read is a bare `*rel` with no `full`.
1428− let past = if matches!(next, TokenKind::StarIdent(_)) {
1429− offset + 1 // `*rel` is one token
1430− } else {
1431− offset + 2 // `*` then `rel`
1432− };
1433− let after = self.peek_ahead(past);
1434− if after == &TokenKind::Eq {
1435− // Write: `full *rel = expr`.
1436− let replace_start = self.span();
1437− self.advance(); // consume `full`
1438− self.skip_newlines();
1439− self.parse_set_with_start(true, replace_start)
1440− } else {
1441− self.error(
1442− "`full` only marks a write (`full *rel = ...`); a read is just `*rel`",
1443− );
1444− None
1445− }
1446− } else {
1447− // `full` used as a regular identifier — fall through to
1448− // Pratt parsing so binary operators and application work.
1449− self.parse_expr_bp(0)
1450− }
1451− }
14521404 TokenKind::Atomic => {
14531405 if !self.enter_recursion() {
14541406 return None;
@@ -1817,7 +1769,6 @@ impl Parser {
18171769 | TokenKind::LParen
18181770 | TokenKind::LBrace
18191771 | TokenKind::LBracket
1820− | TokenKind::Full
18211772 | TokenKind::Pipe => true,
18221773 // `yield` is not a keyword but should not start application atoms
18231774 // (like keywords), to prevent `f; yield x` from parsing as `f yield x`
@@ -2129,13 +2080,6 @@ impl Parser {
21292080 };
21302081 Some(Spanned::new(ExprKind::Constructor(name), tok.span))
21312082 }
2132− TokenKind::Full => {
2133− let tok = self.advance();
2134− Some(Spanned::new(
2135− ExprKind::Var(Binding::User("full".into())),
2136− tok.span,
2137− ))
2138− }
21392083 TokenKind::StarIdent(_) => {
21402084 // `*name` lexed as a single token — source reference.
21412085 let tok = self.advance();
@@ -3254,41 +3198,6 @@ impl Parser {
32543198 })
32553199 }
32563200
3257− fn parse_set_with_start(&mut self, replace: bool, start: Span) -> Option<Expr> {
3258− let ctx = if replace {
3259− "replace set expression"
3260− } else {
3261− "set expression"
3262− };
3263− self.in_context(ctx, |this| {
3264− // The caller has already positioned the parser at the target. A
3265− // set/replace target is a field-access chain (`*rel`, `x`,
3266− // `rec.field`, or `db.*rel` on a source-record) — never an
3267− // application or binary op — so parse it with `parse_postfix`,
3268− // which handles the `.`-chain including the `*name` source-field
3269− // form. (`parse_expr_bp` would stop at `db` and leave `.*todos`
3270− // dangling.)
3271− let target = this.parse_postfix()?;
3272−
3273− this.expect(&TokenKind::Eq, "expected '=' after target")
3274− .ok()?;
3275− let value = this.parse_expr()?;
3276−
3277− let end_sp = value.span;
3278− let kind = if replace {
3279− ExprKind::FullSet {
3280− target: Box::new(target),
3281− value: Box::new(value),
3282− }
3283− } else {
3284− ExprKind::Set {
3285− target: Box::new(target),
3286− value: Box::new(value),
3287− }
3288− };
3289− Some(Spanned::new(kind, Span::new(start.start, end_sp.end)))
3290− })
3291− }
32923201
32933202 /// `with record body` — `record` is an atom (record literal, variable, or
32943203 /// parenthesized expression, optionally with field-access chains); `body`
examples/arith_aggregate.knot+1−1
@@ -17,7 +17,7 @@ avgDemo (|
1717}
1818
1919do
20− full *lines = [{product "widget" price 5 qty 2} {product "gadget" price 9 qty 1} {product "gizmo" price 5 qty 3}]
20+ *lines = [{product "widget" price 5 qty 2} {product "gadget" price 9 qty 1} {product "gizmo" price 5 qty 3}]
2121 totalDemo
2222 avgDemo
2323 yield {}
examples/constraints.knot+2−2
@@ -13,10 +13,10 @@ Rel {customer Text amount (Int 1)} *orders
1313}
1414(|
1515 -- Insert some people
16− full *people = [{ name "Alice" age 30 email "alice@example.com" } { name "Bob" age 25 email "bob@example.com" }]
16+ *people = [{ name "Alice" age 30 email "alice@example.com" } { name "Bob" age 25 email "bob@example.com" }]
1717
1818 -- Insert a valid order (Alice exists in people)
19− full *orders = [{ customer "Alice" amount 100 }]
19+ *orders = [{ customer "Alice" amount 100 }]
2020
2121 -- Print current state
2222 base.println "People:"
examples/fold_stream.knot+1−1
@@ -4,7 +4,7 @@ Sale {item Text qty (Int 1) price (Int 1)}
44Rel Sale *sales
55}
66(|
7− full *sales = [
7+ *sales = [
88 { item "apple" qty 3 price 50 }
99 { item "banana" qty 7 price 20 }
1010 { item "cherry" qty 2 price 120 }
examples/groupby.knot+1−1
@@ -4,7 +4,7 @@ Todo {title Text owner Text done (Int 1)}
44Rel Todo *todos
55}
66(|
7− full *todos = [
7+ *todos = [
88 { title "Write parser" owner "Alice" done 0 }
99 { title "Write codegen" owner "Alice" done 0 }
1010 { title "Write runtime" owner "Bob" done 0 }
examples/hello.knot+1−1
@@ -4,7 +4,7 @@ Person {name Text age (Int 1)}
44Rel Person *people
55}
66(|
7− full *people = [{name "Alice" age 30} {name "Bob" age 25} {name "Carol" age 35}]
7+ *people = [{name "Alice" age 30} {name "Bob" age 25} {name "Carol" age 35}]
88 p <- *people
99 where p.age > 27
1010 yield p.name)
examples/inline_pushdown.knot+1−1
@@ -35,7 +35,7 @@ case5 (|
3535 yield (base.countWhere (\e -> isHighEarner e) emps))
3636}
3737(|
38− full *employees = [
38+ *employees = [
3939 {name "Alice" dept "Eng" salary 90}
4040 {name "Bob" dept "Eng" salary 80}
4141 {name "Carol" dept "Sales" salary 70}
examples/let_pushdown.knot+1−1
@@ -26,7 +26,7 @@ pruneDemo (|
2626 with {kept (| i <- items; where i.price > 0; yield i)} *items = kept)
2727}
2828(|
29− full *items = [{name "Alice" price 10} {name "Bob" price 25}]
29+ *items = [{name "Alice" price 10} {name "Bob" price 25}]
3030 appendDemo
3131 rows1 <- *items
3232 base.println ("after append: " ++ base.show rows1)
examples/migrate.knot+1−1
@@ -29,6 +29,6 @@ Rel Person *people
2929
3030}
3131(|
32− full *people = [{name "Alice" active (Active.Yes {})} {name "Bob" active (Active.No {})}]
32+ *people = [{name "Alice" active (Active.Yes {})} {name "Bob" active (Active.No {})}]
3333 rows <- *people
3434 base.println (base.show rows))
examples/nested.knot+1−1
@@ -6,7 +6,7 @@ Person {name Text age (Int 1)}
66Rel {name Text members (Rel Person)} *teams
77}
88(|
9− full *teams = [
9+ *teams = [
1010 { name "Engineering" members [{ name "Alice" age 30 } { name "Bob" age 25 } { name "Eve" age 22 }] }
1111 { name "Design" members [{ name "Carol" age 35 } { name "Eve" age 22 }] }
1212 ]
examples/query_opt.knot+2−2
@@ -90,14 +90,14 @@ pipeCountWhere (|
9090 yield (employees |> base.countWhere (\e -> e.dept == "Sales")))
9191}
9292(|
93− full *employees = [
93+ *employees = [
9494 {name "Alice" dept "Eng" salary 90}
9595 {name "Bob" dept "Eng" salary 80}
9696 {name "Carol" dept "Sales" salary 70}
9797 {name "Dave" dept "Sales" salary 60}
9898 {name "Eve" dept "Eng" salary 100}
9999 ]
100− full *departments = [{name "Eng" budget 500} {name "Sales" budget 200}]
100+ *departments = [{name "Eng" budget 500} {name "Sales" budget 200}]
101101 countDemo
102102 filterDemo
103103 joinDemo
examples/recursive.knot+1−1
@@ -8,7 +8,7 @@ directReports (|
88 yield {manager m.manager report m.report})
99}
1010(|
11− full *manages = [
11+ *manages = [
1212 {manager "Alice" report "Bob"}
1313 {manager "Alice" report "Carol"}
1414 {manager "Bob" report "Dave"}
examples/showcase.knot+9−9
@@ -52,7 +52,7 @@ Rel Metric *metrics
5252-- ── Seed data ────────────────────────────────────────────────────
5353
5454seedEmployees (|
55− full *employees = [
55+ *employees = [
5656 {name "Alice Chen" age 34 salary 142000.0 dept (Department.Engineering {}) active (Active.Yes {})}
5757 {name "Bob Martinez" age 28 salary 95000.0 dept (Department.Engineering {}) active (Active.Yes {})}
5858 {name "Carol Davis" age 41 salary 155000.0 dept (Department.Engineering {}) active (Active.Yes {})}
@@ -77,7 +77,7 @@ seedEmployees (|
7777 yield {})
7878
7979seedProjects (|
80− full *projects = [
80+ *projects = [
8181 {name "Phoenix" lead "Alice Chen" budget 500000.0 priority (Priority.Critical {})}
8282 {name "Atlas" lead "Carol Davis" budget 350000.0 priority (Priority.High {})}
8383 {name "Meridian" lead "Frank Lee" budget 200000.0 priority (Priority.Medium {})}
@@ -90,7 +90,7 @@ seedProjects (|
9090 yield {})
9191
9292seedTickets (|
93− full *tickets = [
93+ *tickets = [
9494 {
9595 title "Fix auth timeout"
9696 project "Phoenix"
@@ -186,7 +186,7 @@ seedTickets (|
186186 yield {})
187187
188188seedCustomers (|
189− full *customers = [
189+ *customers = [
190190 {name "Acme Corp" email "admin@acme.com" tier (Tier.Enterprise {})}
191191 {name "Widgets Inc" email "hello@widgets.io" tier (Tier.Pro {})}
192192 {name "Startup Labs" email "team@startuplabs.dev" tier (Tier.Free {})}
@@ -203,7 +203,7 @@ seedCustomers (|
203203 yield {})
204204
205205seedProducts (|
206− full *products = [
206+ *products = [
207207 {name "Laptop Pro 16" price 2499.99 category (Category.Electronics {}) inStock (Active.Yes {})}
208208 {name "Wireless Mouse" price 49.99 category (Category.Electronics {}) inStock (Active.Yes {})}
209209 {name "USB-C Hub" price 79.99 category (Category.Electronics {}) inStock (Active.No {})}
@@ -223,7 +223,7 @@ seedProducts (|
223223 yield {})
224224
225225seedOrders (|
226− full *orders = [
226+ *orders = [
227227 {customer "Acme Corp" product "Laptop Pro 16" quantity 50 total 124999.5}
228228 {customer "Acme Corp" product "4K Monitor" quantity 50 total 29999.5}
229229 {customer "Acme Corp" product "IDE License" quantity 100 total 19999.0}
@@ -253,7 +253,7 @@ seedOrders (|
253253 yield {})
254254
255255seedTeams (|
256− full *teams = [
256+ *teams = [
257257 {
258258 name "Platform"
259259 members [
@@ -297,7 +297,7 @@ seedTeams (|
297297 yield {})
298298
299299seedLogs (|
300− full *logs = [
300+ *logs = [
301301 {timestamp 1710900000 level (Level.Info {}) message "Server started on port 8080" source "main"}
302302 {
303303 timestamp 1710900001
@@ -407,7 +407,7 @@ seedLogs (|
407407 yield {})
408408
409409seedMetrics (|
410− full *metrics = [
410+ *metrics = [
411411 {name "http_requests_total" value 48291.0 tags "method=GET,status=200"}
412412 {name "http_requests_total" value 12847.0 tags "method=POST,status=201"}
413413 {name "http_requests_total" value 342.0 tags "method=POST,status=400"}
examples/stm_row_filter.knot+1−1
@@ -26,7 +26,7 @@ _ credit (\aid amount -> atomic |
2626 (*accounts = setBalance aid amount rows))
2727}
2828(|
29− full *accounts = [{id 1 balance 0} {id 2 balance 0} {id 3 balance 0}]
29+ *accounts = [{id 1 balance 0} {id 2 balance 0} {id 3 balance 0}]
3030 credit 1 100
3131 credit 2 50
3232 credit 3 25