package de.skuzzle.polly.core.parser.ast.declarations.types.unification;
import java.util.HashMap;
import java.util.Map;
import de.skuzzle.polly.core.parser.ast.declarations.types.Substitution;
import de.skuzzle.polly.core.parser.ast.declarations.types.Type;
import de.skuzzle.polly.core.parser.ast.declarations.types.TypeVar;
class UnionFindTypeUnifier extends AbstractUnifier {
private final Map<Type, UnionFindItem<Type>> types;
public UnionFindTypeUnifier(boolean subTypeIncl) {
super(subTypeIncl);
this.types = new HashMap<>();
}
/**
* Tests for structural equality of the given type expression in the context of this
* unifier instance.
*
* @param first First type to check.
* @param second Second type to check.
* @return A substitution for the type variables in first and second or
* <code>null</code> if unification was not successful.
*/
@Override
public Substitution unify(Type first, Type second) {
final Map<TypeVar, Type> subst = new HashMap<TypeVar, Type>();
if (!unifyInternal(first, second, subst)) {
return null;
}
return new Substitution(subst);
}
/**
* Tests for structural equality of the two given type expressions.
*
* @param first First type.
* @param second Second type.
* @return Whether the first type is an instance of the second type
*/
@Override
public boolean tryUnify(Type first, Type second) {
return this.unifyInternal(first, second, new HashMap<TypeVar, Type>());
}
@Override
protected Type find(Type type) {
UnionFindItem<Type> result = this.types.get(type);
if (result == null) {
result = new UnionFindItem<Type>(type);
}
result = result.root();
this.types.put(type, result);
return result.getValue();
}
@Override
public void union(Type s, Type t, Map<TypeVar, Type> subst) {
final UnionFindItem<Type> si = this.types.get(s).root();
final UnionFindItem<Type> ti = this.types.get(t).root();
final UnionFindItem<Type> rep = si.getValue() instanceof TypeVar ? ti : si;
final UnionFindItem<Type> other = rep == si ? ti : si;
other.mergeInto(rep);
if (other.getValue() instanceof TypeVar) {
subst.put((TypeVar) other.getValue(), rep.getValue());
}
}
}