public List<QualifiedDefinition> caseAIsExp(AIsExp node, TypeCheckInfo question)
      throws AnalysisException {
    List<QualifiedDefinition> result = new Vector<QualifiedDefinition>();

    if (node.getTest() instanceof AVariableExp) {
      AVariableExp exp = (AVariableExp) node.getTest();
      PDefinition existing = question.env.findName(exp.getName(), NameScope.NAMESANDSTATE);

      if (existing != null && existing.getNameScope().matches(NameScope.NAMES)) {
        if (node.getBasicType() != null) {
          result.add(new QualifiedDefinition(existing, node.getBasicType()));
        } else if (node.getTypeName() != null) {
          if (node.getTypedef() == null) {
            PDefinition typedef =
                question.env.findType(node.getTypeName(), node.getLocation().getModule());
            node.setTypedef(typedef.clone());
          }

          if (node.getTypedef() != null) {
            result.add(new QualifiedDefinition(existing, node.getTypedef().getType()));
          }
        }
      }
    }

    return result;
  }
  protected void stateInPre(List<PExp> args, PDefinition stateDefinition) {

    AVariableExp varExp;
    if (stateDefinition instanceof AStateDefinition) {
      varExp = getVarExp(OLD_STATE_ARG);
      varExp.setType(((AStateDefinition) stateDefinition).getRecordType().clone());
    } else {
      varExp = getVarExp(OLD_SELF_ARG);
      varExp.setType(stateDefinition.getType().clone());
    }
    args.add(varExp);
  }
  protected void stateInPost(
      List<PMultipleBind> exists_binds, List<PExp> postArglist, PDefinition stateDefinition) {

    AVariableExp varExp;
    // replace with super call
    if (stateDefinition instanceof AStateDefinition) {
      varExp = getVarExp(NEW_STATE_ARG);
      AStateDefinition aStateDefinition = (AStateDefinition) stateDefinition;
      varExp.setType(aStateDefinition.getRecordType().clone());
      exists_binds.addAll(
          getMultipleTypeBindList(aStateDefinition.getRecordType().clone(), NEW_STATE_ARG));
    } else {
      varExp = getVarExp(NEW_SELF_ARG);
      varExp.setType(stateDefinition.getType().clone());
      exists_binds.addAll(getMultipleTypeBindList(stateDefinition.getType().clone(), NEW_SELF_ARG));
    }
    postArglist.add(varExp);
  }
  PExp buildPredicate(AImplicitOperationDefinition op, PDefinition stateDefinition)
      throws AnalysisException {
    List<PExp> arglist = new Vector<PExp>();

    for (APatternListTypePair pltp : op.getParameterPatterns()) {
      for (PPattern pattern : pltp.getPatterns()) {
        arglist.add(patternToExp(pattern.clone()));
      }
    }

    if (stateDefinition != null) {
      stateInPre(arglist, stateDefinition);
    }
    AApplyExp preApply = null;

    if (op.getPredef() != null) {
      preApply = getApplyExp(getVarExp(op.getPredef().getName().clone(), op.getPredef()), arglist);
      preApply.getRoot().setType(op.getPredef().getType().clone());
      preApply.setType(new ABooleanBasicType());
    }

    PExp mainExp;

    // Operation Has a Result. Add it in the post condition.
    if (op.getResult() != null) {

      AExistsExp existsExp = new AExistsExp();
      existsExp.setType(new ABooleanBasicType());
      List<PExp> postArglist = new Vector<PExp>(arglist);

      if (op.getResult().getPattern() instanceof AIdentifierPattern) {
        AIdentifierPattern ip = (AIdentifierPattern) op.getResult().getPattern();
        postArglist.add(patternToExp(op.getResult().getPattern().clone()));

        if (stateDefinition != null) {

          if (stateDefinition instanceof AStateDefinition) {
            AVariableExp varExp = getVarExp(OLD_STATE_ARG);
            varExp.setType(((AStateDefinition) stateDefinition).getRecordType().clone());
            postArglist.add(varExp);
            AVariableExp varExp2 = getVarExp(NEW_STATE_ARG);
            varExp2.setType(((AStateDefinition) stateDefinition).getRecordType().clone());
            postArglist.add(varExp2);
          } else {
            AVariableExp varExp = getVarExp(OLD_SELF_ARG);
            postArglist.add(varExp);
            varExp.setType(stateDefinition.getType().clone());
            AVariableExp varExp2 = getVarExp(NEW_SELF_ARG);
            postArglist.add(varExp2);
            varExp2.setType(stateDefinition.getType().clone());
          }
        }

        existsExp.setBindList(
            getMultipleTypeBindList(op.getResult().getType().clone(), ip.getName().clone()));
      } else {
        throw new RuntimeException("Expecting single identifier pattern in operation result");
      }

      AApplyExp postApply = getApplyExp(getVarExp(op.getPostdef().getName()), postArglist);
      postApply.getRoot().setType(op.getPostdef().getType().clone());
      postApply.setType(new ABooleanBasicType());
      existsExp.setPredicate(postApply);
      mainExp = existsExp;
    }

    // No Result. Just add new state to post condition
    else {

      AExistsExp exists_exp = new AExistsExp();
      exists_exp.setType(new ABooleanBasicType());
      List<PExp> postArglist = new Vector<PExp>(arglist);

      List<PMultipleBind> exists_binds = new LinkedList<PMultipleBind>();
      if (stateDefinition != null) {
        stateInPost(exists_binds, postArglist, stateDefinition);
      }
      exists_exp.setBindList(exists_binds);
      AApplyExp postApply =
          getApplyExp(getVarExp(op.getPostdef().getName()), new Vector<PExp>(postArglist));
      postApply.setType(new ABooleanBasicType());
      postApply.getRoot().setType(op.getPostdef().getType().clone());
      exists_exp.setPredicate(postApply);
      mainExp = exists_exp;
    }

    if (preApply != null) {
      return AstExpressionFactory.newAImpliesBooleanBinaryExp(preApply, mainExp);
    } else {
      return mainExp;
    }
  }