From e9a0b18c6cf14900aab77334bd58b9d26923d97d Mon Sep 17 00:00:00 2001 From: Vadim Belman Date: Mon, 27 Sep 2021 22:42:59 -0400 Subject: [PATCH 1/5] Don't make signature part of a callable named parameter When a named parameter is declared as `:&foo:(Int)` the name used for parameter binding was `foo:(Int)` resulting in falling back to parameter's default - `Callable`. A visible effect of this error was parameter checking to attempt calling `signature` method on `Callable` role. --- src/Perl6/Actions.nqp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Perl6/Actions.nqp b/src/Perl6/Actions.nqp index 05f375c742b..1212dc06687 100644 --- a/src/Perl6/Actions.nqp +++ b/src/Perl6/Actions.nqp @@ -5582,7 +5582,7 @@ class Perl6::Actions is HLL::Actions does STDActions { # Set name, if there is one. if $ { %*PARAM_INFO := ~$; - %*PARAM_INFO := ~$; + %*PARAM_INFO := ~($ // $); } %*PARAM_INFO := my $sigil := ~$; @@ -5759,7 +5759,10 @@ class Perl6::Actions is HLL::Actions does STDActions { method named_param($/) { %*PARAM_INFO := %*PARAM_INFO || nqp::list_s(); if $ { nqp::push_s(%*PARAM_INFO, ~$); } - elsif $ { nqp::push_s(%*PARAM_INFO, ~$); } + elsif $ { + my $name := $; + nqp::push_s(%*PARAM_INFO, ~($name // $name)); + } else { nqp::push_s(%*PARAM_INFO, ''); } } From 9c2cc9c2dd8ba930bfcf2784dd3fe41e870565ce Mon Sep 17 00:00:00 2001 From: Vadim Belman Date: Wed, 29 Sep 2021 22:51:54 -0400 Subject: [PATCH 2/5] Re-implement signature constraint support for parameters A major change this commit introduces is relocation of signature object from inside a `where` block into an attribute of `Parameter::SignatureConstraint` role which is mixed into `Parameter` when necessary. Correspondingly, constraint is now checked as part of signature binding when and only when the signature is used in parameter declaration. This commit also introduces support for generic signature constraints. I.e.: sub foo(::T, :&fn:(T)) {...} now works as expected. 1 TODO in t/spec/S03-smartmatch/signature-signature.t is unlocked, but t/spec/S06-signature/closure-parameters.t is broken. --- src/Perl6/Actions.nqp | 110 +++++++++++++++++++++------- src/Perl6/World.nqp | 5 ++ src/Perl6/bootstrap.c/BOOTSTRAP.nqp | 40 +++++++++- src/core.c/Exception.pm6 | 10 ++- src/core.c/Parameter.pm6 | 7 ++ 5 files changed, 144 insertions(+), 28 deletions(-) diff --git a/src/Perl6/Actions.nqp b/src/Perl6/Actions.nqp index 1212dc06687..7cc01aab125 100644 --- a/src/Perl6/Actions.nqp +++ b/src/Perl6/Actions.nqp @@ -5693,19 +5693,7 @@ class Perl6::Actions is HLL::Actions does STDActions { } if $ || $ -> $sig { - unless %*PARAM_INFO { - %*PARAM_INFO := []; - } - my $get_signature_past := QAST::Op.new( - :op('callmethod'), - :name('signature'), - WANTED(QAST::Var.new( :name('$_'), :scope('lexical') ),'param_var') - ); - my $fakesig := $sig; - my $closure_signature := $fakesig.ast; - - my $where := make_where_block($fakesig, $closure_signature, $get_signature_past); - %*PARAM_INFO.push($where); + %*PARAM_INFO := $sig.ast.value; } if $ { @@ -5759,7 +5747,7 @@ class Perl6::Actions is HLL::Actions does STDActions { method named_param($/) { %*PARAM_INFO := %*PARAM_INFO || nqp::list_s(); if $ { nqp::push_s(%*PARAM_INFO, ~$); } - elsif $ { + elsif $ { my $name := $; nqp::push_s(%*PARAM_INFO, ~($name // $name)); } @@ -9430,29 +9418,35 @@ class Perl6::Actions is HLL::Actions does STDActions { } } - # Handle coercion. - # For a generic we can't know beforehand if it's going to be a coercive or any other nominalizable. Thus - # we have to fetch the instantiated parameter object and do run-time processing. - if $ptype_archetypes.generic { - # For a generic-typed parameter get its instantiated clone and see if its type is a coercion. - $decont_name_invalid := 1; - my $inst_param := QAST::Node.unique('__lowered_param_obj_'); - my $low_param_type := QAST::Node.unique('__lowered_param_type'); + my $inst_param; + # Make sure we have (possibly instantiated) parameter object ready when we need it + if $is_generic || %info { + my $inst_param_name := QAST::Node.unique('__lowered_param_obj_'); $var.push( # Fetch instantiated Parameter object QAST::Op.new( :op('bind'), - QAST::Var.new( :name($inst_param), :scope('local'), :decl('var') ), + QAST::Var.new( :name($inst_param_name), :scope('local'), :decl('var') ), QAST::Op.new( :op('atpos'), signature_params($var), QAST::IVal.new(:value($i))))); + $inst_param := QAST::Var.new(:name($inst_param_name), :scope); + } + + # Handle coercion. + # For a generic we can't know beforehand if it's going to be a coercive or any other nominalizable. Thus + # we have to fetch the instantiated parameter object and do run-time processing. + if $is_generic { + # For a generic-typed parameter get its instantiated clone and see if its type is a coercion. + $decont_name_invalid := 1; + my $low_param_type := QAST::Node.unique('__lowered_param_type'); $var.push( # Get actual parameter type QAST::Op.new( :op('bind'), QAST::Var.new(:name($low_param_type), :scope('local'), :decl('var')), QAST::Op.new( :op('getattr'), - QAST::Var.new(:name($inst_param), :scope('local')), + $inst_param, QAST::WVal.new(:value($Param)), QAST::SVal.new(:value('$!type'))))); $var.push( @@ -9469,7 +9463,7 @@ class Perl6::Actions is HLL::Actions does STDActions { :op('bitand_i'), QAST::Op.new( :op('getattr'), - QAST::Var.new(:name($inst_param), :scope('local')), + $inst_param, QAST::WVal.new(:value($Param)), QAST::SVal.new(:value('$!flags')) ), @@ -9716,6 +9710,72 @@ class Perl6::Actions is HLL::Actions does STDActions { } } + if %info { + my $var-qast := QAST::Var.new( :name($name), :scope('local') ); + my $var-decont := get_decont_name() + ?? QAST::Var.new( :name(get_decont_name()), :scope('local') ) + !! QAST::Op.new( :op('decont'), $var-qast ); + my $sigc_name := QAST::Node.unique('__lowered_sig_constraint_'); + my $sigc-var := QAST::Var.new( :name($sigc_name), :scope); + my $sigc-qast; + # Produce different code for generic/non-generic signatures because in the latter case instantiation + # code would be a waste of memory and performance. + if %info.is_generic { + $sigc-qast := QAST::Op.new( + :op, + QAST::Op.new( + :op, + :name, + QAST::Op.new( + :op, + QAST::Var.new( :name($sigc_name), :scope, :decl), + QAST::Op.new( + :op, + $inst_param, + QAST::Op.new(:op, $inst_param), + QAST::SVal.new(:value('$!signature-constraint'))))), + QAST::Op.new( + :op, + :name, + $sigc-var, + QAST::Op.new( + :op, + QAST::Op.new(:op))), + $sigc-var ); + } + else { + $sigc-qast := QAST::Op.new( + :op, + $inst_param, + QAST::Op.new(:op, $inst_param), + QAST::SVal.new(:value('$!signature-constraint'))); + } + $var.push(QAST::ParamTypeCheck.new( + QAST::Op.new( + # If argument is a type object and is the same as parameter default then skip signature + # matching. So far, this is the best way I know to determine if corresponding argument was + # passed or not without inspecting the capture which is too slow. + :op, + QAST::Op.new( + :op, + QAST::Op.new( + :op, + QAST::Op.new( :op, $var-decont )), + QAST::Op.new(:op, $var-decont, QAST::WVal.new(:value(%info)))), + # If argument is concrete or is not parameter's default type then try signature matching + QAST::Op.new( + :op, + QAST::Op.new(:op, $var-qast, QAST::SVal.new(:value)), + QAST::Op.new( + :op, + :name, + $sigc-qast, + QAST::Op.new( + :op, + :name, + $var-qast )))))); + } + # Apply post-constraints (must come after variable bind, as constraints can # refer to the var). if %info { diff --git a/src/Perl6/World.nqp b/src/Perl6/World.nqp index e31cc8652d7..89e164395be 100644 --- a/src/Perl6/World.nqp +++ b/src/Perl6/World.nqp @@ -2286,6 +2286,11 @@ class Perl6::World is HLL::World { if nqp::existskey(%param_info, 'sub_signature') { nqp::bindattr($parameter, $par_type, '$!sub_signature', %param_info); } + if nqp::existskey(%param_info, 'signature_constraint') { + my $psc-role := $*W.find_symbol(['Parameter', 'SignatureConstraint'], :setting-only); + $parameter.HOW.mixin($parameter, $psc-role); + nqp::bindattr($parameter, $parameter.WHAT, '$!signature-constraint', %param_info); + } if nqp::existskey(%param_info, 'dummy') { my $dummy := %param_info; diff --git a/src/Perl6/bootstrap.c/BOOTSTRAP.nqp b/src/Perl6/bootstrap.c/BOOTSTRAP.nqp index 9d11ba798f7..e8f1cfdcc41 100644 --- a/src/Perl6/bootstrap.c/BOOTSTRAP.nqp +++ b/src/Perl6/bootstrap.c/BOOTSTRAP.nqp @@ -486,6 +486,34 @@ my class Binder { nqp::bindkey($lexpad, 'self', nqp::decont($oval)); } + if nqp::can($param, 'signature-constraint') { + # Assume argument not passed if it is undefined and is the same as parameter default type + unless !nqp::isconcrete($oval) && nqp::eqaddr(nqp::decont($oval), nqp::getattr($param, Parameter, '$!type')) { + my $can_signature; + my $sigc := $param.signature-constraint; + unless ($can_signature := nqp::can($oval, 'signature')) + && ($sigc.is_generic + ?? ($sigc := $sigc.instantiate_generic($lexpad)) + !! $sigc).ACCEPTS($oval.signature) + { + if nqp::defined($error) { + $error[0] := { + Perl6::Metamodel::Configuration.throw_or_die( + 'X::TypeCheck::Binding::Parameter', + "Signature check failed for parameter '$varname'", + :got($can_signature ?? $oval.signature !! Nil), + :expected($sigc), + :symbol($varname), + :parameter($param), + :what("Signature constraint") + ) + }; + } + return $BIND_RESULT_FAIL; + } + } + } + # Handle any constraint types (note that they may refer to the parameter by # name, so we need to have bound it already). my $post_cons := nqp::getattr($param, Parameter, '@!post_constraints'); @@ -1942,8 +1970,12 @@ BEGIN { # If nonimnal type or attr_package is generic, so are we. my $type := nqp::getattr($self, Parameter, '$!type'); my $ap := nqp::getattr($self, Parameter, '$!attr_package'); - nqp::hllboolfor($type.HOW.archetypes.generic || - (!nqp::isnull($ap) && $ap.HOW.archetypes.generic), "Raku") + my $sc_generic := nqp::can($self, 'signature-constraint') ?? $self.signature-constraint.is_generic !! 0; + nqp::hllboolfor( + $type.HOW.archetypes.generic + || (!nqp::isnull($ap) && $ap.HOW.archetypes.generic) + || $sc_generic, + "Raku") })); Parameter.HOW.add_method(Parameter, 'instantiate_generic', nqp::getstaticcode(sub ($self, $type_environment) { # Clone with the type instantiated. @@ -1963,6 +1995,10 @@ BEGIN { !nqp::isnull($ap) && $ap.HOW.archetypes.generic ?? $ap.HOW.instantiate_generic($ap, $type_environment) !! $ap; + if nqp::can($self, 'signature-constraint') { + $ins.INSTANTIATE-SIGNATURE-CONSTRAINT($type_environment) + if $ins.signature-constraint.is_generic; + } my int $flags := nqp::getattr_i($ins, Parameter, '$!flags'); unless $ins_type.HOW.archetypes.generic { if $flags +& $SIG_ELEM_TYPE_GENERIC { diff --git a/src/core.c/Exception.pm6 b/src/core.c/Exception.pm6 index f777ad1d791..1b2c4606790 100644 --- a/src/core.c/Exception.pm6 +++ b/src/core.c/Exception.pm6 @@ -2493,9 +2493,17 @@ my class X::TypeCheck::Binding is X::TypeCheck { my class X::TypeCheck::Binding::Parameter is X::TypeCheck::Binding { has Parameter $.parameter; has Bool $.constraint; + has Str $.what; method expectedn() { $.constraint && nqp::istype(self.expected, Code) ?? 'anonymous constraint to be met' + !! (nqp::istype($.expected, Signature) + ?? $.expected.raku + !! callsame()) + } + method gotn() { + nqp::istype($.expected, Signature) && nqp::eqaddr($.got, Nil) + ?? "none" !! callsame() } method message() { @@ -2505,7 +2513,7 @@ my class X::TypeCheck::Binding::Parameter is X::TypeCheck::Binding { my $expected = nqp::eqaddr(self.expected, self.got) ?? "expected type $.expectedn cannot be itself" !! "expected $.expectedn but got $.gotn"; - my $what-check = $.constraint ?? 'Constraint type' !! 'Type'; + my $what-check = $.what // ($.constraint ?? 'Constraint type' !! 'Type'); self.priors() ~ "$what-check check failed in $.operation$to; $expected"; } } diff --git a/src/core.c/Parameter.pm6 b/src/core.c/Parameter.pm6 index acf69237dc5..49a57f3e1a2 100644 --- a/src/core.c/Parameter.pm6 +++ b/src/core.c/Parameter.pm6 @@ -635,6 +635,13 @@ my class Parameter { # declared in BOOTSTRAP } } +my role Parameter::SignatureConstraint { + has $.signature-constraint; + method INSTANTIATE-SIGNATURE-CONSTRAINT(Mu \type_environment) is implementation-detail { + $!signature-constraint := $!signature-constraint.instantiate_generic(type_environment); + } +} + multi sub infix:(Parameter:D $a, Parameter:D $b) { # we're us From ffb587f20281bb884ba34f31dabd9a17790c3d5d Mon Sep 17 00:00:00 2001 From: Vadim Belman Date: Thu, 30 Sep 2021 16:48:26 -0400 Subject: [PATCH 3/5] Sort multi-candidates with signature constraint in mind Mark multi-candidates with signature constrained parameters as `bind_check` and `constrainty`. Resolve ambiguous matching. --- src/Perl6/bootstrap.c/BOOTSTRAP.nqp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Perl6/bootstrap.c/BOOTSTRAP.nqp b/src/Perl6/bootstrap.c/BOOTSTRAP.nqp index e8f1cfdcc41..f255f25be36 100644 --- a/src/Perl6/bootstrap.c/BOOTSTRAP.nqp +++ b/src/Perl6/bootstrap.c/BOOTSTRAP.nqp @@ -2502,7 +2502,9 @@ BEGIN { # to check constraint on every dispatch. Same if it's got a # `where` clause. unless nqp::isnull(nqp::getattr($param, Parameter, '$!sub_signature')) && - nqp::isnull(nqp::getattr($param, Parameter, '@!post_constraints')) { + nqp::isnull(nqp::getattr($param, Parameter, '@!post_constraints')) && + nqp::not_i(nqp::can($param, 'signature-constraint')) + { %info := 1; %info := 1; } @@ -2572,7 +2574,8 @@ BEGIN { } %info[$significant_param] := $ptype; } - unless nqp::isnull(nqp::getattr($param, Parameter, '@!post_constraints')) { + unless nqp::isnull(nqp::getattr($param, Parameter, '@!post_constraints')) + && nqp::not_i(nqp::can($param, 'signature-constraint')) { %info[$significant_param] := 1; } if $flags +& $SIG_ELEM_MULTI_INVOCANT { From 51968148ae6528990bb75ae1b8353203be59081e Mon Sep 17 00:00:00 2001 From: Vadim Belman Date: Thu, 30 Sep 2021 21:08:31 -0400 Subject: [PATCH 4/5] Rollback the idea of extra role for signature constraint It was about wrong assumption that a new `Attribute` instance would be allocated per each instance of `Parameter`. No idea what's got over me when the idea came into my mind... `$!signature_constraint` is now a permement member of `Parameter` class. --- src/Perl6/Actions.nqp | 8 ++++---- src/Perl6/World.nqp | 4 +--- src/Perl6/bootstrap.c/BOOTSTRAP.nqp | 28 +++++++++++++++------------- src/core.c/Parameter.pm6 | 20 +++++++++++++------- 4 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/Perl6/Actions.nqp b/src/Perl6/Actions.nqp index 7cc01aab125..3346a629c53 100644 --- a/src/Perl6/Actions.nqp +++ b/src/Perl6/Actions.nqp @@ -9732,8 +9732,8 @@ class Perl6::Actions is HLL::Actions does STDActions { QAST::Op.new( :op, $inst_param, - QAST::Op.new(:op, $inst_param), - QAST::SVal.new(:value('$!signature-constraint'))))), + QAST::WVal.new(:value($Param)), + QAST::SVal.new(:value('$!signature_constraint'))))), QAST::Op.new( :op, :name, @@ -9747,8 +9747,8 @@ class Perl6::Actions is HLL::Actions does STDActions { $sigc-qast := QAST::Op.new( :op, $inst_param, - QAST::Op.new(:op, $inst_param), - QAST::SVal.new(:value('$!signature-constraint'))); + QAST::WVal.new(:value($Param)), + QAST::SVal.new(:value('$!signature_constraint'))); } $var.push(QAST::ParamTypeCheck.new( QAST::Op.new( diff --git a/src/Perl6/World.nqp b/src/Perl6/World.nqp index 89e164395be..408c60ec5e0 100644 --- a/src/Perl6/World.nqp +++ b/src/Perl6/World.nqp @@ -2287,9 +2287,7 @@ class Perl6::World is HLL::World { nqp::bindattr($parameter, $par_type, '$!sub_signature', %param_info); } if nqp::existskey(%param_info, 'signature_constraint') { - my $psc-role := $*W.find_symbol(['Parameter', 'SignatureConstraint'], :setting-only); - $parameter.HOW.mixin($parameter, $psc-role); - nqp::bindattr($parameter, $parameter.WHAT, '$!signature-constraint', %param_info); + nqp::bindattr($parameter, $par_type, '$!signature_constraint', %param_info); } if nqp::existskey(%param_info, 'dummy') { diff --git a/src/Perl6/bootstrap.c/BOOTSTRAP.nqp b/src/Perl6/bootstrap.c/BOOTSTRAP.nqp index f255f25be36..ee8aadb3ab4 100644 --- a/src/Perl6/bootstrap.c/BOOTSTRAP.nqp +++ b/src/Perl6/bootstrap.c/BOOTSTRAP.nqp @@ -486,15 +486,14 @@ my class Binder { nqp::bindkey($lexpad, 'self', nqp::decont($oval)); } - if nqp::can($param, 'signature-constraint') { + if nqp::defined(my $sigc := nqp::getattr($param, Parameter, '$!signature_constraint')) { # Assume argument not passed if it is undefined and is the same as parameter default type unless !nqp::isconcrete($oval) && nqp::eqaddr(nqp::decont($oval), nqp::getattr($param, Parameter, '$!type')) { my $can_signature; - my $sigc := $param.signature-constraint; unless ($can_signature := nqp::can($oval, 'signature')) - && ($sigc.is_generic - ?? ($sigc := $sigc.instantiate_generic($lexpad)) - !! $sigc).ACCEPTS($oval.signature) + && ( $sigc.is_generic + ?? ($sigc := $sigc.instantiate_generic($lexpad)) + !! $sigc ).ACCEPTS($oval.signature) { if nqp::defined($error) { $error[0] := { @@ -1966,15 +1965,16 @@ BEGIN { Parameter.HOW.add_attribute(Parameter, scalar_attr('$!container_descriptor', Mu, Parameter, :!auto_viv_container)); Parameter.HOW.add_attribute(Parameter, Attribute.new(:name<$!attr_package>, :type(Mu), :package(Parameter))); Parameter.HOW.add_attribute(Parameter, Attribute.new(:name<$!why>, :type(Mu), :package(Parameter))); + Parameter.HOW.add_attribute(Parameter, Attribute.new(:name<$!signature_constraint>, :type(Signature), :package(Parameter))); Parameter.HOW.add_method(Parameter, 'is_generic', nqp::getstaticcode(sub ($self) { # If nonimnal type or attr_package is generic, so are we. my $type := nqp::getattr($self, Parameter, '$!type'); my $ap := nqp::getattr($self, Parameter, '$!attr_package'); - my $sc_generic := nqp::can($self, 'signature-constraint') ?? $self.signature-constraint.is_generic !! 0; + my $sigc := nqp::getattr($self, Parameter, '$!signature_constraint'); nqp::hllboolfor( $type.HOW.archetypes.generic || (!nqp::isnull($ap) && $ap.HOW.archetypes.generic) - || $sc_generic, + || (nqp::defined($sigc) && $sigc.is_generic), "Raku") })); Parameter.HOW.add_method(Parameter, 'instantiate_generic', nqp::getstaticcode(sub ($self, $type_environment) { @@ -1985,6 +1985,7 @@ BEGIN { my $type := nqp::getattr($self, Parameter, '$!type'); my $cd := nqp::getattr($self, Parameter, '$!container_descriptor'); my $ap := nqp::getattr($self, Parameter, '$!attr_package'); + my $sigc := nqp::getattr($self, Parameter, '$!signature_constraint'); my $ins_type := $type; my $ins_cd := $cd; if $type.HOW.archetypes.generic { @@ -1995,10 +1996,10 @@ BEGIN { !nqp::isnull($ap) && $ap.HOW.archetypes.generic ?? $ap.HOW.instantiate_generic($ap, $type_environment) !! $ap; - if nqp::can($self, 'signature-constraint') { - $ins.INSTANTIATE-SIGNATURE-CONSTRAINT($type_environment) - if $ins.signature-constraint.is_generic; - } + my $ins_sigc := + nqp::defined($sigc) && $sigc.is_generic + ?? $sigc.instantiate_generic($type_environment) + !! $sigc; my int $flags := nqp::getattr_i($ins, Parameter, '$!flags'); unless $ins_type.HOW.archetypes.generic { if $flags +& $SIG_ELEM_TYPE_GENERIC { @@ -2012,6 +2013,7 @@ BEGIN { nqp::bindattr($ins, Parameter, '$!type', $ins_type); nqp::bindattr($ins, Parameter, '$!container_descriptor', $ins_cd); nqp::bindattr($ins, Parameter, '$!attr_package', $ins_ap); + nqp::bindattr($ins, Parameter, '$!signature_constraint', $ins_sigc); $ins })); Parameter.HOW.add_method(Parameter, 'set_rw', nqp::getstaticcode(sub ($self) { @@ -2503,7 +2505,7 @@ BEGIN { # `where` clause. unless nqp::isnull(nqp::getattr($param, Parameter, '$!sub_signature')) && nqp::isnull(nqp::getattr($param, Parameter, '@!post_constraints')) && - nqp::not_i(nqp::can($param, 'signature-constraint')) + !nqp::defined(nqp::getattr($param, Parameter, '$!signature_constraint')) { %info := 1; %info := 1; @@ -2575,7 +2577,7 @@ BEGIN { %info[$significant_param] := $ptype; } unless nqp::isnull(nqp::getattr($param, Parameter, '@!post_constraints')) - && nqp::not_i(nqp::can($param, 'signature-constraint')) { + && !nqp::defined(nqp::getattr($param, Parameter, '$!signature_constraint')) { %info[$significant_param] := 1; } if $flags +& $SIG_ELEM_MULTI_INVOCANT { diff --git a/src/core.c/Parameter.pm6 b/src/core.c/Parameter.pm6 index 49a57f3e1a2..64ce58bf425 100644 --- a/src/core.c/Parameter.pm6 +++ b/src/core.c/Parameter.pm6 @@ -510,6 +510,15 @@ my class Parameter { # declared in BOOTSTRAP return False; } + my \osignature_constraint := nqp::getattr(o, Parameter, '$!signature_constraint'); + if nqp::defined($!signature_constraint) { + return False unless nqp::defined(osignature_constraint) + && $!signature_constraint.ACCEPTS(osignature_constraint); + } + else { + return False if nqp::defined(osignature_constraint); + } + # we have a post constraint if nqp::islist(@!post_constraints) { @@ -626,6 +635,10 @@ my class Parameter { # declared in BOOTSTRAP nqp::isnull($!sub_signature) ?? Signature !! $!sub_signature } + method signature_constraint(Parameter:D: --> Signature:_) { + nqp::isnull($!signature_constraint) ?? Signature !! $!signature_constraint + } + method set_why(Parameter:D: $why --> Nil) { $!why := $why; } @@ -635,13 +648,6 @@ my class Parameter { # declared in BOOTSTRAP } } -my role Parameter::SignatureConstraint { - has $.signature-constraint; - method INSTANTIATE-SIGNATURE-CONSTRAINT(Mu \type_environment) is implementation-detail { - $!signature-constraint := $!signature-constraint.instantiate_generic(type_environment); - } -} - multi sub infix:(Parameter:D $a, Parameter:D $b) { # we're us From d47185eb3e75f43a65199ca8826fe0f349037726 Mon Sep 17 00:00:00 2001 From: Vadim Belman Date: Thu, 30 Sep 2021 21:24:58 -0400 Subject: [PATCH 5/5] Add signature constraint to parameter name in .raku As we now have access to this information, .raku output would better resemble the original declaration. --- src/core.c/Parameter.pm6 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/core.c/Parameter.pm6 b/src/core.c/Parameter.pm6 index 64ce58bf425..fbd26011527 100644 --- a/src/core.c/Parameter.pm6 +++ b/src/core.c/Parameter.pm6 @@ -577,6 +577,9 @@ my class Parameter { # declared in BOOTSTRAP } else { $name ~= $sigil ~ $twigil ~ $usage-name; } + if nqp::isconcrete($!signature_constraint) { + $name ~= $!signature_constraint.raku; + } if nqp::isconcrete(@!named_names) { my $var-is-named = False; my @outer-names = gather for @.named_names {