more typing

This commit is contained in:
ncannasse
2018-09-20 18:21:17 +02:00
parent e407b2a307
commit 56ddc3c24e
+203 -7
View File
@@ -164,19 +164,19 @@ class CheckerTypes {
types.set(t.path, CTTypedef(td));
case TAbstractdecl(a):
if( types.exists(a.path) ) return;
var td : CTypedef = {
var td : CEnum = {
name : a.path,
params : [],
t : null,
constructors : new Map(),
};
for( p in a.params )
td.params.push(TParam(p));
todo.push(function() {
localParams = [for( t in td.params ) a.path+"."+Checker.typeStr(t) => t];
td.t = makeXmlType(a.athis);
//td.t = makeXmlType(a.athis);
localParams = null;
});
types.set(a.path, CTTypedef(td));
types.set(a.path, CTEnum(td));
}
}
@@ -238,6 +238,7 @@ class Checker {
public var types : CheckerTypes;
var locals : Map<String,TType>;
var globals : Map<String,TType> = new Map();
var events : Map<String,TType> = new Map();
public var allowAsync : Bool;
public var allowReturn : Null<TType>;
@@ -250,6 +251,10 @@ class Checker {
globals.set(name, type);
}
public function setEvent( name : String, type : TType ) {
events.set(name, type);
}
public function getGlobals() {
return globals;
}
@@ -295,7 +300,7 @@ class Checker {
}
public static function typeStr( t : TType ) {
inline function makeArgs(args:Array<TType>) return args.length==0 ? "" : "<"+[for( a in args ) typeStr(t)].join(",")+">";
inline function makeArgs(args:Array<TType>) return args.length==0 ? "" : "<"+[for( t in args ) typeStr(t)].join(",")+">";
return switch (t) {
case TMono(r): r.r == null ? "Unknown" : typeStr(r.r);
case TInst(c, args): c.name + makeArgs(args);
@@ -310,18 +315,61 @@ class Checker {
}
}
function linkLoop( a : TType, t : TType ) {
if( t == a ) return true;
switch( t ) {
case TMono(r):
if( r.r == null ) return false;
return linkLoop(a,r.r);
case TEnum(_,tl), TInst(_,tl), TType(_,tl):
for( t in tl )
if( linkLoop(a,t) )
return true;
return false;
case TFun(args,ret):
for( arg in args )
if( linkLoop(a,arg.t) )
return true;
return linkLoop(a,ret);
case TDynamic:
if( t == TDynamic )
return false;
return linkLoop(a,TDynamic);
case TAnon(fl):
for( f in fl )
if( linkLoop(a, f.t) )
return true;
return false;
default:
return false;
}
}
function link( a : TType, b : TType, r : { r : TType } ) {
if( linkLoop(a,b) )
return follow(b) == a;
if( b == TDynamic )
return true;
r.r = b;
return true;
}
function typeEq( t1 : TType, t2 : TType ) {
if( t1 == t2 )
return true;
switch( [t1,t2] ) {
case [TMono(r), _]:
if( r.r == null ) {
if( !link(t1,t2,r) )
return false;
r.r = t2;
return true;
}
return typeEq(r.r, t2);
case [_, TMono(r)]:
if( r.r == null ) {
if( !link(t2,t1,r) )
return false;
r.r = t1;
return true;
}
@@ -374,12 +422,16 @@ class Checker {
switch( [t1,t2] ) {
case [TMono(r), _]:
if( r.r == null ) {
if( !link(t1,t2,r) )
return false;
r.r = t2;
return true;
}
return tryUnify(r.r, t2);
case [_, TMono(r)]:
if( r.r == null ) {
if( !link(t2,t1,r) )
return false;
r.r = t1;
return true;
}
@@ -414,6 +466,19 @@ class Checker {
return true;
case [TDynamic, _]:
return true;
case [TAnon(a1),TAnon(a2)]:
var m = new Map();
for( f in a1 )
m.set(f.name, f);
for( f2 in a2 ) {
var f1 = m.get(f2.name);
if( f1 == null ) return false;
if( !typeEq(f1.t,f2.t) )
return false;
}
return true;
case [TInt, TFloat]:
return true;
default:
}
return false;
@@ -439,6 +504,27 @@ class Checker {
}
}
public function getFields( t : TType ) {
var fields = [];
while( t != null ) {
t = follow(t);
switch( t ) {
case TInst(c, args):
for( fname in c.fields.keys() ) {
var f = c.fields.get(fname);
fields.push({ name : f.name, t : f.t });
}
t = c.superClass;
case TAnon(fl):
for( f in fl )
fields.push({ name : f.name, t : f.t });
break;
default:
}
}
return fields;
}
function getField( t : TType, f : String, e : Expr ) {
switch( follow(t) ) {
case TInst(c, args):
@@ -494,6 +580,23 @@ class Checker {
return TMono({r:null});
}
function makeIterator(t) : TType {
return TAnon([{ name : "next", opt : false, t : TFun([],t) }, { name : "hasNext", opt : false, t : TFun([],TBool) }]);
}
function mk(e,p) : Expr {
#if hscriptPos
return { e : e, pmin : p.pmin, pmax : p.pmax, origin : p.origin, line : p.line };
#else
return e;
#end
}
function isString( t : TType ) {
t = follow(t);
return t.match(TInst({name:"String"},_));
}
function typeExpr( expr : Expr, withType : WithType ) : TType {
switch( edef(expr) ) {
case EConst(c):
@@ -619,8 +722,12 @@ class Checker {
var oldRet = allowReturn;
allowReturn = tret;
var withArgs = null;
if( name != null && !withType.match(WithType(follow(_) => TFun(_))) ) {
var ev = events.get(name);
if( ev != null ) withType = WithType(ev);
}
switch( withType ) {
case WithType(TFun(args, ret)): withArgs = args; unify(tret,ret,expr);
case WithType(follow(_) => TFun(args,ret)): withArgs = args; unify(tret,ret,expr);
default:
}
var targs = [for( i in 0...args.length ) {
@@ -631,6 +738,7 @@ class Checker {
this.locals.set(a.name, at);
{ name : a.name, opt : a.opt, t : at };
}];
typeExpr(body,NoValue);
allowReturn = oldRet;
this.locals = locals;
@@ -649,8 +757,96 @@ class Checker {
return et;
default:
}
case EBinop(op, e1, e2):
case EFor(v, it, e):
var locals = saveLocals();
var itt = typeExpr(it, Value);
var vt = switch( follow(itt) ) {
case TInst({name:"Array"},[t]):
t;
default:
var t = makeMono();
var iter = makeIterator(t);
unify(itt,iter,it);
t;
}
this.locals.set(v, vt);
typeExpr(e, Value);
this.locals = locals;
return TVoid;
case EBinop(op, e1, e2):
switch( op ) {
case "&", "|", "^", ">>", ">>>", "<<":
typeExprWith(e1,TInt);
typeExprWith(e2,TInt);
return TInt;
case "=":
var vt = typeExpr(e1, Value);
typeExprWith(e2,vt);
return vt;
case "+":
var t1 = typeExpr(e1,WithType(TInt));
var t2 = typeExpr(e2,WithType(t1));
tryUnify(t1,t2);
switch( [follow(t1), follow(t2)]) {
case [TInt, TInt]:
return TInt;
case [TFloat, TInt], [TInt, TFloat], [TFloat, TFloat]:
return TFloat;
case [TDynamic, _], [_, TDynamic]:
return TDynamic;
case [t1,t2]:
if( isString(t1) || isString(t2) )
return types.t_string;
unify(t1, TFloat, e1);
unify(t2, TFloat, e2);
}
case "-", "*", "/":
var t1 = typeExpr(e1,WithType(TInt));
var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) )
unify(t2,t1,e2);
switch( [follow(t1), follow(t2)]) {
case [TInt, TInt]:
if( op == "/" ) return TFloat;
return TInt;
case [TFloat|TDynamic, TInt|TDynamic], [TInt|TDynamic, TFloat|TDynamic], [TFloat, TFloat]:
return TFloat;
default:
unify(t1, TFloat, e1);
unify(t2, TFloat, e2);
}
case "&&", "||":
typeExprWith(e1,TBool);
typeExprWith(e2,TBool);
return TBool;
case "...":
typeExprWith(e1,TInt);
typeExprWith(e2,TInt);
return makeIterator(TInt);
case "==", "!=":
var t1 = typeExpr(e1,Value);
var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) )
unify(t2,t1,e2);
return TBool;
case ">", "<", ">=", "<=":
var t1 = typeExpr(e1,Value);
var t2 = typeExpr(e2,WithType(t1));
if( !tryUnify(t1,t2) )
unify(t2,t1,e2);
switch( follow(t1) ) {
case TInt, TFloat, TBool, TInst({name:"String"},_):
default:
error("Cannot compare "+typeStr(t1), expr);
}
return TBool;
default:
if( op.charCodeAt(op.length-1) == "=".code ) {
var t = typeExpr(mk(EBinop(op.substr(0,op.length-1),e1,e2),expr),withType);
return typeExpr(mk(EBinop("=",e1,e2),expr), withType);
}
error("Unsupported operation "+op, expr);
}
case ENew(cl, params):
case ETry(e, v, t, ecatch):
case ESwitch(e, cases, defaultExpr):