in base/src/main/java/org/arend/typechecking/UseTypechecking.java [135:248]
public static ParametersLevel typecheckLevel(Concrete.UseDefinition def, FunctionDefinition typedDef, Definition useParent, ErrorReporter errorReporter) {
if (!(useParent instanceof DataDefinition || useParent instanceof ClassDefinition || useParent instanceof FunctionDefinition)) {
return null;
}
Expression resultType = def == null || def.getResultType() != null ? typedDef.getResultType() : null;
boolean ok = true;
List<ClassField> levelFields = null;
List<Pair<ClassDefinition, Set<ClassField>>> strictList = null;
Expression type = null;
DependentLink parameters = null;
DependentLink link = typedDef.getParameters();
if (useParent instanceof DataDefinition || useParent instanceof FunctionDefinition) {
ExprSubstitution substitution = new ExprSubstitution();
List<Expression> defCallArgs = new ArrayList<>();
for (DependentLink defLink = useParent.getParameters(); defLink.hasNext(); defLink = defLink.getNext(), link = link.getNext()) {
if (!link.hasNext()) {
ok = false;
break;
}
if (!Expression.compare(link.getTypeExpr(), defLink.getTypeExpr().subst(substitution), Type.OMEGA, CMP.EQ)) {
if (parameters == null) {
parameters = DependentLink.Helper.take(typedDef.getParameters(), DependentLink.Helper.size(defLink));
}
}
ReferenceExpression refExpr = new ReferenceExpression(link);
defCallArgs.add(refExpr);
substitution.add(defLink, refExpr);
}
if (ok) {
if (link.hasNext() || resultType != null) {
type = useParent instanceof DataDefinition
? DataCallExpression.make((DataDefinition) useParent, useParent.makeIdLevels(), defCallArgs)
: FunCallExpression.make((FunctionDefinition) useParent, useParent.makeIdLevels(), defCallArgs);
} else {
ok = false;
}
}
} else {
ClassCallExpression classCall = null;
DependentLink classCallLink = link;
for (; classCallLink.hasNext(); classCallLink = classCallLink.getNext()) {
classCallLink = classCallLink.getNextTyped(null);
classCall = classCallLink.getTypeExpr().cast(ClassCallExpression.class);
if (classCall != null && classCall.getDefinition() == useParent && (classCall.getUniverseKind() == UniverseKind.NO_UNIVERSES || typedDef.isIdLevels(classCall.getLevels()))) {
break;
}
}
if (!classCallLink.hasNext() && resultType != null) {
PiExpression piType = resultType.normalize(NormalizationMode.WHNF).cast(PiExpression.class);
if (piType != null) {
classCall = piType.getParameters().getTypeExpr().normalize(NormalizationMode.WHNF).cast(ClassCallExpression.class);
if (classCall != null && classCall.getDefinition() == useParent && (classCall.getUniverseKind() == UniverseKind.NO_UNIVERSES || typedDef.isIdLevels(classCall.getLevels()))) {
classCallLink = piType.getParameters();
}
}
}
if (classCall == null || !classCallLink.hasNext()) {
ok = false;
} else {
if (!classCall.getImplementedHere().isEmpty()) {
levelFields = new ArrayList<>();
strictList = new ArrayList<>();
Expression thisExpr = new ReferenceExpression(classCallLink);
for (Map.Entry<ClassField, Expression> entry : classCall.getImplementedHere().entrySet()) {
ClassField classField = entry.getKey();
if (classField.isProperty()) {
continue;
}
if (!(link.hasNext() && entry.getValue() instanceof ReferenceExpression && ((ReferenceExpression) entry.getValue()).getBinding() == link)) {
ok = false;
break;
}
levelFields.add(classField);
Expression fieldType = classCall.getDefinition().getFieldType(classField, classCall.getLevels(classField.getParentClass()), thisExpr);
Expression paramType = link.getTypeExpr();
if (!Expression.compare(fieldType, paramType, Type.OMEGA, CMP.EQ)) {
if (parameters == null) {
int numberOfClassParameters = 0;
for (DependentLink link1 = link; link1 != classCallLink && link1.hasNext(); link1 = link1.getNext()) {
numberOfClassParameters++;
}
parameters = DependentLink.Helper.take(typedDef.getParameters(), numberOfClassParameters);
}
ClassCallExpression fieldClassCall = fieldType.cast(ClassCallExpression.class);
ClassCallExpression paramClassCall = paramType.cast(ClassCallExpression.class);
if (strictList != null && paramClassCall != null && fieldClassCall != null && paramClassCall.getDefinition().isSubClassOf(fieldClassCall.getDefinition()) && paramClassCall.getLevels(fieldClassCall.getDefinition()).equals(fieldClassCall.getLevels()) && paramClassCall.getUniverseKind().ordinal() <= fieldClassCall.getUniverseKind().ordinal()) {
strictList.add(new Pair<>(paramClassCall.getDefinition(), paramClassCall.getImplementedHere().keySet()));
} else {
strictList = null;
}
} else if (strictList != null) {
strictList.add(null);
}
link = link.getNext();
}
}
type = classCall;
}
}
Integer level = CheckTypeVisitor.getExpressionLevel(link, resultType, ok ? type : null, DummyEquations.getInstance(), def, errorReporter);
if (level == null) {
return null;
}
if (def != null && useParent instanceof DataDefinition && parameters == null && Level.compare(((DataDefinition) useParent).getSort().getHLevel(), new Level(level), CMP.LE, DummyEquations.getInstance(), def)) {
errorReporter.report(new CertainTypecheckingError(CertainTypecheckingError.Kind.USELESS_LEVEL, def));
}
return useParent instanceof ClassDefinition ? new ClassDefinition.ParametersLevel(parameters, level, levelFields, strictList) : new ParametersLevel(parameters, level);
}