? operator only guards the head of an access chain; nested required access never errors #19
Labels
No labels
automated-🤖
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Hemera/nomo#19
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The README contract says: "Per default, trying to access a value that is not defined will cause an error. This can be changed with the
?operator." and for{{= user?.profile.description? }}: "This will give an error ifuser.profileis not defined."That contract only holds for the first identifier of a chain. Object-key lookups (
IndexSlotToSlot,src/eval/mod.rs:291) never fail — a missing key silently becomesUndefinedand renders as empty string,?or not.Verified behaviour:
{{= user.profile }}with context{ "user": {} }→ renders"", no error, even though there is no?.{{= user?.profile.description? }}withuserpresent butprofilemissing → renders"". Per the README this must be an error ("if there is a user, it must have a profile value").Root cause:
FailIfUndefined(src/eval/mod.rs:117) is never emitted. The only emit site (src/compiler/mod.rs:621) is inside anAccessOperationarm ofinner_access_opthat the parser never constructs (a./?infix rhs is always a plain operand, never anAccessOperation), so it is dead code.?beyond the first dot is effectively a no-op for enforcement.Minimal fix: in
inner_access_op, theVariableAccessarm (src/compiler/mod.rs:591-598) should emitFailIfUndefinedafter itsIndexSlotToSlot. This yields the documented semantics:a.b,a?.b,a.b.call error on a missing key;a?.bonly skips whenaitself is missing.