in base/src/main/java/org/arend/typechecking/visitor/DefinitionTypechecker.java [1072:1212]
private boolean typecheckFunctionHeader(FunctionDefinition typedDef, Concrete.BaseFunctionDefinition def, LocalInstancePool localInstancePool) {
def.getData().setTypecheckedIfNotCancelled(typedDef);
if (myNewDef) {
typedDef.setParametersOriginalDefinitions(def.getParametersOriginalDefinitions());
}
if (def.enclosingClass != null) {
typedDef.setHasEnclosingClass(true);
}
ClassField implementedField = def instanceof Concrete.CoClauseFunctionDefinition ? typechecker.referableToClassField(((Concrete.CoClauseFunctionDefinition) def).getImplementedField(), def) : null;
FunctionKind kind = implementedField == null ? def.getKind() : implementedField.isProperty() && implementedField.getTypeLevel() == null ? FunctionKind.LEMMA : FunctionKind.FUNC;
checkFunctionLevel(def, kind);
if (def.isRecursive() && def.getResultType() == null && !(def.getBody() instanceof Concrete.ElimFunctionBody)) {
errorReporter.report(new TypecheckingError("The type of a recursive function must be specified explictly", def));
}
if (def.getKind() == FunctionKind.LEVEL) {
Definition useParent = def.getUseParent().getTypechecked();
if (def.getPLevelParameters() == null && useParent.hasNonTrivialPLevelParameters()) {
def.setPLevelParameters(Concrete.LevelParameters.makeLevelParameters(useParent.getLevelParameters().subList(0, useParent.getNumberOfPLevelParameters()), true));
}
if (def.getHLevelParameters() == null && useParent.hasNonTrivialHLevelParameters()) {
def.setHLevelParameters(Concrete.LevelParameters.makeLevelParameters(useParent.getLevelParameters().subList(useParent.getNumberOfPLevelParameters(), useParent.getLevelParameters().size()), false));
}
}
if (myNewDef) {
if (def.getKind() == FunctionKind.CLASS_COCLAUSE) {
Definition enclosingClass = def.enclosingClass.getTypechecked();
List<? extends LevelVariable> params = enclosingClass.getLevelParameters();
if (params != null) {
if (typedDef.getLevelParameters() == null) {
int n = enclosingClass.getNumberOfPLevelParameters();
Concrete.LevelParameters pLevelParams = levelVariablesToParameters(def.getData(), enclosingClass.getLevelParameters().subList(0, n), true);
Concrete.LevelParameters hLevelParams = levelVariablesToParameters(def.getData(), enclosingClass.getLevelParameters().subList(n, enclosingClass.getLevelParameters().size()), false);
def.setPLevelParameters(pLevelParams);
def.setHLevelParameters(hLevelParams);
if (!def.getParameters().isEmpty()) {
Concrete.Expression type = def.getParameters().get(0).getType();
if (type instanceof Concrete.ClassExtExpression) {
type = ((Concrete.ClassExtExpression) type).getBaseClassExpression();
}
if (type instanceof Concrete.ReferenceExpression refExpr) {
if (pLevelParams != null) {
refExpr.setPLevels(levelParametersToExpressions(refExpr.getData(), pLevelParams, LevelVariable.LvlType.PLVL));
}
if (hLevelParams != null) {
refExpr.setHLevels(levelParametersToExpressions(refExpr.getData(), hLevelParams, LevelVariable.LvlType.HLVL));
}
}
}
typedDef.setLevelParameters(typecheckLevelParameters(def));
typedDef.setPLevelsParent(enclosingClass.getPLevelsParent());
typedDef.setHLevelsParent(enclosingClass.getHLevelsParent());
} else {
boolean setPLevel = def.getPLevelParameters() == null && enclosingClass.hasNonTrivialPLevelParameters();
boolean setHLevel = def.getHLevelParameters() == null && enclosingClass.hasNonTrivialHLevelParameters();
if (setPLevel || setHLevel) {
List<LevelVariable> newParams = new ArrayList<>();
newParams.addAll(setPLevel ? enclosingClass.getLevelParameters().subList(0, enclosingClass.getNumberOfPLevelParameters()) : typedDef.getLevelParameters().subList(0, typedDef.getNumberOfPLevelParameters()));
newParams.addAll(setHLevel ? enclosingClass.getLevelParameters().subList(enclosingClass.getNumberOfPLevelParameters(), enclosingClass.getLevelParameters().size()) : typedDef.getLevelParameters().subList(typedDef.getNumberOfPLevelParameters(), typedDef.getLevelParameters().size()));
typedDef.setLevelParameters(newParams);
if (setPLevel) typedDef.setPLevelsParent(enclosingClass.getPLevelsParent());
if (setHLevel) typedDef.setHLevelsParent(enclosingClass.getHLevelsParent());
}
}
}
} else {
if (def.getKind().isUse()) {
Definition useParent = def.getUseParent().getTypechecked();
int n = useParent.getNumberOfPLevelParameters();
if (def.getPLevelParameters() != null) {
compareUseLevelParameters(def.getPLevelParameters(), levelVariablesToParameters(def.getPLevelParameters().getData(), useParent.getLevelParameters().subList(0, n), true));
}
if (def.getHLevelParameters() != null) {
compareUseLevelParameters(def.getHLevelParameters(), levelVariablesToParameters(def.getHLevelParameters().getData(), useParent.getLevelParameters().subList(n, useParent.getLevelParameters().size()), false));
}
}
findLevelsParentsInParameters(typedDef, def, def.getParameters());
typedDef.setLevelParameters(typecheckLevelParameters(def));
}
}
LinkList list = new LinkList();
Pair<Sort, Expression> pair = typecheckParameters(def, typedDef, list, localInstancePool, null, myNewDef ? null : typedDef.getParameters(), implementedField, null);
if (def.getBody() instanceof Concrete.CoelimFunctionBody || def.getBody() instanceof Concrete.ElimFunctionBody && def.getBody().getClauses().isEmpty()) {
checkNoStrictParameters(def.getParameters());
} else if (myNewDef) {
typedDef.setStrictParameters(getStrictParameters(def.getParameters()));
}
if (def.getKind() == FunctionKind.TYPE && def.getBody() instanceof Concrete.ElimFunctionBody && def.getResultType() == null) {
def.setResultType(new Concrete.UniverseExpression(def.getData(), null, null));
}
Expression expectedType = null;
Concrete.Expression cResultType = def.getResultType();
if (cResultType != null) {
Type expectedTypeResult = pair == null
? new ErrorExpression()
: def.getBody() instanceof Concrete.CoelimFunctionBody && !def.isRecursive()
? null // The result type will be typechecked together with all field implementations during body typechecking.
: checkResultTypeLater(def)
? typechecker.checkType(cResultType, Type.OMEGA)
: typechecker.finalCheckType(cResultType, Type.OMEGA, kind == FunctionKind.LEMMA && def.getResultTypeLevel() == null);
if (expectedTypeResult != null) {
expectedType = expectedTypeResult.getExpr();
}
}
if (myNewDef) {
if (pair != null && pair.proj2 != null && cResultType == null && implementedField != null) {
expectedType = pair.proj2;
if (expectedType.findBinding(implementedField.getType().getParameters())) {
errorReporter.report(new TypeFromFieldError(typechecker.getExpressionPrettifier(), TypeFromFieldError.resultType(), expectedType, def));
expectedType = null;
}
}
if (expectedType == null) {
expectedType = new ErrorExpression();
}
typedDef.setResultType(expectedType);
typedDef.setKind(kind.isSFunc() ? (kind == FunctionKind.LEMMA || kind == FunctionKind.AXIOM ? CoreFunctionDefinition.Kind.LEMMA : kind == FunctionKind.TYPE ? CoreFunctionDefinition.Kind.TYPE : CoreFunctionDefinition.Kind.SFUNC) : kind == FunctionKind.INSTANCE ? CoreFunctionDefinition.Kind.INSTANCE : CoreFunctionDefinition.Kind.FUNC);
calculateTypeClassParameters(def, typedDef);
calculateParametersTypecheckingOrder(typedDef);
GoodThisParametersVisitor goodThisParametersVisitor;
goodThisParametersVisitor = new GoodThisParametersVisitor(typedDef.getParameters());
expectedType.accept(goodThisParametersVisitor, null);
if (typedDef.getResultTypeLevel() != null) {
typedDef.getResultTypeLevel().accept(goodThisParametersVisitor, null);
}
typedDef.setGoodThisParameters(goodThisParametersVisitor.getGoodParameters());
typedDef.setUniverseKind(checkForUniverses(typedDef, def));
}
return pair != null;
}