private Map<String, Type> getFieldsMap(StructDef ts) {
   String strName = ts.getFullName();
   if (fTypesMap.containsKey(strName)) {
     return fTypesMap.get(strName);
   } else {
     Map<String, Type> fieldsMap = new HashMap<String, Type>();
     LinkedList<String> queue = new LinkedList<String>();
     queue.add(strName);
     while (!queue.isEmpty()) {
       String current = queue.removeFirst();
       StructDef curStruct = nres.getStruct(current);
       List<String> children = nres.getStructChildren(current);
       queue.addAll(children);
       for (Entry<String, Type> field : curStruct.getFieldTypMap()) {
         String name = field.getKey();
         Type type = field.getValue();
         if (fieldsMap.containsKey(name) && !fieldsMap.get(name).equals(type)) {
           // throw error
           throw new ExceptionAtNode(
               "Two fields with name = " + name + " and different types. Rename one of them.",
               ts);
         } else {
           fieldsMap.put(name, type);
         }
       }
     }
     fTypesMap.put(strName, fieldsMap);
     return fieldsMap;
   }
 }
    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;
      }
    }
 private void addFieldsToMap(Map<String, Type> fm, StructDef sdef) {
   for (StructFieldEnt fld : sdef.getFieldEntries()) {
     if (fm.containsKey(fld.getName())) {
       Type t1 = fm.get(fld.getName());
       Type t2 = fld.getType();
       if (t1.equals(t2)) {
         continue;
       }
       fm.put(fld.getName(), null);
     } else {
       fm.put(fld.getName(), fld.getType());
     }
   }
 }
  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;
  }