private boolean typecheckClause()

in base/src/main/java/org/arend/typechecking/patternmatching/PatternTypechecking.java [143:297]


  private boolean typecheckClause(Concrete.FunctionClause clause, List<? extends Concrete.Parameter> abstractParameters, DependentLink parameters, Expression expectedType, List<ExtElimClause> resultClauses, FunctionDefinition definition) {
    assert myVisitor != null;
    try (var ignored = new Utils.RefContextSaver(myVisitor.getContext(), myVisitor.getLocalExpressionPrettifier())) {
      // Typecheck patterns
      myPathPatterns.clear();
      ExprSubstitution substitution = new ExprSubstitution();
      ExprSubstitution totalSubst = new ExprSubstitution();
      Result result = typecheckPatterns(clause.getPatterns(), abstractParameters, parameters, substitution, totalSubst, clause);
      if (result == null) {
        return false;
      }

      ExtElimClause elimClause = new ExtElimClause(result.patterns, null, totalSubst);

      // If we have the absurd pattern, then RHS is ignored
      if (result.hasEmptyPattern()) {
        if (clause.getExpression() != null) {
          myErrorReporter.report(new CertainTypecheckingError(CertainTypecheckingError.Kind.BODY_IGNORED, clause.getExpression()));
        }
        resultClauses.add(elimClause);
        return true;
      } else {
        if (clause.getExpression() == null) {
          myErrorReporter.report(new TypecheckingError("Required a body", clause));
          return false;
        }
      }

      for (Map.Entry<Referable, Binding> entry : myContext.entrySet()) {
        Binding binding = entry.getValue();
        Expression expr = substitution.get(binding);
        Binding newBinding = expr instanceof ReferenceExpression
          ? ((ReferenceExpression) expr).getBinding()
          : expr != null
            ? new TypedEvaluatingBinding(binding.getName(), expr, binding.getTypeExpr())
            : null;
        if (newBinding != null) {
          entry.setValue(newBinding);
        }
      }
      expectedType = expectedType.subst(substitution);

      GlobalInstancePool globalInstancePool = myVisitor.getInstancePool();
      LocalInstancePool instancePool = globalInstancePool == null ? null : globalInstancePool.getLocalInstancePool();
      if (instancePool != null) {
        globalInstancePool.setInstancePool(instancePool.subst(substitution));
      }

      TypecheckingResult tcResult;
      try {
        List<Binding> intervalBindings;
        Expression exprType = expectedType;
        if (!myPathPatterns.isEmpty()) {
          Body body = new ElimTypechecking(null, null, null, myMode, null, Level.INFINITY, false, null, 0, null).typecheckElim(resultClauses, parameters, myElimParams);
          if (body == null) {
            myErrorReporter.report(new TypecheckingError("Cannot compute body", clause));
            return false;
          }
          if (!(body instanceof ElimBody)) {
            myErrorReporter.report(new TypecheckingError("Incorrect body", clause));
            return false;
          }
          Sort sort = expectedType.getSortOfType();
          if (sort == null) {
            myErrorReporter.report(new TypecheckingError("Cannot infer the sort of the type", clause));
            return false;
          }

          if (definition != null) definition.setBody(body);
          intervalBindings = new ArrayList<>();
          getIntervalBindings(result.patterns, 0, intervalBindings);

          List<TypedSingleDependentLink> lamBindings = new ArrayList<>(intervalBindings.size());
          ExprSubstitution intervalSubst = new ExprSubstitution();
          for (Binding binding : intervalBindings) {
            TypedSingleDependentLink link = new TypedSingleDependentLink(true, binding.getName(), binding.getType());
            lamBindings.add(link);
            intervalSubst.add(binding, new ReferenceExpression(link));
          }

          LevelPair levels = new LevelPair(sort.getPLevel(), sort.getHLevel());
          Sort hSort = new Sort(sort.getPLevel(), Level.INFINITY);
          exprType = expectedType.subst(intervalSubst);
          List<Expression> exprTypes = new ArrayList<>(intervalBindings.size());
          List<Expression> args = ExpressionPattern.toExpressions(result.patterns);
          for (int i = intervalBindings.size() - 1; i >= 0; i--) {
            exprTypes.add(exprType);
            Binding intervalBinding = intervalBindings.get(i);

            intervalSubst.add(intervalBinding, Left());
            Expression leftArg = evalBody(intervalSubst, (ElimBody) body, args);
            if (leftArg == null && definition != null) {
              leftArg = makeFunCall(definition, args, intervalSubst, clause);
            }

            intervalSubst.add(intervalBinding, Right());
            Expression rightArg = evalBody(intervalSubst, (ElimBody) body, args);
            if (rightArg == null && definition != null) {
              rightArg = makeFunCall(definition, args, intervalSubst, clause);
            }

            if (leftArg == null || rightArg == null) {
              myErrorReporter.report(new TypecheckingError("Cannot evaluate conditions", clause));
              return false;
            }

            if (definition != null) {
              leftArg = normalizeRecursiveCalls(leftArg, definition);
              rightArg = normalizeRecursiveCalls(rightArg, definition);
            }

            for (int j = intervalBindings.size() - 1, k = 0; j > i; j--, k++) {
              leftArg = new PathExpression(levels, new LamExpression(hSort, lamBindings.get(j), exprTypes.get(k).subst(lamBindings.get(i), Left())), new LamExpression(hSort, lamBindings.get(j), leftArg));
              rightArg = new PathExpression(levels, new LamExpression(hSort, lamBindings.get(j), exprTypes.get(k).subst(lamBindings.get(i), Right())), new LamExpression(hSort, lamBindings.get(j), rightArg));
            }

            intervalSubst.add(intervalBinding, new ReferenceExpression(lamBindings.get(i)));
            exprType = DataCallExpression.make(Prelude.PATH, levels, Arrays.asList(new LamExpression(hSort, lamBindings.get(i), exprType), leftArg, rightArg));
          }
        } else {
          intervalBindings = null;
        }

        // Typecheck the RHS
        tcResult = myVisitor.checkExpr(clause.getExpression(), exprType);
        if (intervalBindings != null && tcResult != null) {
          ErrorExpression errorExpr = tcResult.expression.cast(ErrorExpression.class);
          if (!(errorExpr != null && errorExpr.isGoal())) {
            Expression resultExpr = tcResult.expression;
            for (Binding binding : intervalBindings) {
              resultExpr = AtExpression.make(resultExpr, new ReferenceExpression(binding), false);
            }
            tcResult = new TypecheckingResult(resultExpr, expectedType);
          }
          if (errorExpr instanceof GoalErrorExpression) {
            ((GoalErrorExpression) errorExpr).goalError.removeConditions();
          }
        }
        if (myFinal) {
          tcResult = myVisitor.finalize(tcResult, clause.getExpression(), false);
        }
      } finally {
        if (definition != null) definition.setBody(null);
      }
      if (instancePool != null) {
        globalInstancePool.setInstancePool(instancePool);
      }
      if (tcResult == null) {
        return false;
      }
      elimClause.setExpression(tcResult.expression);
      resultClauses.add(elimClause);
      return true;
    }
  }