From d8ad62249ae0e2eca954a1cc92d62accbb9078ad Mon Sep 17 00:00:00 2001 From: Vadim Belman Date: Sat, 23 Mar 2019 19:48:16 -0400 Subject: [PATCH] Made all operators in Real require definite objects Fix for rakudo/rakudo#2786. As a side effect, this changes the way rakudo complains about use of type objects. Where previously it was throwing an exception it is now warns about use of undefined value: Use of uninitialized value of type Int in numeric context This is to conform with similar behaviour of other types like Str, Date, Version. Also, I would refer to this: https://colabti.org/irclogger/irclogger_log/perl6?date=2011-07-03#l554 --- src/core/Real.pm6 | 36 ++++++++++++++++++------------------ t/05-messages/02-errors.t | 33 +++++++++++++++++++-------------- 2 files changed, 37 insertions(+), 32 deletions(-) diff --git a/src/core/Real.pm6 b/src/core/Real.pm6 index c341649893f..ef76949b1b4 100644 --- a/src/core/Real.pm6 +++ b/src/core/Real.pm6 @@ -132,42 +132,42 @@ my role Real does Numeric { } proto sub cis($, *%) {*} -multi sub cis(Real $a) { $a.cis } +multi sub cis(Real:D $a) { $a.cis } -multi sub infix:<+>(Real \a, Real \b) { a.Bridge + b.Bridge } +multi sub infix:<+>(Real:D \a, Real:D \b) { a.Bridge + b.Bridge } -multi sub infix:<->(Real \a, Real \b) { a.Bridge - b.Bridge } +multi sub infix:<->(Real:D \a, Real:D \b) { a.Bridge - b.Bridge } -multi sub infix:<*>(Real \a, Real \b) { a.Bridge * b.Bridge } +multi sub infix:<*>(Real:D \a, Real:D \b) { a.Bridge * b.Bridge } -multi sub infix:(Real \a, Real \b) { a.Bridge / b.Bridge } +multi sub infix:(Real:D \a, Real:D \b) { a.Bridge / b.Bridge } -multi sub infix:<%>(Real \a, Real \b) { a.Bridge % b.Bridge } +multi sub infix:<%>(Real:D \a, Real:D \b) { a.Bridge % b.Bridge } -multi sub infix:<**>(Real \a, Real \b) { a.Bridge ** b.Bridge } +multi sub infix:<**>(Real:D \a, Real:D \b) { a.Bridge ** b.Bridge } -multi sub infix:«<=>»(Real \a, Real \b) { a.Bridge <=> b.Bridge } +multi sub infix:«<=>»(Real:D \a, Real:D \b) { a.Bridge <=> b.Bridge } -multi sub infix:<==>(Real \a, Real \b) { a.Bridge == b.Bridge } +multi sub infix:<==>(Real:D \a, Real:D \b) { a.Bridge == b.Bridge } -multi sub infix:«<»(Real \a, Real \b) { a.Bridge < b.Bridge } +multi sub infix:«<»(Real:D \a, Real:D \b) { a.Bridge < b.Bridge } -multi sub infix:«<=»(Real \a, Real \b) { a.Bridge <= b.Bridge } +multi sub infix:«<=»(Real:D \a, Real:D \b) { a.Bridge <= b.Bridge } -multi sub infix:«>»(Real \a, Real \b) { a.Bridge > b.Bridge } +multi sub infix:«>»(Real:D \a, Real:D \b) { a.Bridge > b.Bridge } -multi sub infix:«>=»(Real \a, Real \b) { a.Bridge >= b.Bridge } +multi sub infix:«>=»(Real:D \a, Real:D \b) { a.Bridge >= b.Bridge } multi sub prefix:<->(Real:D \a) { -a.Bridge } # NOTE: According to the spec, infix: is "Not coercive, # so fails on differing types." Thus no casts here. proto sub infix:($, $, *%) is pure {*} -multi sub infix:(Real $a, Real $b) { +multi sub infix:(Real:D $a, Real:D $b) { $a - ($a div $b) * $b; } -multi sub abs(Real \a) { +multi sub abs(Real:D \a) { a < 0 ?? -a !! a; } @@ -177,13 +177,13 @@ multi sub truncate(Cool:D $x) { $x.Numeric.truncate } proto sub atan2($, $?, *%) {*} -multi sub atan2(Real \a, Real \b = 1e0) { a.Bridge.atan2(b.Bridge) } +multi sub atan2(Real:D \a, Real:D \b = 1e0) { a.Bridge.atan2(b.Bridge) } # should really be (Cool, Cool), and then (Cool, Real) and (Real, Cool) # candidates, but since Int both conforms to Cool and Real, we'd get lots # of ambiguous dispatches. So just go with (Any, Any) for now. -multi sub atan2( \a, \b = 1e0) { a.Numeric.atan2(b.Numeric) } +multi sub atan2(Any:D \a, Any:D \b = 1e0) { a.Numeric.atan2(b.Numeric) } proto sub unpolar($, $, *%) {*} -multi sub unpolar(Real $mag, Real $angle) { $mag.unpolar($angle) } +multi sub unpolar(Real:D $mag, Real:D $angle) { $mag.unpolar($angle) } # vim: ft=perl6 expandtab sw=4 diff --git a/t/05-messages/02-errors.t b/t/05-messages/02-errors.t index 642916a6dc2..65768d639d8 100644 --- a/t/05-messages/02-errors.t +++ b/t/05-messages/02-errors.t @@ -211,47 +211,52 @@ throws-like 「Set.new(1..300)<42> = 42」, subtest 'cannot use Int type object as an operand' => { plan 14; + CONTROL { + when CX::Warn { + die $_ + } + } throws-like 「(1/1)+Int」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'A Rational instance cannot be added by an Int type object'; throws-like 「Int+(1/1)」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'An Int type object cannot be added by a Rational instance'; throws-like 「(1/1)-Int」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'A Rational instance cannot be subtracted by an Int type object'; throws-like 「Int-(1/1)」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'An Int type object cannot be subtracted by a Rational instance'; throws-like 「(1/1)*Int」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'A Rational instance cannot be multiplied by an Int type object'; throws-like 「Int*(1/1)」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'An Int type object cannot be multiplied by a Rational instance'; throws-like 「(1/1)/Int」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'A Rational instance cannot be divided by an Int type object'; throws-like 「Int/(1/1)」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'An Int type object cannot be divided by a Rational instance'; throws-like 「Int/Int」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'An Int type object cannot be divided by an Int type object'; throws-like 「Int/1」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'An Int type object cannot be divided by an Int instance'; throws-like 「1/Int」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'An Int instance cannot be divided by an Int type object'; throws-like 「(1/1)%Int」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'A Rational instance modulo an Int type object is incalculable'; throws-like 「Int%(1/1)」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'An Int type object modulo a Rational instance is incalculable'; throws-like 「(1/1)**Int」, - X::Parameter::InvalidConcreteness, + CX::Warn, 'A Rational instance cannot be powered by an Int type object'; }