in base/src/main/java/org/arend/core/definition/CoerceData.java [95:179]
public static TypecheckingResult coerce(TypecheckingResult result, Expression expectedType, Concrete.SourceNode sourceNode, CheckTypeVisitor visitor) {
DefCallExpression actualDefCall = result.type.cast(DefCallExpression.class);
DefCallExpression expectedDefCall = expectedType.cast(DefCallExpression.class);
if (actualDefCall != null && expectedDefCall != null && (actualDefCall.getDefinition() == expectedDefCall.getDefinition() || actualDefCall.getDefinition() instanceof ClassDefinition && expectedDefCall.getDefinition() instanceof ClassDefinition && ((ClassDefinition) actualDefCall.getDefinition()).isSubClassOf((ClassDefinition) expectedDefCall.getDefinition()))) {
return null;
}
CoerceData actualCoerceData = actualDefCall != null ? actualDefCall.getDefinition().getCoerceData() : null;
if (actualCoerceData != null && actualCoerceData.myMapTo.isEmpty()) {
actualCoerceData = null;
}
CoerceData expectedCoerceData = expectedDefCall != null ? expectedDefCall.getDefinition().getCoerceData() : null;
if (expectedCoerceData != null && expectedCoerceData.myMapFrom.isEmpty()) {
expectedCoerceData = null;
}
ClassCallExpression classCall = actualDefCall instanceof ClassCallExpression ? (ClassCallExpression) actualDefCall : null;
if (classCall != null && classCall.getDefinition().getClassifyingField() == null) classCall = null;
if (actualCoerceData == null && expectedCoerceData == null && classCall == null) {
return null;
}
Key actualKey = getKey(result.type);
Key originalExpectedKey = getKey(expectedType);
Key expectedKey = originalExpectedKey;
// Coerce from a definition
if (expectedCoerceData != null && !(actualKey instanceof AnyKey)) {
List<Definition> defs = expectedCoerceData.myMapFrom.get(actualKey);
if (defs != null) {
return coerceResult(result, defs, expectedType, sourceNode, visitor, false, false);
}
}
// Coerce to a definition
if (actualCoerceData != null && !(expectedKey instanceof AnyKey)) {
List<Definition> defs = actualCoerceData.myMapTo.get(expectedKey);
if (defs != null) {
return coerceResult(result, defs, expectedType, sourceNode, visitor, false, false);
}
}
// Can't coerce from or to a definition
if (expectedCoerceData != null && !(actualKey instanceof AnyKey)) {
actualKey = new AnyKey();
}
if (actualCoerceData != null && !(expectedKey instanceof AnyKey)) {
expectedKey = new AnyKey();
}
// Coerce from an arbitrary type
if (expectedCoerceData != null) {
List<Definition> defs = expectedCoerceData.myMapFrom.get(actualKey);
if (defs != null) {
return coerceResult(result, defs, expectedType, sourceNode, visitor, true, false);
}
}
// Coerce to an arbitrary type
if (actualCoerceData != null) {
List<Definition> defs = actualCoerceData.myMapTo.get(expectedKey);
if (defs != null) {
TypecheckingResult tcResult = coerceResult(result, defs, expectedType, sourceNode, visitor, false, true);
if (tcResult != null) return tcResult;
}
}
// Coerce using classifying field
if (classCall != null) {
List<Definition> defs = new ArrayList<>();
while (true) {
ClassField classifyingField = classCall.getDefinition().getClassifyingField();
if (classifyingField == null) break;
defs.add(classifyingField);
Expression type = getClassifyingFieldType(classCall);
Key key = getKey(type);
if (key.equals(originalExpectedKey)) {
return coerceResult(result, defs, expectedType, sourceNode, visitor, false, originalExpectedKey instanceof AnyKey);
}
if (!(type instanceof ClassCallExpression)) break;
classCall = (ClassCallExpression) type;
}
}
// Can't coerce
return null;
}