Skip to content

Let a boxed value reach a native-only multi candidate by unboxing - #6569

Draft
ugexe wants to merge 1 commit into
rakudo:mainfrom
ugexe:ugexe/multi-dispatch-native-unbox-fallback
Draft

ugexe wants to merge 1 commit into
rakudo:mainfrom
ugexe:ugexe/multi-dispatch-native-unbox-fallback

Conversation

@ugexe

@ugexe ugexe commented Aug 16, 2026

Copy link
Copy Markdown
Member

The multi dispatch candidate filter requires a native value or a native container for a natively typed parameter. The binder is less strict. It unboxes a boxed value into the same parameter for a non-multi routine and for a named parameter. A call such as bar("f") against a lone (str $s) candidate could therefore only dispatch when the optimizer settled the call at compile time and skipped the filter. Whether that happened depended on the candidate body being inlinable and on the shape of the call site. The same call worked at the top level and failed inside a loop body. It always failed for method multis and at lower optimization levels. "Give a paired literal its native representation" then made a lone literal dispatch as the boxed value it is, so such a call failed everywhere. Failing consistently still leaves the multi form rejecting a value the equivalent sub form binds.

The dispatcher now sets aside a candidate whose only obstacle is a native parameter facing a concrete value of the native box type. When no candidate is in the running otherwise, those candidates are tried in order with a bind check deciding each. Within a tied group that order is the candidate order, as it is for constrained candidates on the normal path. A dispatch that resolves today keeps its candidate. The retry only exists on calls that otherwise fail, carries its bind check at run time, and is never settled at compile time. A parameter marked rw stays native container only. A boxed integer against an int and Int pair keeps choosing Int, and a native container keeps choosing the native candidate. find_best_dispatchee applies the same rule with the same gating, including the named argument admission the dispatch plan applies. A trial bind that throws counts as not bindable there instead of leaking a VM error out of introspection.

The compile time analysis judges an object argument against a native parameter by the same relation. A Str argument to a lone int candidate is still refused at compile time. An Int argument to a lone uint candidate no longer is. Both frontends judge a multi with the reading the call site passes and keep the native reading of a lone literal for the proto trial bind.

The multi dispatch candidate filter requires a native value or a
native container for a natively typed parameter. The binder is less
strict. It unboxes a boxed value into the same parameter for a
non-multi routine and for a named parameter. A call such as bar("f")
against a lone (str $s) candidate could therefore only dispatch when
the optimizer settled the call at compile time and skipped the
filter. Whether that happened depended on the candidate body being
inlinable and on the shape of the call site. The same call worked at
the top level and failed inside a loop body. It always failed for
method multis and at lower optimization levels. "Give a paired
literal its native representation" then made a lone literal dispatch
as the boxed value it is, so such a call failed everywhere. Failing
consistently still leaves the multi form rejecting a value the
equivalent sub form binds.

The dispatcher now sets aside a candidate whose only obstacle is a
native parameter facing a concrete value of the native box type.
When no candidate is in the running otherwise, those candidates are
tried in order with a bind check deciding each. Within a tied group
that order is the candidate order, as it is for constrained
candidates on the normal path. A dispatch that resolves today keeps
its candidate. The retry only exists on calls that otherwise fail,
carries its bind check at run time, and is never settled at compile
time. A parameter marked rw stays native container only. A boxed
integer against an int and Int pair keeps choosing Int, and a native
container keeps choosing the native candidate. find_best_dispatchee
applies the same rule with the same gating, including the named
argument admission the dispatch plan applies. A trial bind that
throws counts as not bindable there instead of leaking a VM error
out of introspection.

The compile time analysis judges an object argument against a native
parameter by the same relation. A Str argument to a lone int
candidate is still refused at compile time. An Int argument to a
lone uint candidate no longer is. Both frontends judge a multi with
the reading the call site passes and keep the native reading of a
lone literal for the proto trial bind.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant