iets3.opensource
iets3.opensource copied to clipboard
Issue with comparing types in case of sets with units
In a customer project, we have a issue with types related to comparing types when the type is a set<set<number
It looks like a set of set of numbers with units is not correctly matched to its type, but it is rather matched to a sort of interval.
In short, the function computeSupertype (in SimpleTypesPrimitiveTypeMapper) is not working as expected forthe function computeSupertype (in SimpleTypesPrimitiveTypeMapper) is not working as expected for this case.
Let's consider the iets3 open source code for the method:
@Override
public node<> computeSupertype(nlist<> types, boolean goToInfinity, SubtypingManager mgr) {
nlist<NumberType> numberTypes = types.ofConcept<NumberType>.toList;
nlist<TupleType> tupleTypes = types.ofConcept<TupleType>.toList;
nlist<> resultTypes = types.except(numberTypes).except(tupleTypes).toList;
nlist<> resultTupleTypes = new nlist<>;
if (tupleTypes.size > 0) {
resultTupleTypes.addAll(computeSupertypeOfTuples(tupleTypes, goToInfinity, mgr));
}
if (numberTypes.size > 0) {
resultTypes.add(computeSupertypeOfNumberTypes(numberTypes, goToInfinity));
}
// The next part is a hack:
// Because mgr.leastCommonSupertypes(set, false) does only operate on sets containing 2 elements,
// we need to extract the elements from resultTypes and pass them to the function successively.
// s.a.: https://youtrack.jetbrains.com/issue/MPSI-45/leastCommonSupertypes-does-not-calculate-correctly-on-tuples-with-multiple-values
set<node<>> set = new hashset<node<>>;
set.add(resultTypes.first);
foreach type in resultTypes.where({~it => it != resultTypes.first; }) {
set.add(type);
Set<SNode> least = mgr.leastCommonSupertypes(set, false);
set.clear;
least.removeIf({SNode nn => nn.getConcept().isAbstract(); });
// No common supertype available:
if (least.isEmpty()) { break; }
// More than one supertype should never occur:
if (least.size() > 1) {
// fall back to join-Type
break;
} else {
set.addAll(least);
}
}
// END OF the hack.
// Now the set contains the supertype as only element if there is one.
node<JoinType> jt = new node<JoinType>();
if (set.size == 1) {
jt.types.add(set.iterator.next as Type);
} else {
jt.types.addAll(resultTypes.ofConcept<Type>);
}
if (resultTupleTypes.size > 0) {
jt.types.addAll(resultTupleTypes.ofConcept<Type>);
}
if (jt.types.size == 1) {
return jt.types.first;
} else {
return jt;
}
}
And now, we consider how it works in this specific case:
set<set<number<m>>> input13 : default set(set(1 m, 2 m), set(2 m, 4 m)) optional false
The problem, in our case, is that
- we would expect to have a
set<set<number{0}<SIUnits.m>>>
, - while we get a
set<join<[set<number[1|2]{0}<SIUnits.m>>, set<number[2|4]{0}<SIUnits.m>>]>>
For our case, looking at the code in the computeSupertype we observe the following:
-
set<node<>> set = new hashset<node<>>;
starts with a new set - then we add
resultTypes.first
to the set. In this caseset(1 m, 2 m)
- and then, for each type in resultType which is different w.r.t. the first result type, we add the type to the set
Now, I believe the problem lies in how the .where({~it => it != resultTypes.first; })
is unable to compare the types.
Indeed, in our case, we return a join type.
To me looks like the solution is refactoring the type-equality condition.