{"atom":"regression/currying-and-signature-render","family":"regression","slug":"currying-and-signature-render","header":{"atom":"regression/currying-and-signature-render","kind":"whole-program — a minimal repro, not yet reduced to an atom","source":"curated"},"axes":null,"cols":null,"engines":["rakudo-2026.07","rakupp-3.14.0"],"kinds":["ref","pp"],"defFrom":"rakupp:t/regression/currying-and-signature-render.raku","counts":{"a":1,"f":0,"d":0,"c":0,"r":0,"n":0},"files":["atoms/regression/currying-and-signature-render.grid"],"records":[["0001","","# Regression: signature rendering + `.assuming` priming (S06-currying).\n#   1. Signature.raku is `:(…)`; .gist/.Str are the bare parens.\n#   2. named params render with their `:` (`:$a`, `:key($var)`, nested\n#      `:b(:c($a))`), required nameds keep `!`, slurpies keep `*`/`**`/`+`,\n#      captures render `|c`, and defaults render (literals fold, thunks are\n#      `Code.new`).\n#   3. priming a NAMED param leaves it in the residual signature, optional,\n#      defaulting to the primed value; priming a POSITIONAL removes it.\n#   4. `*` in a priming is a hole the call's next positional fills.\n#   5. a capture param does not CONSUME its args — two captures see the same list.\n# Contract: exit 0 + last line PASS.\nmy @fail;\nsub check($got, $want, $what) { @fail.push(\"$what: got $got want $want\") unless $got eq $want }\n\n# 1-2. rendering\ncheck(sub (:$a) {}.signature.raku,   ':(:$a)',            'named');\ncheck(sub (:$a) {}.signature.gist,   '(:$a)',             'named-gist');\ncheck(sub (:$a!) {}.signature.raku,  ':(:$a!)',           'named-required');\ncheck(sub (:a($x)) {}.signature.raku, ':(:a($x))',        'named-alias');\ncheck(sub (:b(:c($a))!) {}.signature.raku, ':(:b(:c($a))!)', 'nested-alias');\ncheck(sub (*@r) {}.signature.raku,   ':(*@r)',            'slurpy-flat');\ncheck(sub (**@r) {}.signature.raku,  ':(**@r)',           'slurpy-noflat');\ncheck(sub (+@r) {}.signature.raku,   ':(+@r)',            'slurpy-one');\ncheck(sub (*%h) {}.signature.raku,   ':(*%h)',            'slurpy-named');\ncheck(sub (|c) {}.signature.raku,    ':(|c)',             'capture');\ncheck(sub ($x = 42) {}.signature.raku, ':($x = 42)',      'default-int');\ncheck(sub ($x = 'q') {}.signature.raku, ':($x = \"q\")',    'default-str');\ncheck(sub ($x = -1) {}.signature.raku, ':($x = Code.new)', 'default-thunk');\ncheck(sub (Int:D $x) {}.signature.raku, ':(Int:D $x)',    'smiley');\ncheck(sub ($a, $b?, *@c, :$d, :$e!) {}.signature.raku, ':($a, $b?, *@c, :$d, :$e!)', 'mixed');\ncheck(sub ($, @, %) {}.signature.raku, ':($, @, %)',      'anon');\n\n# 3. residual signature after priming\ncheck(sub (:$a) {}.assuming(:a).signature.raku,       ':(:$a = Bool::True)', 'prime-named');\ncheck(sub (:$a!) {}.assuming(:a).signature.raku,      ':(:$a = Bool::True)', 'prime-required-named');\ncheck(sub (:$a, :$b) {}.assuming(:b).signature.raku,  ':(:$a, :$b = Bool::True)', 'prime-one-named');\ncheck(sub ($a, $b, :$c) {}.assuming(1).signature.raku, ':($b, :$c)',        'prime-positional');\ncheck(sub (:b($a)!) {}.assuming(:b).signature.raku,   ':(:b($a) = Bool::True)', 'prime-alias');\ncheck(sub (:b(:c($a))!) {}.assuming(:c).signature.raku, ':(:b(:c($a)) = Bool::True)', 'prime-inner-alias');\n\n# 4. `*` is a hole, not a value\nsub two($a, $b) { \"$a|$b\" }\ncheck(&two.assuming(*, 2).signature.raku, ':($a)', 'hole-sig');\ncheck(&two.assuming(*, 2)(1), '1|2',              'hole-call');\ncheck(&two.assuming(1)(2),    '1|2',              'plain-prime-call');\nsub three($a, $b, $c) { \"$a|$b|$c\" }\ncheck(&three.assuming(1, *, 3).signature.raku, ':($b)', 'hole-mid-sig');\ncheck(&three.assuming(1, *, 3)(2), '1|2|3',              'hole-mid-call');\n\n# the caller's named wins over the primed one\nsub named3(:$a = '', :$b = '', :$c = '') { \"a$a b$b c$c\" }\ncheck(&named3.assuming(b => 'x')(a => 'w', c => 'y'), 'aw bx cy', 'prime-named-call');\ncheck(&named3.assuming(b => 'x')(b => 'z'), 'a bz c', 'named-override');\n\n# 5. captures don't consume\nsub capcap (|c ($a, $b?), |d ($p, $q?)) { \"a$a b$b c$p d$q\" }\ncheck(capcap('a', 'b'), 'aa bb ca db', 'two-captures');\ncheck(&capcap.assuming('a')('b'), 'aa bb ca db', 'two-captures-primed');\n\n# 6. a priming whose args can't bind throws AT `.assuming`, not at call time\nsub thrown(&code) { my $e; try { code(); CATCH { default { $_.defined; $e = $_ } } }; $e }\nmy $e1 = thrown({ sub (:$a) { }.assuming(:nosuch) });\n@fail.push('unexpected-named-not-thrown') unless $e1 ~~ X::AdHoc && $e1.payload ~~ /Unexpected/;\nmy $e2 = thrown({ sub (Str $a) { }.assuming(1) });\n@fail.push('typecheck-not-thrown') unless $e2 ~~ X::TypeCheck::Binding\n    && $e2.expected =:= Str && $e2.symbol eq '$a';\nmy $e3 = thrown({ sub ($a) { }.assuming(1, 2) });\n@fail.push('too-many-not-thrown') unless $e3 ~~ X::AdHoc && $e3.payload ~~ /'Too many positionals'/;\n@fail.push('good-prime-threw') if thrown({ sub ($a, $b) { }.assuming(1) }).defined;\n\n# the roast helper turns that throw back into a mixed-in Failure — `.can` has to\n# see a mixin's methods for it to work\nmy $mixed = Any but Failure.new(X::AdHoc.new(payload => 'nope'));\n@fail.push('can-misses-mixin') unless $mixed.can('Failure');\ncheck($mixed.Failure.exception.payload, 'nope', 'mixin-failure-payload');\n\n# 7. `die \"msg\"` — X::AdHoc.payload IS the message\ntry { die 'boom' }\ncheck($!.payload, 'boom', 'adhoc-payload');\n\n# 8. parameter binding is not assignment: an itemized Array binds to an `@`\n#    param as the Positional it is\nsub takes-array(@x) { @x.raku }\nmy @m = [[1, 2], [3, 4]];\ncheck(takes-array(@m[0]), '[1, 2]', 'itemized-elem-binds-flat');\ncheck(takes-array($[1, 2]), '[1, 2]', 'itemized-literal-binds-flat');\ncheck(takes-array([1, 2]), '[1, 2]', 'plain-array-binds-flat');\nmy @assigned = $[1, 2];\ncheck(@assigned.raku, '[[1, 2],]', 'assignment-still-nests');\n\nif @fail { note \"FAILED: @fail.join('; ')\"; say 'FAIL' } else { say 'PASS' }","output PASS","a",["PASS","PASS"],0,[["budget","20s"]]]]}