in meta/src/main/java/org/arend/lib/meta/simplify/Simplifier.java [227:307]
public ConcreteExpression simplifyTypeOfExpression(ConcreteExpression expression, CoreExpression type, boolean isForward) {
CoreExpression normType = type.normalize(NormalizationMode.WHNF);
var processor = new SimplifyExpressionProcessor();
typechecker.withCurrentState(tc -> normType.processSubexpression(processor));
var occurrences = processor.getSimplificationOccurrences().stream().map(x -> x.proj1).collect(Collectors.toList());
var lamParams = new ArrayList<ConcreteParameter>();
if (occurrences.isEmpty()) {
errorReporter.report(new TypecheckingError("Nothing to simplify", refExpr));
return expression;
}
for (int i = 0; i < occurrences.size(); ++i) {
var var = factory.local("y" + i);
var typeParam = factory.core(occurrences.get(i).computeType().computeTyped());
lamParams.add(factory.param(true, Collections.singletonList(var), typeParam));
}
ConcreteExpression lam = factory.lam(lamParams, factory.meta("\\lam y_v => {!}", new MetaDefinition() {
@Override
public TypedExpression invokeMeta(@NotNull ExpressionTypechecker typechecker, @NotNull ContextData contextData) {
List<TypedExpression> checkedVars = new ArrayList<>();
for (var param : lamParams) {
var checkedVar = typechecker.typecheck(factory.ref(param.getRefList().get(0)), null);
assert checkedVar != null;
checkedVars.add(checkedVar);
}
Map<Wrapper<CoreExpression>, Integer> indexOfSubExpr = new HashMap<>();
for (int i = 0; i < occurrences.size(); ++i) {
indexOfSubExpr.put(new Wrapper<>(occurrences.get(i)), i);
}
UncheckedExpression typeWithOccur = replaceSubexpr(normType, checkedVars, indexOfSubExpr, processor.getExprsToNormalize(), occurrences);
/*final boolean[] subexprNormalized = {true};
while (subexprNormalized[0]) {
subexprNormalized[0] = false;
typeWithOccur = typeWithOccur.replaceSubexpressions(expression -> {
var newSubexpr = expression;
if (processor.getExprsToNormalize().containsKey(expression)) {
subexprNormalized[0] = true;
newSubexpr = processor.getExprsToNormalize().get(expression);
}
Integer occurInd = indexOfSubExpr.get(new Wrapper<>(newSubexpr));
if (occurInd != null) {
return newSubexpr;
}
return newSubexpr == expression ? null : newSubexpr;
}, true);
if (typeWithOccur == null) break;
}
typeWithOccur = typeWithOccur == null ? null : typeWithOccur.replaceSubexpressions(expression -> {
Integer occurInd = indexOfSubExpr.get(new Wrapper<>(expression));
if (occurInd == null) return null;
return checkedVars.get(occurInd).getExpression();
}, false); /**/
TypedExpression result = typeWithOccur != null ? Utils.tryTypecheck(typechecker, tc -> tc.check(typeWithOccur, refExpr)) : null;
if (result == null) {
errorReporter.report(typeWithOccur == null ? new SimplifyError(typechecker.getExpressionPrettifier(), occurrences, normType, refExpr) : new TypeError(typechecker.getExpressionPrettifier(), "Cannot substitute a variable. The resulting type is invalid", typeWithOccur, refExpr));
}/**/
return result;
// return typeWithOccur;
}
}));
var checkedLam = typechecker.typecheck(lam, null);
if (checkedLam == null || checkedLam instanceof CoreErrorExpression) {
return null;
}
var proofs = processor.simplificationOccurrences.stream().map(x -> isForward ? x.proj2 : x.proj2.inverse(factory, ext)).collect(Collectors.toList());
return RewriteMeta.chainOfTransports(factory.ref(ext.transport.getRef(), refExpr.getPLevels(), refExpr.getHLevels()),
checkedLam.getExpression(), proofs, expression, factory, ext);
}