Better type comparison (closes #25)

This commit is contained in:
Kevin Leung
2019-05-13 17:01:54 +08:00
parent 77973f6007
commit 00640d8328
2 changed files with 107 additions and 12 deletions

View File

@@ -252,11 +252,97 @@ class Types {
t2 = t2.reduce();
}
return switch t1.getIndex() - t2.getIndex() {
case 0:
Reflect.compare(t1.toString(), t2.toString());//much to my surprise, this actually seems to work (at least with 3.4)
return switch [t1, t2] {
case [TMono(_.get() => t1), TMono(_.get() => t2)]:
switch [t1, t2] {
case [null, null]: 0;
case [null, _]: -1;
case [_, null]: 1;
case _: compare(t1, t2, follow);
}
case [TInst(c1, p1), TInst(c2, p2)]:
switch Reflect.compare(c1.toString(), c2.toString()) {
case 0: compareMultiple(p1, p2, follow);
case v: v;
}
case [TType(_.get() => {type: t1}, p1), TType(_.get() => {type: t2}, p2)]:
switch compare(t1, t2) {
case 0: compareMultiple(p1, p2);
case v: v;
}
case [TFun(a1, r1), TFun(a2, r2)]:
switch compare(r1, r2) {
case 0: compareMultiple([for(a in a1) a.t], [for(a in a2) a.t]);
case v: v;
}
case [TAnonymous(_.get() => {fields: f1}), TAnonymous(_.get() => {fields: f2})]:
switch [f1.length, f2.length] {
case [l1, l2] if(l1 == l2):
f1.sort(function(f1, f2) return Reflect.compare(f1.name, f2.name));
f2.sort(function(f1, f2) return Reflect.compare(f1.name, f2.name));
compareArray(f1, f2, compareClassField);
case [l1, l2]:
l1 - l2;
}
case [TDynamic(null), TDynamic(null)]:
0;
case [TDynamic(null), TDynamic(_)]:
1;
case [TDynamic(_), TDynamic(null)]:
-1;
case [TDynamic(t1), TDynamic(t2)]:
compare(t1, t2);
case [TLazy(f1), TLazy(f2)]:
compare(f1(), f2());
case _:
t1.getIndex() - t2.getIndex();
}
}
static function compareClassField(f1:ClassField, f2:ClassField) {
return switch Reflect.compare(f1.name, f2.name) {
case 0:
switch compare(f1.type, f2.type) {
case 0:
var m1 = [for(m in f1.meta.get()) m.toString()];
var m2 = [for(m in f2.meta.get()) m.toString()];
m1.sort(Reflect.compare);
m2.sort(Reflect.compare);
compareArray(m1, m2, function(m1, m2) return Reflect.compare(m1, m2));
case v: v;
}
case v: v;
}
}
}
static function compareMeta(m1:MetadataEntry, m2:MetadataEntry) {
return switch Reflect.compare(m1.name, m2.name) {
case 0: compareArray(m1.params, m2.params, function(e1, e2) return Reflect.compare(e1.toString(), e2.toString()));
case v: v;
}
}
static function compareArray<T>(a1:Array<T>, a2:Array<T>, compare:T->T->Int) {
return switch [a1.length, a2.length] {
case [l1, l2] if(l1 == l2):
for(i in 0...l1) {
switch compare(a1[i], a2[i]) {
case 0: // skip
case v: return v;
}
}
0;
case [l1, l2]:
l1 - l2;
}
}
static function compareMultiple(t1:Array<Type>, t2:Array<Type>, follow = true) {
return compareArray(t1, t2, function(t1, t2) return compare(t1, t2, follow));
}
static var SUGGESTIONS = ~/ \(Suggestions?: .*\)$/;