Skip to content

Commit

Permalink
Streamline return value handling some more
Browse files Browse the repository at this point in the history
Extract the handling of generic types to a new dispatcher
"raku-rv-typecheck-generic", which puts a guard on the type
and then delegates to "raku-rv-typecheck".

Adapt "raku-rv-typecheck" not need to guard on type anymore.

Removes the need for the additional "is_generic" argument to
"raku-rv-typecheck", which saves a few bytes on each callsite.

Document the "raku-rv-typecheck" and "raku-rv-typecheck-generic"
dispatchers.
  • Loading branch information
lizmat committed Feb 8, 2024
1 parent ccbe370 commit 07049e7
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 22 deletions.
14 changes: 14 additions & 0 deletions docs/dispatchers.md
Original file line number Diff line number Diff line change
Expand Up @@ -558,7 +558,21 @@ implies that any `Proxy` object will **not** be decontainerized. This was
an error in the 6.c implementation on which some modules in the ecosystem
depend.

### raku-rv-typecheck-generic
```
nqp::dispatch("raku-rv-typecheck", $value, $generic-type);
```
Returns the given $value if the typecheck with the **generic** type-value
is successful: assumes the actual type value can vary due to its
genericness. Otherwise throw an error.

### raku-rv-typecheck
```
nqp::dispatch("raku-rv-typecheck", $value, $type);
```
Returns the given $value if the typecheck with the type-value is successful
assuming the type at the call-site is a constant. Otherwise throw an error.

### raku-sink
```
nqp::dispatch("raku-sink", $value);
Expand Down
21 changes: 12 additions & 9 deletions src/vm/moar/Perl6/Ops.nqp
Original file line number Diff line number Diff line change
Expand Up @@ -416,19 +416,22 @@ $ops.add_hll_op('Raku', 'p6typecheckrv', -> $qastcomp, $op {
elsif nqp::objprimspec(nqp::decont($type)) {
$qastcomp.as_mast($value)
}
elsif $type.HOW.archetypes($type).generic {
$qastcomp.as_mast(QAST::Op.new(:op<dispatch>,
QAST::SVal.new( :value('raku-rv-typecheck-generic') ),
QAST::Op.new( :op('p6box'), $value ),
QAST::Op.new(:op<callmethod>, :name<instantiate_generic>,
QAST::Op.new(:op<how>, QAST::WVal.new(:value($type))),
QAST::WVal.new(:value($type)),
QAST::Op.new(:op<curlexpad>)
)
));
}
else {
my $is_generic := $type.HOW.archetypes($type).generic;
$qastcomp.as_mast(QAST::Op.new(:op<dispatch>,
QAST::SVal.new( :value('raku-rv-typecheck') ),
QAST::Op.new( :op('p6box'), $value ),
$is_generic
?? QAST::Op.new(:op<callmethod>, :name<instantiate_generic>,
QAST::Op.new(:op<how>, QAST::WVal.new(:value($type))),
QAST::WVal.new(:value($type)),
QAST::Op.new(:op<curlexpad>)
)
!! QAST::WVal.new(:value($type)),
QAST::IVal.new(:value($is_generic))
QAST::WVal.new(:value($type))
));
}
}
Expand Down
25 changes: 12 additions & 13 deletions src/vm/moar/dispatchers.nqp
Original file line number Diff line number Diff line change
Expand Up @@ -4413,6 +4413,15 @@ nqp::register('raku-coercion', -> $capture {
}
});

#- raku-rv-typecheck-generic ---------------------------------------------------
# Return value type-check dispatcher for instantiated generic types. The
# first value is the return value, the second is the type that is expected,
# which may be a definiteness or coercion type.
nqp::register('raku-rv-typecheck-generic', -> $capture {
nqp::guard('type', nqp::track('arg', $capture, 1));
nqp::delegate('raku-rv-typecheck', $capture);
});

#- raku-rv-typecheck -----------------------------------------------------------
# Typechecking return values

Expand Down Expand Up @@ -4492,8 +4501,8 @@ my $check_type_coerce := -> $ret, $type, $coercion, @cdesc {

# Return value type-check dispatcher. The first value is the return value,
# the second is the type that is expected, which may be a definiteness or
# coercion type. The third argument is a native integer flag indicating
# whether type is generic or not.
# coercion type. The type is supposed to be guarded already if it is an
# instantiated generic type.
nqp::register('raku-rv-typecheck', -> $capture {

# Preset most common case, which will return identity
Expand All @@ -4504,7 +4513,7 @@ nqp::register('raku-rv-typecheck', -> $capture {
my $Tvalue := nqp::track( 'arg', $capture, 0);
if nqp::istype($rv, Nil)
&& (!nqp::iscont($rv) || nqp::istype_nd($rv,Scalar)) {
nqp::guard('type', nqp::iscont($rv)
nqp::guard('type', nqp::istype_nd($rv,Scalar)
?? nqp::track('attr', $Tvalue, Scalar, '$!value')
!! $Tvalue
);
Expand All @@ -4526,16 +4535,6 @@ nqp::register('raku-rv-typecheck', -> $capture {
)
}

# If the type has been instantiated from a generic then we'd need to
# track over it too.
nqp::guard('type', nqp::track('arg', $capture, 1))
if nqp::captureposarg_i($capture, 2);

# We will never need the $is_generic argument, but otherwise the
# capture is used to call checker subs where the third argument is
# not anticipated.
$capture := nqp::syscall('dispatcher-drop-arg', $capture, 2);

# Make sure we guard on on the value and concreteness, even if
# inside a container
if nqp::istype_nd($rv, Scalar) {
Expand Down

0 comments on commit 07049e7

Please sign in to comment.