iets3.opensource icon indicating copy to clipboard operation
iets3.opensource copied to clipboard

Issue with comparing types in case of sets with units

Open psuzzi opened this issue 5 months ago • 1 comments

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.

image

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 case set(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.

psuzzi avatar Sep 17 '24 12:09 psuzzi