in meta/src/main/java/org/arend/lib/meta/SimpCoeMeta.java [329:468]
private Spec getSpec(CoreExpression arg, ExpressionTypechecker typechecker, ConcreteSourceNode marker, ConcreteFactory factory, List<CoreExpression> args, CoreClassField field, int proj, ConcreteExpression concreteArg, TypedExpression simpCoeArg, List<ConcreteArgument> excessiveArgs, boolean isForward) {
arg = arg.normalize(NormalizationMode.WHNF);
if (!(arg instanceof CoreLamExpression lam) || lam.getParameters().getNext().hasNext()) {
return null;
}
CoreExpression body = lam.getBody().getUnderlyingExpression();
if (body instanceof CoreFunCallExpression && ((CoreFunCallExpression) body).getDefinition() == ext.prelude.getEquality()) {
return new EqualitySpec(lam.getParameters(), (CoreFunCallExpression) body, typechecker, marker, concreteArg, simpCoeArg, isForward);
}
body = body.normalize(NormalizationMode.WHNF);
if (!args.isEmpty() && !(body instanceof CorePiExpression)) {
return null;
}
if (body instanceof CorePiExpression) {
if (args.isEmpty()) {
List<ConcreteLetClause> letClauses = new ArrayList<>();
PiTreeMaker piTreeMaker = new PiTreeMaker(ext, typechecker, factory, letClauses);
PiTreeRoot piTree = piTreeMaker.make(body, Collections.singletonList(lam.getParameters()));
return piTree.subtrees.isEmpty() ? null : new PiSpec(piTreeMaker, piTree, letClauses, concreteArg, simpCoeArg, excessiveArgs, isForward);
} else {
int s = 0;
List<CoreParameter> parameters = new ArrayList<>();
while (true) {
CoreParameter param = ((CorePiExpression) body).getParameters();
if (param.getTypeExpr().findFreeBinding(lam.getParameters().getBinding())) {
return null;
}
int n = 0;
for (; param.hasNext() && s < args.size(); param = param.getNext(), n++, s++) {
parameters.add(param);
}
if (s == args.size()) {
body = param.hasNext() ? ((CorePiExpression) body).dropParameters(n) : ((CorePiExpression) body).getCodomain();
break;
}
body = ((CorePiExpression) body).getCodomain();
}
return new PiArgsSpec(args, lam, parameters, body, concreteArg, isForward);
}
}
if (body instanceof CoreSigmaExpression || body instanceof CoreClassCallExpression) {
CoreParameter parameters = body instanceof CoreSigmaExpression ? ((CoreSigmaExpression) body).getParameters() : ((CoreClassCallExpression) body).getClassFieldParameters();
List<CoreClassField> classFields = body instanceof CoreClassCallExpression ? Utils.getNotImplementedField((CoreClassCallExpression) body) : null;
if (proj == -1 && field == null) {
List<CoreExpression> sigmaParamTypes = new ArrayList<>();
List<Integer> indices = classFields == null ? new ArrayList<>() : null;
Set<CoreBinding> bindings = new HashSet<>();
int i = 0;
for (CoreParameter param = parameters; param.hasNext(); param = param.getNext(), i++) {
CoreExpression paramType = param.getTypeExpr();
if (!(classFields != null && classFields.get(i).isProperty() || Utils.isProp(paramType))) {
if (paramType.findFreeBindings(bindings) != null) {
return null;
}
sigmaParamTypes.add(paramType);
if (classFields == null) indices.add(i);
} else if (classFields != null) {
classFields.remove(i--);
}
bindings.add(param.getBinding());
}
if (classFields != null && concreteArg instanceof ConcreteClassExtExpression classExt) {
ConcreteExpression baseExpr = classExt.getBaseClassExpression();
CoreDefinition def = baseExpr instanceof ConcreteReferenceExpression ? ext.definitionProvider.getCoreDefinition(((ConcreteReferenceExpression) baseExpr).getReferent()) : null;
CoreClassDefinition classDef = ((CoreClassCallExpression) body).getDefinition();
if (!(def instanceof CoreClassDefinition && ((CoreClassDefinition) def).isSubClassOf(classDef))) {
typechecker.getErrorReporter().report(new SubclassError(true, classDef.getRef(), baseExpr));
return new ErrorSpec();
}
Map<ArendRef, ConcreteCoclause> implMap = new HashMap<>();
for (ConcreteCoclause coclause : classExt.getCoclauses().getCoclauseList()) {
if (coclause.getImplementation() == null) {
typechecker.getErrorReporter().report(new TypecheckingError("Implementation is missing", coclause));
return new ErrorSpec();
}
if (implMap.putIfAbsent(coclause.getImplementedRef(), coclause) != null) {
typechecker.getErrorReporter().report(new RedundantCoclauseError(coclause));
}
}
List<ConcreteExpression> tupleFields = new ArrayList<>(classFields.size());
List<ArendRef> notImplemented = new ArrayList<>();
for (CoreClassField classField : classFields) {
ConcreteCoclause coclause = implMap.remove(classField.getRef());
if (coclause != null) {
tupleFields.add(coclause.getImplementation());
} else {
notImplemented.add(classField.getRef());
}
}
for (ConcreteCoclause coclause : implMap.values()) {
typechecker.getErrorReporter().report(new RedundantCoclauseError(coclause));
}
if (!notImplemented.isEmpty()) {
typechecker.getErrorReporter().report(new FieldsImplementationError(false, classDef.getRef(), notImplemented, classExt.getCoclauses()));
return new ErrorSpec();
}
concreteArg = tupleFields.size() == 1 ? tupleFields.get(0) : factory.withData(classExt.getData()).tuple(tupleFields);
}
return new SigmaSpec(lam, sigmaParamTypes, classFields, indices, concreteArg, isForward);
} else {
int i = 0;
Set<CoreBinding> bindings = new HashSet<>();
CoreExpression parameterType = null;
for (CoreParameter param = parameters; param.hasNext(); param = param.getNext(), i++) {
bindings.add(param.getBinding());
if (i == proj || classFields != null && classFields.get(i) == field) {
CoreExpression paramType = param.getTypeExpr();
if (paramType.findFreeBindings(bindings) != null) {
return null;
}
parameterType = paramType;
break;
}
}
return parameterType == null ? null : new SigmaProjSpec(lam, proj, field, parameterType, concreteArg, isForward);
}
}
CoreFunCallExpression equality = body.toEquality();
if (equality != null ) {
return new EqualitySpec(lam.getParameters(), equality, typechecker, marker, concreteArg, simpCoeArg, isForward);
}
return null;
}