public Object visitExprNew(ExprNew expNew) {

      Type nt = (Type) expNew.getTypeToConstruct().accept(this);
      StructDef ts = null;
      {
        assert nt instanceof TypeStructRef;
        ts = TypeInferenceForStars.this.nres.getStruct(((TypeStructRef) nt).getName());
      }

      boolean changed = false;
      List<ExprNamedParam> enl = new ArrayList<ExprNamedParam>(expNew.getParams().size());
      for (ExprNamedParam en : expNew.getParams()) {
        Expression old = en.getExpr();
        Type oldType = type;
        if (expNew.isHole()) {
          type = getFieldsMap(ts).get(en.getName());
        } else {
          type = ts.getFieldTypMap().get(en.getName());
        }
        StructDef cur = ts;
        while (type == null) {
          cur = nres.getStruct(cur.getParentName());
          type = cur.getFieldTypMap().get(en.getName());
        }
        Expression rhs = doExpression(old);
        if (rhs != old) {
          enl.add(new ExprNamedParam(en, en.getName(), rhs));
          changed = true;
        } else {
          enl.add(en);
        }
        type = oldType;
      }

      if (nt != expNew.getTypeToConstruct() || changed) {
        if (!changed) {
          enl = expNew.getParams();
        }
        if (expNew.isHole()) {
          return new ExprNew(expNew, nt, enl, false, expNew.getStar());
        } else {
          return new ExprNew(expNew, nt, enl, false);
        }
      } else {
        return expNew;
      }
    }
  public Object visitExprNew(ExprNew expNew) {
    if (expNew.isHole()) {
      TypeStructRef t = (TypeStructRef) expNew.getTypeToConstruct();
      Map<String, Type> mst;
      if (ftypeMaps.containsKey(t.getName())) {
        mst = ftypeMaps.get(t.getName());
      } else {
        mst = new HashMap<String, Type>();
        ftypeMaps.put(t.getName(), mst);

        String cur = t.getName();
        LinkedList<String> queue = new LinkedList<String>();
        queue.add(cur);
        addFieldsToMap(mst, nres.getStruct(t.getName()));
        while (!queue.isEmpty()) {
          String cs = queue.removeFirst();
          StructDef sdef = nres.getStruct(cs);
          addFieldsToMap(mst, sdef);
          queue.addAll(nres.getStructChildren(sdef.getFullName()));
        }
      }
      Map<String, Expression> repl = new HashMap<String, Expression>();
      VarReplacer vr = new VarReplacer(repl);
      for (ExprNamedParam en : expNew.getParams()) {
        Expression actual = en.getExpr();
        repl.put(en.getName(), actual);
      }
      for (ExprNamedParam en : expNew.getParams()) {
        String name = en.getName();
        if (!mst.containsKey(name)) {
          throw new ExceptionAtNode("Unknown field " + name, expNew);
        }
        Type ftype = mst.get(en.getName());
        Expression actual = en.getExpr();
        if (ftype == null) {
          if (actual instanceof ExprStar) {
            throw new ExceptionAtNode(
                "The type of field " + name + " is ambiguous. Can't resolve the type of the hole.",
                expNew);
          }
          continue;
        }
        upgradeStarToInt(actual, (Type) ftype.accept(vr));
      }

      return expNew;
    }
    TypeStructRef nt = (TypeStructRef) expNew.getTypeToConstruct().accept(this);
    StructDef sd = nres.getStruct(nt.getName());
    Map<String, Expression> repl = new HashMap<String, Expression>();
    VarReplacer vr = new VarReplacer(repl);
    for (ExprNamedParam en : expNew.getParams()) {
      Expression actual = en.getExpr();
      repl.put(en.getName(), actual);
    }
    for (ExprNamedParam en : expNew.getParams()) {
      // ADT
      StructDef current = sd;
      Type t = null;
      while (current != null) {
        t = current.getType(en.getName());
        if (t != null) break;
        String parent;
        if ((parent = nres.getStructParentName(current.getFullName())) != null) {
          current = nres.getStruct(parent);
        } else {
          current = null;
        }
      }
      Expression actual = en.getExpr();
      upgradeStarToInt(actual, (Type) t.accept(vr));
    }
    return expNew;
  }