various fixes in type checker

This commit is contained in:
Nicolas Cannasse
2019-11-26 14:34:15 +01:00
parent 54463b78d2
commit 965f334d59
+102 -11
View File
@@ -23,6 +23,7 @@ enum TType {
TAbstract( a : CAbstract, args : Array<TType> );
TFun( args : Array<{ name : String, opt : Bool, t : TType }>, ret : TType );
TAnon( fields : Array<{ name : String, opt : Bool, t : TType }> );
TLazy( f : Void -> TType );
}
private enum WithType {
@@ -68,6 +69,7 @@ typedef CTypedef = {> CNamedType,
}
typedef CAbstract = {> CNamedType,
var t : TType;
}
class Completion {
@@ -193,11 +195,13 @@ class CheckerTypes {
var ta : CAbstract = {
name : a.path,
params : [],
t : null,
};
for( p in a.params )
ta.params.push(TParam(p));
todo.push(function() {
localParams = [for( t in ta.params ) a.path+"."+Checker.typeStr(t) => t];
ta.t = makeXmlType(a.athis);
localParams = null;
});
types.set(a.path, CTAbstract(ta));
@@ -234,8 +238,18 @@ class CheckerTypes {
if( t != null ) return t;
}
var t = resolve(name,args);
if( t == null )
if( t == null ) {
var pack = name.split(".");
if( pack.length > 1 ) {
// bugfix for some args reported as pack._Name.Name while they are not private
var priv = pack[pack.length-2];
if( priv.charCodeAt(0) == "_".code ) {
pack.remove(priv);
return getType(pack.join("."), args);
}
}
return TUnresolved(name); // most likely private class
}
return t;
}
@@ -266,14 +280,23 @@ class Checker {
var events : Map<String,TType> = new Map();
var currentFunType : TType;
var isCompletion : Bool;
var allowDefine : Bool;
public var allowAsync : Bool;
public var allowReturn : Null<TType>;
public var allowGlobalsDefine : Bool;
public var allowUntypedMeta : Bool;
public function new( ?types ) {
if( types == null ) types = new CheckerTypes();
this.types = types;
}
public function setGlobals( cl : CClass ) {
for( f in cl.fields )
if( f.isPublic )
setGlobal(f.name, f.params.length == 0 ? f.t : TLazy(() -> apply(f.t,f.params,[for( i in 0...f.params.length) makeMono()])));
}
public function removeGlobal( name : String ) {
globals.remove(name);
}
@@ -301,12 +324,19 @@ class Checker {
public function check( expr : Expr, ?withType : WithType, ?isCompletion = false ) {
if( withType == null ) withType = NoValue;
locals = new Map();
allowDefine = allowGlobalsDefine;
this.isCompletion = isCompletion;
switch( edef(expr) ) {
case EBlock(el):
var delayed = [];
var last = TVoid;
for( e in el )
for( e in el ) {
while( true ) {
switch( edef(e) ) {
case EMeta(_,_,e2): e = e2;
default: break;
}
}
switch( edef(e) ) {
case EFunction(args,_,name,ret) if( name != null ):
var tret = ret == null ? makeMono() : makeType(ret, e);
@@ -325,6 +355,7 @@ class Checker {
else
typeExpr(e, NoValue);
}
}
for( f in delayed )
last = f();
return last;
@@ -354,7 +385,7 @@ class Checker {
function makeType( t : CType, e : Expr ) : TType {
return switch (t) {
case CTPath(path, params):
var ct = types.resolve(path.join("."),params == null ? [] : [for( p in params ) makeType(t,e)]);
var ct = types.resolve(path.join("."),params == null ? [] : [for( p in params ) makeType(p,e)]);
if( ct == null ) {
error("Unknown type "+path, e);
ct = TDynamic;
@@ -573,6 +604,25 @@ class Checker {
if( !typeEq(pl1[i],pl2[i]) )
return false;
return true;
case [TInst(cl1,pl1),TAnon(fl)]:
for( i in 0...fl.length ) {
var f2 = fl[i];
var f1 = null;
var cl = cl1;
while( true ) {
f1 = cl.fields.get(f2.name);
if( f1 != null ) break;
if( cl.superClass == null )
return false;
cl = switch( cl.superClass ) {
case TInst(c,_): c;
default: throw "assert";
}
}
if( !typeEq(f1.t,f2.t) )
return false;
}
return true;
case [TInt, TFloat]:
return true;
case [TFun(_), TAbstract({ name : "haxe.Function" },_)]:
@@ -625,6 +675,8 @@ class Checker {
return TFun([for( a in args ) { name : a.name, opt : a.opt, t : f(a.t) }], f(ret));
case TAnon(fields):
return TAnon([for( af in fields ) { name : af.name, opt : af.opt, t : f(af.t) }]);
case TLazy(l):
return f(l());
}
}
@@ -633,6 +685,7 @@ class Checker {
case TMono(r): if( r.r != null ) follow(r.r) else t;
case TType(t,args): apply(t.t, t.params, args);
case TNull(t): follow(t);
case TLazy(f): f();
default: t;
}
}
@@ -678,7 +731,9 @@ class Checker {
}
if( !cf.isPublic )
error("Can't access private field "+f+" on "+c.name, e);
return apply(cf.t, c.params, args);
var t = cf.t;
if( cf.params != null ) t = apply(t, cf.params, [for( i in 0...cf.params.length ) makeMono()]);
return apply(t, c.params, args);
case TDynamic:
return makeMono();
case TAnon(fields):
@@ -752,7 +807,12 @@ class Checker {
var l = locals.get(v);
if( l != null ) return l;
var g = globals.get(v);
if( g != null ) return g;
if( g != null ) {
return switch( g ) {
case TLazy(f): f();
default: g;
}
}
if( allowAsync ) {
g = globals.get("a_"+v);
if( g != null ) g = unasync(g);
@@ -792,7 +852,10 @@ class Checker {
case TFun(args, ret):
for( i in 0...params.length ) {
var a = args[i];
if( a == null ) error("Too many arguments", params[i]);
if( a == null ) {
error("Too many arguments", params[i]);
break;
}
var t = typeExpr(params[i], a == null ? Value : WithType(a.t));
unify(t, a.t, params[i]);
}
@@ -822,7 +885,9 @@ class Checker {
var vt = typeExpr(v, WithType(ct));
unify(vt, ct, v);
return ct;
case EMeta(_, _, e):
case EMeta(m, _, e):
if( m == ":untyped" && allowUntypedMeta )
return makeMono();
return typeExpr(e, withType);
case EIf(cond, e1, e2), ETernary(cond, e1, e2):
typeExprWith(cond, TBool);
@@ -873,7 +938,7 @@ class Checker {
if( tryUnify(et,t) ) et = t else unify(t,et,v);
}
}
if( et == null ) et = TDynamic;
if( et == null ) et = makeMono();
return types.getType("Array",[et]);
case EArray(a, index):
typeExprWith(index, TInt);
@@ -901,7 +966,9 @@ class Checker {
}
var locals = saveLocals();
var oldRet = allowReturn;
var oldGDef = allowDefine;
allowReturn = tret;
allowDefine = false;
var withArgs = null;
if( name != null && !withType.match(WithType(follow(_) => TFun(_))) ) {
var ev = events.get(name);
@@ -920,6 +987,7 @@ class Checker {
this.locals.set(a.name, a.t);
}
typeExpr(body,NoValue);
allowDefine = oldGDef;
allowReturn = oldRet;
this.locals = locals;
if( ft == null ) {
@@ -945,13 +1013,27 @@ class Checker {
case TInst({name:"Array"},[t]):
t;
default:
var ft = getField(itt,"iterator", it);
if( ft == null )
switch( itt ) {
case TAbstract(a, args):
// special case : we allow unconditional access
// to an abstract iterator() underlying value (eg: ArrayProxy)
ft = getField(apply(a.t,a.params,args),"iterator",it);
default:
}
if( ft != null )
switch( ft ) {
case TFun([],ret): ft = ret;
default: ft = null;
}
var t = makeMono();
var iter = makeIterator(t);
unify(itt,iter,it);
unify(ft != null ? ft : itt,iter,it);
t;
}
this.locals.set(v, vt);
typeExpr(e, Value);
typeExpr(e, NoValue);
this.locals = locals;
return TVoid;
case EBinop(op, e1, e2):
@@ -961,6 +1043,15 @@ class Checker {
typeExprWith(e2,TInt);
return TInt;
case "=":
if( allowDefine ) {
switch( edef(e1) ) {
case EIdent(i) if( !locals.exists(i) && !globals.exists(i) ):
var vt = typeExpr(e2,Value);
locals.set(i, vt);
return vt;
default:
}
}
var vt = typeExpr(e1, Value);
typeExprWith(e2,vt);
return vt;
@@ -1058,7 +1149,7 @@ class Checker {
for( c in cases ) {
for( v in c.values ) {
var ct = typeExpr(v, WithType(vt));
unify(vt, ct, v);
unify(ct, vt, v);
}
var et = typeExpr(c.expr, withType);
mergeType(et, c.expr);