private TCExplicitFunctionDefinition getPostDefinition() {
    TCPatternList last = new TCPatternList();
    int psize = paramPatternList.size();

    for (TCPattern p : paramPatternList.get(psize - 1)) {
      last.add(p);
    }

    last.add(new TCIdentifierPattern(name.getResultName(location)));

    TCPatternListList parameters = new TCPatternListList();

    if (psize > 1) {
      parameters.addAll(paramPatternList.subList(0, psize - 1));
    }

    parameters.add(last);

    TCExplicitFunctionDefinition def =
        new TCExplicitFunctionDefinition(
            accessSpecifier,
            name.getPostName(postcondition.location),
            typeParams,
            type.getCurriedPostType(isCurried),
            parameters,
            postcondition,
            null,
            null,
            false,
            null);

    def.classDefinition = classDefinition;
    return def;
  }
  @Override
  public void typeResolve(Environment base) {
    if (typeParams != null) {
      FlatCheckedEnvironment params =
          new FlatCheckedEnvironment(getTypeParamDefinitions(), base, NameScope.NAMES);

      type = type.typeResolve(params, null);
    } else {
      type = type.typeResolve(base, null);
    }

    if (base.isVDMPP()) {
      name.setTypeQualifier(type.parameters);
    }

    if (body instanceof TCSubclassResponsibilityExpression
        || body instanceof TCNotYetSpecifiedExpression) {
      isUndefined = true;
    }

    if (precondition != null) {
      predef.typeResolve(base);
    }

    if (postcondition != null) {
      postdef.typeResolve(base);
    }

    for (TCPatternList pp : paramPatternList) {
      pp.typeResolve(base);
    }
  }
  private TCType checkParams(ListIterator<TCPatternList> plists, TCFunctionType ftype) {
    TCTypeList ptypes = ftype.parameters;
    TCPatternList patterns = plists.next();

    if (patterns.size() > ptypes.size()) {
      report(3020, "Too many parameter patterns");
      detail2("Pattern(s)", patterns, "Type(s)", ptypes);
      return ftype.result;
    } else if (patterns.size() < ptypes.size()) {
      report(3021, "Too few parameter patterns");
      detail2("Pattern(s)", patterns, "Type(s)", ptypes);
      return ftype.result;
    }

    if (ftype.result instanceof TCFunctionType) {
      if (!plists.hasNext()) {
        // We're returning the function itself
        return ftype.result;
      }

      // We're returning what the function returns, assuming we
      // pass the right parameters. Note that this recursion
      // means that we finally return the result of calling the
      // function with *all* of the curried argument sets applied.
      // This is because the type check of the body determines
      // the return type when all of the curried parameters are
      // provided.

      return checkParams(plists, (TCFunctionType) ftype.result);
    }

    if (plists.hasNext()) {
      report(3022, "Too many curried parameters");
    }

    return ftype.result;
  }
  private TCDefinitionListList getParamDefinitions() {
    TCDefinitionListList defList = new TCDefinitionListList();
    TCFunctionType ftype = type; // Start with the overall function
    Iterator<TCPatternList> piter = paramPatternList.iterator();

    while (piter.hasNext()) {
      TCPatternList plist = piter.next();
      TCDefinitionList defs = new TCDefinitionList();
      TCTypeList ptypes = ftype.parameters;
      Iterator<TCType> titer = ptypes.iterator();

      if (plist.size() != ptypes.size()) {
        // This is a type/param mismatch, reported elsewhere. But we
        // have to create definitions to avoid a cascade of errors.

        TCType unknown = new TCUnknownType(location);

        for (TCPattern p : plist) {
          defs.addAll(p.getDefinitions(unknown, NameScope.LOCAL));
        }
      } else {
        for (TCPattern p : plist) {
          defs.addAll(p.getDefinitions(titer.next(), NameScope.LOCAL));
        }
      }

      defList.add(checkDuplicatePatterns(defs));

      if (ftype.result instanceof TCFunctionType) // else???
      {
        ftype = (TCFunctionType) ftype.result;
      }
    }

    return defList;
  }