broken

16 views
Skip to first unread message

John Skaller2

unread,
Apr 30, 2019, 11:54:30 AM4/30/19
to felix google
Felix is broken at the moment. In fixing the interaction between abstract types and
nominal type subtyping coercions, I decided to abandon the approach I was using
(which destroyed an invariant) and instead try another (which preserved the invariant).

Unfortunately I just clobbered most of my changes which included several bug fixes
which hadn’t been committed, and retained some good ones, then committed,
leaving the system broken. I can’t remember what i did before. There are two
bugs I have to fix again. Sorry!




John Skaller
ska...@internode.on.net





John Skaller2

unread,
Apr 30, 2019, 12:12:17 PM4/30/19
to felix google
The nominal subtyping test is nonsense:

typedef mylong = long;
ctor mylong (x:int) => x.long;
supertype mylong (x:int) => x.mylong;

println$ 12.mylong;

So, this is just saying long is supertype of int, which it already is.
You cannot do this sanely, typedefs are just factored away.

But what I do not understand is that the result is 64.
The C++ code is an infinite loop:

void _init_(FLX_APAR_DECL_ONLY){
{
_a17385t_70713 _tmp70732 = ::flx::rtl::strutil::str<long>(_ctor_mylong(12)) + ::std::string("\n") ;
::flx::rtl::ioutil::write(stdout,((_tmp70732)));
}
fflush(stdout);
…..


//------------------------------
//C FUNC <67823>: _ctor_mylong
long _ctor_mylong( int _vI67825_x){
return (_supertype_mylong(_vI67825_x)) ;
}

//------------------------------
//C FUNC <67826>: _supertype_mylong
long _supertype_mylong( int _vI67828_x){
return _ctor_mylong(_vI67828_x);
}


This should crash but prints the wrong answer instead.

Note I had to change the code. The current rule (which sucks) is that
ctors must be applied explicitly, however a supertype coersion is
applied implicitly. To apply it explicitly you have to use a coercion:

x :>> T

The code is WRONG because the coercion shouldn’t be involved at all.
It’s a plain call to the ctor here!

I have another routine with the same problem. I fixed this before but clobbered the
fix. The problem was related to abstract types and explicit returns. When you give
an explicit return type, the value returned is coerced to it. So for example

fun f (x:int): long => x;

should work because long is a supertype of x. It does work.






John Skaller
ska...@internode.on.net





John Skaller2

unread,
Apr 30, 2019, 12:39:55 PM4/30/19
to felix google

HOWEVER this fails:

open class A {
open class A {
type mydouble = new double;
ctor mydouble : int = "(double)$1";
supertype mydouble (x:int) => x.mydouble;
supertype mydouble : double = "$1";

fun + (x:mydouble, y:mydouble) => (x._repr_ + y._repr_);

instance Str[mydouble] { fun str (x:mydouble) => x._repr_.str; }
}
println$ 42.mydouble + 0.3;


UNRESOLVED RETURN ERROR
In /Users/skaller/felix/bb.flx: line 7, cols 3 to 59
6:
7: fun + (x:mydouble, y:mydouble) => (x._repr_ + y._repr_);
*********************************************************


It’s rubbish. The return type here should be double.
This works:

fun + (x:mydouble, y:mydouble): mydouble => (x._repr_ + y._repr_);

by using the coercion implicitly. This fails:

instance Str[mydouble] { fun str (x:mydouble)=> x._repr_.str; }

but this works:

instance Str[mydouble] { fun str (x:mydouble):string => x._repr_.str; }


but then the program, finally, goes into an infinite loop.



John Skaller
ska...@internode.on.net





John Skaller2

unread,
Apr 30, 2019, 12:49:27 PM4/30/19
to felix google
So one of the reasons for supertypes is to get rid of typed integers. No more stuff
like 25L. Instead, we have a type “integer literal” which in C++ is a constexpr int.
Constant folding is then an ordinary function. But the big thing is that
we make all integers a supertype of an integer literal type AND provide
an explicit constructor.

The effect is that you can write

12.int64

instead of

12i64

Expressions like

x + 1

will then work, by promoting literal 1 to the type of x.


John Skaller
ska...@internode.on.net





John Skaller2

unread,
May 1, 2019, 8:02:05 AM5/1/19
to felix google
I am having serious problems here! I seem to have about 20 bugs working at once.

open Str[double];
fun sd (x:double) => x.str;
open class A {
type mydouble = new double;
ctor mydouble : int = "(double)$1";
supertype mydouble (x:int) => x.mydouble;
supertype mydouble : double = "$1";

fun + (x:mydouble, y:mydouble) => (x._repr_ + y._repr_) :>> mydouble;

instance Str[mydouble] { fun str (x:mydouble) => x._repr_.sd; }
}
println$ 42.mydouble + 0.3;

The above won’t compile if I remove the coercion from fun +.
However with it in there, it compiles and generates rubbish:

void _init_(){
double y;
double _vI65623_x;
double _urv65622;
_vI65623_x = (double)42 ; //init
y = (0.3) ; //init
start_65621_L65625:;
/*parallel assignment*/
y = y ; //init
_vI65623_x = _vI65623_x ; //init
goto start_65621_L65625;
{
_a17385t_65732 _tmp65740 = str(_urv65622) + ::std::string("\n") ;
::flx::rtl::ioutil::write(stdout,((_tmp65740)));
}
fflush(stdout);
}

This C++ code is full of stupid bugs. There is an infinite loop in which
two variables are assigned to themselves. Rubbish. However the C++
compiler is eliding the loop I think because I get a SIGILL not a hang.
That would seem to be because it is trying to call str on an uninitialised
variable.

The addition isn’t performed at all.

The _repr_ function is just an identity function and should be thrown out,
that is, _repr_ x should be just x. It looks like the whole expression is thrown out.

The y and *_x variables there are in fact the arguments to the + function,
0.3 and 42. Presumably the urv variable is the result.




John Skaller
ska...@internode.on.net





John Skaller2

unread,
May 1, 2019, 9:06:35 PM5/1/19
to felix google
OMG. I have found the problem. It’s NOT a compiler bug.

open Str[double];
fun sd (x:double) => x.str;
open class A {
type mydouble = new double;
ctor mydouble : int = "(double)$1";
supertype mydouble (x:int) => x.mydouble;
supertype mydouble : double = "$1";

fun + (x:mydouble, y:mydouble) => (x._repr_ + y._repr_) :>> mydouble;

instance Str[mydouble] { fun str (x:mydouble) => x._repr_.sd; }
}

var r = 42.mydouble + 0.3;
println$ r;

Recall, + disappears and is replaced by an infinite loop.

The reason is SUBTLE! But the compiler is correct.

My theory was, x._repr_ + y._repr_ would invoke fun +: double * double -> double.

But it doesn’t! It invokes itself. It can do that, because there is a coercion
from double to mydouble! Although the double * double signature is a better match,
it is shadowed! In Felix .. UNLIKE C++ which sucks totally … if a match is not found
for an overload in a scope, Felix tries the enclosing scope. Without the implicit
conversion from double to mydouble, a match would not be found. But with the
conversion, it matches. So it doesn’t try for a better match in the enclosing scope.

Its a bug .. in the test case!

Because it is recursive .. it also explains why Felix cannot deternine the return type,
Because its an infinite loop and never returns.



John Skaller
ska...@internode.on.net





Reply all
Reply to author
Forward
0 new messages