Skip to content

Commit

Permalink
Merge pull request #1073 from MasterDuke17/add_method_name_to_type_vs…
Browse files Browse the repository at this point in the history
…_instance_error

Add method name and received type to type vs instance error
  • Loading branch information
lizmat committed May 1, 2017
2 parents 0e0ac2f + b4b5504 commit 858a3d5
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 18 deletions.
37 changes: 19 additions & 18 deletions src/Perl6/Metamodel/BOOTSTRAP.nqp
Expand Up @@ -316,25 +316,26 @@ my class Binder {

# Also enforce definedness constraints.
if $flags +& $SIG_ELEM_DEFINEDNES_CHECK {
if $flags +& $SIG_ELEM_UNDEFINED_ONLY && nqp::isconcrete($oval) {
if (my $should_be_concrete := $flags +& $SIG_ELEM_DEFINED_ONLY && !nqp::isconcrete($oval)) ||
$flags +& $SIG_ELEM_UNDEFINED_ONLY && nqp::isconcrete($oval)
{
if nqp::defined($error) {
my $class := $nom_type.HOW.name($nom_type);
my $what := $flags +& $SIG_ELEM_INVOCANT
?? "Invocant"
!! "Parameter '$varname'";
$error[0] := "$what requires a type object of type $class, but an object instance was passed. Did you forget a 'multi'?";
}
return $oval.WHAT =:= Junction && nqp::isconcrete($oval)
?? $BIND_RESULT_JUNCTION
!! $BIND_RESULT_FAIL;
}
if $flags +& $SIG_ELEM_DEFINED_ONLY && !nqp::isconcrete($oval) {
if nqp::defined($error) {
my $class := $nom_type.HOW.name($nom_type);
my $what := $flags +& $SIG_ELEM_INVOCANT
?? "Invocant"
!! "Parameter '$varname'";
$error[0] := "$what requires an instance of type $class, but a type object was passed. Did you forget a .new?";
my $method := nqp::getcodeobj(nqp::ctxcode($lexpad)).name;
my $class := $nom_type.HOW.name($nom_type);
my $got := $oval.HOW.name($oval);
my %ex := nqp::gethllsym('perl6', 'P6EX');
if nqp::isnull(%ex) || !nqp::existskey(%ex, 'X::Parameter::RW') {
$method := '<anon>' if nqp::isnull_s($method) || $method eq '';
$error[0] := $flags +& $SIG_ELEM_INVOCANT
?? $should_be_concrete
?? "Invocant of method '$method' must be an object instance of type '$class', not a type object of type '$got'. Did you forget a '.new'?"
!! "Invocant of method '$method' must be a type object of type '$class', not an object instance of type '$got'. Did you forget a 'multi'?"
!! $should_be_concrete
?? "Parameter '$varname' of routine '$method' must be an object instance of type '$class', not a type object of type '$got'. Did you forget a '.new'?"
!! "Parameter '$varname' of routine '$method' must be a type object of type '$class', not an object instance of type '$got'. Did you forget a 'multi'?";
} else {
$error[0] := { nqp::atkey(%ex, 'X::Parameter::InvalidConcreteness')($class, $got, $method, $varname, $should_be_concrete, $flags +& $SIG_ELEM_INVOCANT) };
}
}
return $oval.WHAT =:= Junction && nqp::isconcrete($oval)
?? $BIND_RESULT_JUNCTION
Expand Down
25 changes: 25 additions & 0 deletions src/core/Exception.pm
Expand Up @@ -1143,6 +1143,26 @@ my class X::Parameter::WrongOrder does X::Comp {
}
}

my class X::Parameter::InvalidConcreteness is Exception {
has $.expected;
has $.got;
has $.routine;
has $.param;
has $.should-be-concrete;
has $.param-is-invocant;

method message() {
$!routine = '<anon>' if not $!routine.defined or $!routine eq '';
$!param = '<anon>' if not $!param.defined or $!param eq '';
my $beginning = $!param-is-invocant ?? 'Invocant of method' !! "Parameter '$!param' of routine";
my $must-be = $!should-be-concrete ?? 'an object instance' !! 'a type object';
my $not-a = $!should-be-concrete ?? 'a type object' !! 'an object instance';
my $suggestion = $!should-be-concrete ?? '.new' !! 'multi';

"$beginning '$!routine' must be $must-be of type '$!expected', not $not-a of type '$!got'. Did you forget a '$suggestion'?"
}
}

my class X::Parameter::InvalidType does X::Comp {
has $.typename;
has @.suggestions;
Expand Down Expand Up @@ -2457,6 +2477,7 @@ my class X::PhaserExceptions is Exception {
}
}


#?if jvm
nqp::bindcurhllsym('P6EX', nqp::hash(
#?endif
Expand Down Expand Up @@ -2529,6 +2550,10 @@ nqp::bindcurhllsym('P6EX', BEGIN nqp::hash(
-> $type, $subtype, $declaring, $name {
X::Trait::Invalid.new(:$type, :$subtype, :$declaring, :$name).throw;
},
'X::Parameter::InvalidConcreteness',
-> $expected, $got, $routine, $param, $should-be-concrete, $param-is-invocant {
X::Parameter::InvalidConcreteness.new(:$expected, :$got, :$routine, :$param, :$should-be-concrete, :$param-is-invocant).throw;
},
));

my class X::HyperWhatever::Multiple is Exception {
Expand Down
20 changes: 20 additions & 0 deletions t/05-messages/01-errors.t
Expand Up @@ -85,4 +85,24 @@ throws-like 「m: my @a = for 1..3 <-> { $_ }」, Exception,
'The message when trying to pun a role with required methods should have the names of the child, parent, required methods, and suggest "does"';
}

# RT #126124
# adapted from S06-signature/types.t
{
throws-like { sub f(Mu:D $a) {}; f(Int) },
Exception,
message => all(/'Parameter'/, /\W '$a'>>/, /<<'f'>>/, /<<'must be an object instance'>>/, /<<'not a type object'>>/, /<<'Mu'>>/, /<<'Int'>>/, /\W '.new'>>/),
'types and names shown in the exception message are correct';
throws-like { sub f(Mu:U $a) {}; f(123) },
Exception,
message => all(/'Parameter'/, /\W '$a'>>/, /<<'f'>>/, /<<'not an object instance'>>/, /<<'must be a type object'>>/, /<<'Mu'>>/, /<<'Int'>>/, /<<'multi'>>/),
'types shown in the exception message are correct';
}

# adapted from S32-exceptions/misc.t
for <fail die throw rethrow resumable resume> -> $meth {
throws-like 'X::NYI.' ~ $meth,
Exception,
message => all(/'Invocant'/, /<<$meth>>/, /<<'must be an object instance'>>/, /<<'not a type object'>>/, /<<'Exception'>>/, /<<'X::NYI'>>/, /\W '.new'>>/),
}

done-testing;

0 comments on commit 858a3d5

Please sign in to comment.