Skip to content

Commit

Permalink
Make method Bridge take care of uninitialized numerics
Browse files Browse the repository at this point in the history
I needed all this to take care of `Int() == 0` case.

For typeobject it'd throw a new X::Numeric::Uninitialized exception.

For coercions it'd bypass to Mu::Numeric to produce a warning and
use it's return as the default.

Definite values are special-cased by some of the numeric types.

As a side effect this commit results in more user-friendly error
messages.
  • Loading branch information
vrurg committed Nov 15, 2020
1 parent 43a81a2 commit 8a1ba7f
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 23 deletions.
2 changes: 1 addition & 1 deletion src/core.c/Duration.pm6
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ my class Duration is Cool does Real {
!! nqp::p6bindattrinvres(nqp::create(Duration),Duration,'$!tai',tai)
}

method Bridge(Duration:D: --> Num:D) { $!tai.Num }
method Bridge(Duration: --> Num:D) { self.defined ?? $!tai.Num !! self.Real::Bridge }
method Num (Duration:D: --> Num:D) { $!tai.Num }
method Rat (Duration:D: --> Rat:D) { $!tai }
method narrow(Duration:D: ) { $!tai.narrow }
Expand Down
5 changes: 5 additions & 0 deletions src/core.c/Exception.pm6
Original file line number Diff line number Diff line change
Expand Up @@ -2758,6 +2758,11 @@ my class X::Numeric::Underflow is Exception {
method message() { "Numeric underflow" }
}

my class X::Numeric::Uninitialized is Exception {
has Numeric $.type;
method message() { "Use of uninitialized value of type " ~ $!type.^name ~ " in numeric context" }
}

my class X::Numeric::Confused is Exception {
has $.num;
has $.base;
Expand Down
2 changes: 1 addition & 1 deletion src/core.c/Instant.pm6
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ my class Instant is Cool does Real {
my ($posix,$flag) = self.to-posix;
'Instant.from-posix(' ~ $posix.raku ~ ($flag ?? ',True)' !! ')')
}
method Bridge(Instant:D: ) { $!tai.Bridge }
method Bridge(Instant: --> Num:D) { self.defined ?? $!tai.Bridge !! self.Real::Bridge }
method Num (Instant:D: --> Num:D) { $!tai.Num }
method Rat (Instant:D: --> Rat:D) { $!tai }
method Int (Instant:D: --> Int:D) { $!tai.Int }
Expand Down
6 changes: 4 additions & 2 deletions src/core.c/Int.pm6
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,10 @@ my class Int does Real { # declared in BOOTSTRAP
nqp::abs_I(self, Int)
}

method Bridge(Int:D: --> Num:D) {
nqp::p6box_n(nqp::tonum_I(self));
method Bridge(Int: --> Num:D) {
self.defined
?? nqp::p6box_n(nqp::tonum_I(self))
!! self.Real::Bridge
}

method chr(Int:D: --> Str:D) {
Expand Down
2 changes: 1 addition & 1 deletion src/core.c/Num.pm6
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ my class Num does Real { # declared in BOOTSTRAP
multi method Bool(Num:D:) { nqp::hllbool(nqp::isne_n(self,0e0)) }
method Capture() { X::Cannot::Capture.new( :what(self) ).throw }
method Num() { self }
method Bridge(Num:D:) { self }
method Bridge(Num:) { self.defined ?? self !! self.Real::Bridge }
method Range(Num:U:) { Range.new(-Inf,Inf) }

method Int(Num:D:) {
Expand Down
2 changes: 0 additions & 2 deletions src/core.c/Rational.pm6
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,6 @@ my role Rational[::NuT = Int, ::DeT = ::("NuT")] does Real {

multi method Bool(::?CLASS:D:) { nqp::hllbool(nqp::istrue($!numerator)) }

method Bridge() { self.Num }

method Range(::?CLASS:U:) { Range.new(-Inf, Inf) }

method isNaN (--> Bool:D) {
Expand Down
11 changes: 9 additions & 2 deletions src/core.c/Real.pm6
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
my class Complex { ... }
my class X::Numeric::Uninitialized { ... }

my role Real does Numeric {
method Rat(Real:D: Real $epsilon = 1.0e-6) { self.Bridge.Rat($epsilon) }
Expand Down Expand Up @@ -125,7 +126,13 @@ my role Real does Numeric {
self.Mu::Real; # issue a warning;
self.new
}
method Bridge(Real:D:) { self.Num }
method Bridge(Real: --> Num:D) {
self.defined
?? self.Num
!! (self.HOW.archetypes.coercive
?? self.Mu::Numeric.Num
!! X::Numeric::Uninitialized.new(:type(self)).throw)
}
method Int(Real:D:) { self.Bridge.Int }
method Num(Real:D:) { self.Bridge.Num }
multi method Str(Real:D:) { self.Bridge.Str }
Expand All @@ -148,7 +155,7 @@ multi sub infix:<**>(Real \a, Real \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 \a, Real \b) { a.Bridge < b.Bridge }

Expand Down
28 changes: 14 additions & 14 deletions t/05-messages/02-errors.t
Original file line number Diff line number Diff line change
Expand Up @@ -215,46 +215,46 @@ subtest 'cannot use Int type object as an operand' => {
plan 14;

throws-like (1/1)+Int,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'A Rational instance cannot be added by an Int type object';
throws-like Int+(1/1),
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'An Int type object cannot be added by a Rational instance';
throws-like (1/1)-Int,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'A Rational instance cannot be subtracted by an Int type object';
throws-like Int-(1/1),
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'An Int type object cannot be subtracted by a Rational instance';
throws-like (1/1)*Int,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'A Rational instance cannot be multiplied by an Int type object';
throws-like Int*(1/1),
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'An Int type object cannot be multiplied by a Rational instance';
throws-like (1/1)/Int,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'A Rational instance cannot be divided by an Int type object';
throws-like Int/(1/1),
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'An Int type object cannot be divided by a Rational instance';
throws-like Int/Int,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'An Int type object cannot be divided by an Int type object';
throws-like Int/1,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'An Int type object cannot be divided by an Int instance';
throws-like 1/Int,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'An Int instance cannot be divided by an Int type object';
throws-like (1/1)%Int,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'A Rational instance modulo an Int type object is incalculable';
throws-like Int%(1/1),
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'An Int type object modulo a Rational instance is incalculable';
throws-like (1/1)**Int,
X::Parameter::InvalidConcreteness,
X::Numeric::Uninitialized,
'A Rational instance cannot be powered by an Int type object';
}

Expand Down

0 comments on commit 8a1ba7f

Please sign in to comment.