Fix another inner class bug: every inner class along the inherited chain has a pointe...
[IRC.git] / Robust / src / IR / Tree / SemanticCheck.java
index f6f5df32b19299db5a4d210efb03e76dcf18ee5d..95042d31b38833a1f307fb118bc1b04a5cdb5379 100644 (file)
@@ -10,6 +10,8 @@ public class SemanticCheck {
   Stack loopstack;
   HashSet toanalyze;
   HashMap<ClassDescriptor, Integer> completed;
+  HashMap<ClassDescriptor, Vector<VarDescriptor>> inlineClass2LiveVars;
+  boolean trialcheck = false;
 
   public static final int NOCHECK=0;
   public static final int REFERENCE=1;
@@ -32,6 +34,7 @@ public class SemanticCheck {
     this.toanalyze=new HashSet();
     this.completed=new HashMap<ClassDescriptor, Integer>();
     this.checkAll=checkAll;
+    this.inlineClass2LiveVars = new HashMap<ClassDescriptor, Vector<VarDescriptor>>();
   }
 
   public ClassDescriptor getClass(ClassDescriptor context, String classname) {
@@ -56,6 +59,9 @@ public class SemanticCheck {
         //Set superclass link up
         if (cd.getSuper()!=null) {
          ClassDescriptor superdesc=getClass(cd, cd.getSuper(), fullcheck);
+         if (superdesc.isInnerClass()) {
+           cd.setAsInnerClass();
+         }
          if (superdesc.isInterface()) {
            if (cd.getInline()) {
              cd.setSuper(null);
@@ -113,6 +119,32 @@ public class SemanticCheck {
       }
     }
   }
+  
+  public void semanticCheckClass(ClassDescriptor cd) {
+    // need to initialize typeutil object here...only place we can
+    // get class descriptors without first calling getclass
+    getClass(cd, cd.getSymbol());
+    if(cd.getInline()) {
+      
+      // for inline defined anonymous classes, we need to check its 
+      // surrounding class first to get its surrounding context
+      ClassDescriptor surroundingcd = cd.getSurroundingDesc();
+      if(toanalyze.contains(surroundingcd)) {
+         toanalyze.remove(surroundingcd);
+         semanticCheckClass(surroundingcd);
+      }
+    }
+
+    for (Iterator method_it = cd.getMethods(); method_it.hasNext(); ) {
+      MethodDescriptor md = (MethodDescriptor) method_it.next();
+      try {
+       checkMethodBody(cd, md);
+      } catch (Error e) {
+        System.out.println("Error in " + md);
+        throw e;
+      }
+    }
+  }
 
   public void semanticCheck() {
     SymbolTable classtable = state.getClassSymbolTable();
@@ -134,19 +166,7 @@ public class SemanticCheck {
       } else {
         ClassDescriptor cd = (ClassDescriptor) obj;
         toanalyze.remove(cd);
-
-        // need to initialize typeutil object here...only place we can
-        // get class descriptors without first calling getclass
-        getClass(cd, cd.getSymbol());
-        for (Iterator method_it = cd.getMethods(); method_it.hasNext(); ) {
-          MethodDescriptor md = (MethodDescriptor) method_it.next();
-          try {
-            checkMethodBody(cd, md);
-          } catch (Error e) {
-            System.out.println("Error in " + md);
-            throw e;
-          }
-        }
+        semanticCheckClass(cd);
       }
     }
   }
@@ -301,8 +321,9 @@ public class SemanticCheck {
       VarDescriptor thisvd=new VarDescriptor(new TypeDescriptor(cd),"this");
       md.setThis(thisvd);
     }
-    if(md.isDefaultConstructor() && (cd.getSuperDesc() != null)) {
+    if(md.isDefaultConstructor() && (cd.getSuperDesc() != null) && !cd.getInline()) {
       // add the construction of it super class, can only be super()
+      // NOTE: inline class should be treated differently
       NameDescriptor nd=new NameDescriptor("super");
       MethodInvokeNode min=new MethodInvokeNode(nd);
       BlockExpressionNode ben=new BlockExpressionNode(min);
@@ -313,7 +334,8 @@ public class SemanticCheck {
 
   public void checkMethodBody(ClassDescriptor cd, MethodDescriptor md) {
     ClassDescriptor superdesc=cd.getSuperDesc();
-    if (superdesc!=null) {
+    // for inline classes, it has done this during trial check
+    if ((!cd.getInline() || this.trialcheck) && (superdesc!=null)) {
       Set possiblematches=superdesc.getMethodTable().getSet(md.getSymbol());
       for(Iterator methodit=possiblematches.iterator(); methodit.hasNext(); ) {
         MethodDescriptor matchmd=(MethodDescriptor)methodit.next();
@@ -389,6 +411,7 @@ public class SemanticCheck {
 
     case Kind.SESENode:
     case Kind.GenReachNode:
+    case Kind.GenDefReachNode:
       // do nothing, no semantic check for SESEs
       return;
     }
@@ -407,6 +430,8 @@ public class SemanticCheck {
     if ((d==null)||
         (d instanceof FieldDescriptor)) {
       nametable.add(vd);
+    } else if((md instanceof MethodDescriptor) && (((MethodDescriptor)md).getClassDesc().getInline()) && !this.trialcheck) {
+      // for inline classes, the var has been checked during trial check and added into the nametable
     } else
       throw new Error(vd.getSymbol()+" in "+md+" defined a second time");
     if (dn.getExpression()!=null)
@@ -419,6 +444,8 @@ public class SemanticCheck {
     if ((d==null)||
         (d instanceof FieldDescriptor)) {
       nametable.add(vd);
+    } else if((md instanceof MethodDescriptor) && (((MethodDescriptor)md).getClassDesc().getInline()) && !this.trialcheck) {
+      // for inline classes, the var has been checked during trial check and added into the nametable
     } else
       throw new Error(vd.getSymbol()+" defined a second time");
   }
@@ -642,6 +669,7 @@ public class SemanticCheck {
     throw new Error("Cast will always fail\n"+cn.printNode(0));
   }
 
+  //FieldDescriptor checkFieldAccessNodeForParentNode( Descriptor md, SymbolTable na )
   void checkFieldAccessNode(Descriptor md, SymbolTable nametable, FieldAccessNode fan, TypeDescriptor td) {
     ExpressionNode left=fan.getExpression();
     checkExpressionNode(md,nametable,left,null);
@@ -653,11 +681,67 @@ public class SemanticCheck {
     FieldDescriptor fd=null;
     if (ltd.isArray()&&fieldname.equals("length"))
       fd=FieldDescriptor.arrayLength;
-    else
+    else if(((left instanceof NameNode) && ((NameNode)left).isSuper())
+           ||((left instanceof FieldAccessNode) && ((FieldAccessNode)left).isSuper())){
+      fd = (FieldDescriptor) ltd.getClassDesc().getSuperDesc().getFieldTable().get(fieldname);
+    } else {
       fd=(FieldDescriptor) ltd.getClassDesc().getFieldTable().get(fieldname);
-
+    }
     if(ltd.isClassNameRef()) {
       // the field access is using a class name directly
+      if (fd==null) {
+       // check if it is to access a surrounding class in an inner class
+       if(fieldname.equals("this") || fieldname.equals("super")) {
+          ClassDescriptor icd = ((VarDescriptor)nametable.get("this")).getType().getClassDesc();
+          if(icd.isInnerClass()) {
+              NameNode nn = new NameNode(new NameDescriptor("this"));
+              nn.setVar((VarDescriptor)nametable.get("this"));
+              fan.setExpression(nn);
+              if(icd.getSurroundingDesc()==ltd.getClassDesc()) {
+                  // this is a surrounding class access inside an inner class
+                  fan.setExpression(nn);
+                  fan.setFieldName("this$0");
+                  fd = (FieldDescriptor)icd.getFieldTable().get("this$0");
+              } else if(icd==ltd.getClassDesc()) {
+                  // this is an inner class this operation 
+                  fd = new FieldDescriptor(new Modifiers(),new TypeDescriptor(icd),"this",null,false);
+              }
+              if(fieldname.equals("super")) {
+                  fan.setIsSuper();
+              }
+              fan.setField(fd);
+              return;
+          }
+       } 
+       ClassDescriptor surroundingCls=ltd.getClassDesc().getSurroundingDesc();
+       
+       while(surroundingCls!=null) {
+         fd=(FieldDescriptor) surroundingCls.getFieldTable().get(fieldname);
+         if (fd!=null) {
+           fan.left=new ClassTypeNode(new TypeDescriptor(surroundingCls));
+           break;
+         }
+         surroundingCls=surroundingCls.getSurroundingDesc();
+       }
+       
+       // check if it is to access an enum field
+       Iterator it_enum = ltd.getClassDesc().getEnum();
+       while(it_enum.hasNext()) {
+        ClassDescriptor ecd = (ClassDescriptor)it_enum.next();
+        if(ecd.getSymbol().equals(ltd.getClassDesc().getSymbol()+"$"+fieldname)) {
+          // this is an enum field access
+          if(!ecd.isStatic() && !ecd.getModifier().isStatic() && !ecd.getModifier().isPublic()) {
+            throw new Error(fieldname + " is not a public/static enum field in "+fan.printNode(0)+" in "+md);
+          }
+          TypeDescriptor tp = new TypeDescriptor(ecd);
+          tp.setClassNameRef();
+          fd=new FieldDescriptor(ecd.getModifier(), tp, ltd.getClassDesc().getSymbol()+"$"+fieldname, null, false);;
+          fd.setIsEnumClass();
+          break;
+        }
+       }
+      }
+
       if(ltd.getClassDesc().isEnum()) {
         int value = ltd.getClassDesc().getEnumConstant(fieldname);
         if(-1 == value) {
@@ -679,8 +763,22 @@ public class SemanticCheck {
       }
     }
 
-    if (fd==null)
-      throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md);
+    if (fd==null){
+       if((md instanceof MethodDescriptor) && false == ((MethodDescriptor)md).isStaticBlock()) {
+           ClassDescriptor cd = ((MethodDescriptor)md).getClassDesc();
+           FieldAccessNode theFieldNode =      fieldAccessExpression( cd, fieldname, fan.getNumLine() );
+           if( null != theFieldNode ) {
+               //fan = theFieldNode;
+               checkFieldAccessNode( md, nametable, theFieldNode, td );
+               fan.setField( theFieldNode.getField() );
+               fan.setExpression( theFieldNode.getExpression() );
+               //TypeDescriptor td1 = fan.getType();
+               //td1.toString();
+               return;         
+           }   
+       }
+       throw new Error("Unknown field "+fieldname + " in "+fan.printNode(0)+" in "+md);
+    }
 
     if (fd.getType().iswrapper()) {
       FieldAccessNode fan2=new FieldAccessNode(left, fieldname);
@@ -763,6 +861,64 @@ public class SemanticCheck {
       }
   }
 
+  FieldDescriptor recurseSurroundingClasses( ClassDescriptor icd, String varname ) {
+        if( null == icd || false == icd.isInnerClass() )
+           return null;
+      
+        ClassDescriptor surroundingDesc = icd.getSurroundingDesc();
+        if( null == surroundingDesc )
+           return null;
+      
+        SymbolTable fieldTable = surroundingDesc.getFieldTable();
+        FieldDescriptor fd = ( FieldDescriptor ) fieldTable.get( varname );
+        if( null != fd )
+           return fd;
+        return recurseSurroundingClasses( surroundingDesc, varname );
+  }
+  
+  FieldAccessNode fieldAccessExpression( ClassDescriptor icd, String varname, int linenum ) {
+        FieldDescriptor fd = recurseSurroundingClasses( icd, varname );
+       if( null == fd )
+               return null;
+
+       ClassDescriptor cd = fd.getClassDescriptor();
+       if(icd.getInStaticContext()) {
+         // if the inner class is in a static context, it does not have the this$0 
+         // pointer to its surrounding class. Instead, it might have reference to 
+         // its static surrounding method/block is there is any and it can refer 
+         // to static fields in its surrounding class too.
+         if(fd.isStatic()) {
+           NameNode nn = new NameNode(new NameDescriptor(cd.getSymbol()));
+           nn.setNumLine(linenum);
+           FieldAccessNode theFieldNode = new FieldAccessNode(nn,varname);
+           theFieldNode.setNumLine(linenum);
+           return theFieldNode;
+         } else {
+           throw new Error("Error: access non-static field " + cd.getSymbol() + "." + fd.getSymbol() + " in an inner class " + icd.getSymbol() + " that is declared in a static context");
+         }
+       }
+       int depth = 1;
+       int startingDepth = icd.getInnerDepth();
+
+       if( true == cd.isInnerClass() ) 
+               depth = cd.getInnerDepth();
+
+       String composed = "this";
+       NameDescriptor runningDesc = new NameDescriptor( "this" );;
+       
+       for ( int index = startingDepth; index > depth; --index ) {
+               composed = "this$" + String.valueOf( index - 1  );      
+               runningDesc = new NameDescriptor( runningDesc, composed );
+       }
+       if( false == cd.isInnerClass() )
+               runningDesc = new NameDescriptor( runningDesc, "this$" + String.valueOf(0) ); //all the way up.
+       NameDescriptor idDesc = new NameDescriptor( runningDesc, varname );
+       
+       
+       FieldAccessNode theFieldNode = ( FieldAccessNode )translateNameDescriptorintoExpression( idDesc, linenum );
+       return theFieldNode;
+  }
+
   void checkNameNode(Descriptor md, SymbolTable nametable, NameNode nn, TypeDescriptor td) {
     NameDescriptor nd=nn.getName();
     if (nd.getBase()!=null) {
@@ -773,14 +929,40 @@ public class SemanticCheck {
       checkExpressionNode(md,nametable,en,td);
     } else {
       String varname=nd.toString();
-      if(varname.equals("this")) {
+      if(varname.equals("this") || varname.equals("super")) {
         // "this"
         nn.setVar((VarDescriptor)nametable.get("this"));
+        if(varname.equals("super")) {
+            nn.setIsSuper();
+        }
         return;
       }
       Descriptor d=(Descriptor)nametable.get(varname);
       if (d==null) {
         ClassDescriptor cd = null;
+       //check the inner class case first.
+       if((md instanceof MethodDescriptor) && false == ((MethodDescriptor)md).isStaticBlock()) {
+               cd = ((MethodDescriptor)md).getClassDesc();
+               FieldAccessNode theFieldNode =  fieldAccessExpression( cd, varname, nn.getNumLine() );
+               if( null != theFieldNode ) {
+                       nn.setExpression(( ExpressionNode )theFieldNode);
+                       checkExpressionNode(md,nametable,( ExpressionNode )theFieldNode,td);
+                       return;         
+               } else if(cd.getInline() && (this.trialcheck)) {
+                   // for the trial check of an inline class, cache the unknown var
+                   d = cd.getSurroundingNameTable().get(varname);
+                   if(null!=d) {
+                     if(!this.inlineClass2LiveVars.containsKey(cd)) {
+                       this.inlineClass2LiveVars.put(cd, new Vector<VarDescriptor>());
+                     }
+                     Vector<VarDescriptor> vars = this.inlineClass2LiveVars.get(cd);
+                     if(!vars.contains((VarDescriptor)d)) {
+                       vars.add((VarDescriptor)d);
+                     }
+                   }
+               }
+       }
+       if(null==d) {
         if((md instanceof MethodDescriptor) && ((MethodDescriptor)md).isStaticBlock()) {
           // this is a static block, all the accessed fields should be static field
           cd = ((MethodDescriptor)md).getClassDesc();
@@ -827,10 +1009,12 @@ public class SemanticCheck {
             nn.setClassDesc(cd);
             return;
           } else {
-            throw new Error("Name "+varname+" undefined in: "+md);
+            throw new Error("Name "+varname+" undefined in: "+md);         
           }
         }
+       }
       }
+
       if (d instanceof VarDescriptor) {
         nn.setVar(d);
       } else if (d instanceof FieldDescriptor) {
@@ -901,65 +1085,35 @@ public class SemanticCheck {
   }
 
   void checkArrayInitializerNode(Descriptor md, SymbolTable nametable, ArrayInitializerNode ain, TypeDescriptor td) {
-    Vector<TypeDescriptor> vec_type = new Vector<TypeDescriptor>();
     for( int i = 0; i < ain.numVarInitializers(); ++i ) {
-      checkExpressionNode(md, nametable, ain.getVarInitializer(i), td==null?td:td.dereference());
-      vec_type.add(ain.getVarInitializer(i).getType());
-    }
-    // descide the type of this variableInitializerNode
-    TypeDescriptor out_type = null;
-    for(int i = 0; i < vec_type.size(); i++) {
-      TypeDescriptor tmp_type = vec_type.elementAt(i);
-      if(out_type == null) {
-        if(tmp_type != null) {
-          out_type = tmp_type;
-        }
-      } else if(out_type.isNull()) {
-        if(!tmp_type.isNull() ) {
-          if(!tmp_type.isArray()) {
-            throw new Error("Error: mixed type in var initializer list");
-          } else {
-            out_type = tmp_type;
-          }
-        }
-      } else if(out_type.isArray()) {
-        if(tmp_type.isArray()) {
-          if(tmp_type.getArrayCount() > out_type.getArrayCount()) {
-            out_type = tmp_type;
-          }
-        } else if((tmp_type != null) && (!tmp_type.isNull())) {
-          throw new Error("Error: mixed type in var initializer list");
-        }
-      } else if(out_type.isInt()) {
-        if(!tmp_type.isInt()) {
-          throw new Error("Error: mixed type in var initializer list");
-        }
-      } else if(out_type.isString()) {
-        if(!tmp_type.isString()) {
-          throw new Error("Error: mixed type in var initializer list");
-        }
-      }
-    }
-    if(out_type != null) {
-      out_type = out_type.makeArray(state);
+      checkExpressionNode(md, nametable, ain.getVarInitializer(i), td.dereference());
     }
-    ain.setType(out_type);
+    if (td==null)
+       throw new Error();
+    
+    ain.setType(td);
   }
 
   void checkAssignmentNode(Descriptor md, SymbolTable nametable, AssignmentNode an, TypeDescriptor td) {
-    boolean postinc=true;
-    if (an.getOperation().getBaseOp()==null||
-        (an.getOperation().getBaseOp().getOp()!=Operation.POSTINC&&
-         an.getOperation().getBaseOp().getOp()!=Operation.POSTDEC))
-      postinc=false;
-    if (!postinc)
-      checkExpressionNode(md, nametable, an.getSrc(),td);
-    //TODO: Need check on validity of operation here
+    // Need to first check the lside to decide the correct type of the rside
+    // TODO: Need check on validity of operation here
     if (!((an.getDest() instanceof FieldAccessNode)||
           (an.getDest() instanceof ArrayAccessNode)||
           (an.getDest() instanceof NameNode)))
       throw new Error("Bad lside in "+an.printNode(0));
     checkExpressionNode(md, nametable, an.getDest(), null);
+    boolean postinc=true;
+    if (an.getOperation().getBaseOp()==null||
+        (an.getOperation().getBaseOp().getOp()!=Operation.POSTINC&&
+         an.getOperation().getBaseOp().getOp()!=Operation.POSTDEC))
+      postinc=false;
+    if (!postinc) {
+      if(an.getSrc() instanceof ArrayInitializerNode) {
+       checkExpressionNode(md, nametable, an.getSrc(), an.getDest().getType());
+      } else {
+        checkExpressionNode(md, nametable, an.getSrc(),td);
+      }
+    }
 
     /* We want parameter variables to tasks to be immutable */
     if (md instanceof TaskDescriptor) {
@@ -1048,7 +1202,114 @@ public class SemanticCheck {
     loopstack.pop();
   }
 
-
+  void InnerClassAddParamToCtor( MethodDescriptor md, ClassDescriptor cd, SymbolTable nametable, 
+                                CreateObjectNode con, TypeDescriptor td ) {
+       
+       TypeDescriptor cdsType = new TypeDescriptor( cd );
+       ExpressionNode conExp = con.getSurroundingClassExpression();
+       //System.out.println( "The surrounding class expression si " + con );
+       if( null == conExp ) {
+               if( md.isStatic()) {
+                       throw new Error("trying to instantiate inner class: " +  con.getType() + " in a static scope" );
+               }
+               VarDescriptor thisVD = md.getThis();
+               if( null == thisVD ) {
+                       throw new Error( "this pointer is not defined in a non static scope" ); 
+               }                       
+               if( cdsType.equals( thisVD.getType() ) == false ) {
+                       throw new Error( "the type of this pointer is different than the type expected for inner class constructor. Initializing the inner class: "                             +  con.getType() + " in the wrong scope" );             
+               }       
+               //make this into an expression node.
+               NameNode nThis=new NameNode( new NameDescriptor( "this" ) );
+               con.addArgument( nThis );
+       }
+       else {
+               //REVISIT : here i am storing the expression as an expressionNode which does not implement type, there is no way for me to semantic check this argument.
+               con.addArgument( conExp );
+       }
+       //System.out.println( " the modified createObjectNode is " + con.printNode( 0 ) + "\n" );
+}
+  
+  void trialSemanticCheck(ClassDescriptor cd) {
+    if(!cd.getInline()) {
+      throw new Error("Error! Try to do a trial check on a non-inline class " + cd.getSymbol());
+    }
+    trialcheck = true;
+      
+    for (Iterator method_it = cd.getMethods(); method_it.hasNext(); ) {
+      MethodDescriptor md = (MethodDescriptor) method_it.next();
+      try {
+        checkMethodBody(cd, md);
+      } catch (Error e) {
+        System.out.println("Error in " + md);
+        throw e;
+      }
+    }
+    trialcheck = false;
+  }
+  
+  // add all the live vars that are referred by the inline class in the surrounding 
+  // context of the inline class into the inline class' field table and pass them to 
+  // the inline class' constructors
+  // TODO: BUGFIX. These local vars should be final. But currently we've lost those 
+  // information, so we cannot have that checked.
+  void InlineClassAddParamToCtor(MethodDescriptor md, ClassDescriptor cd , SymbolTable nametable, CreateObjectNode con, TypeDescriptor td, TypeDescriptor[] tdarray ) {
+    // for an inline class, need to first add the original parameters of the CreatObjectNode
+    // into its anonymous constructor and insert a super(...) into the anonymous constructor
+    // if its super class is not null
+    MethodDescriptor cd_constructor = null;
+    for(Iterator it_methods = cd.getMethods(); it_methods.hasNext();) {
+      MethodDescriptor imd = (MethodDescriptor)it_methods.next();
+      if(imd.isConstructor()) {
+         cd_constructor = imd; // an inline class should only have one anonymous constructor
+      }
+    }
+    MethodInvokeNode min = null;
+    if(cd.getSuper()!= null) {
+      // add a super(...) into the anonymous constructor
+      NameDescriptor nd=new NameDescriptor("super");
+      min=new MethodInvokeNode(nd);
+      BlockExpressionNode ben=new BlockExpressionNode(min);
+      BlockNode bn = state.getMethodBody(cd_constructor);
+      bn.addFirstBlockStatement(ben);
+      if(cd.getSuperDesc().isInnerClass()&&!cd.getSuperDesc().isStatic()&&!cd.getSuperDesc().getInStaticContext()) {
+       // for a super class that is also an inner class with surrounding reference, add the surrounding 
+       // instance of the child instance as the parent instance's surrounding instance
+       min.addArgument(new NameNode(new NameDescriptor("surrounding$0")));
+      }
+    }
+    for(int i = 0 ; i < tdarray.length; i++) {
+      assert(null!=min);
+      TypeDescriptor itd = tdarray[i];
+      cd_constructor.addParameter(itd, itd.getSymbol()+"_from_con_node_"+i);
+      min.addArgument(new NameNode(new NameDescriptor(itd.getSymbol()+"_from_con_node_"+i)));
+    }
+    
+    // Next add the live vars into the inline class' fields
+    cd.setSurroundingNameTable(nametable);
+    // do a round of semantic check trial to get all the live vars required by the inline class
+    trialSemanticCheck(cd);
+    Vector<VarDescriptor> vars = this.inlineClass2LiveVars.remove(cd);
+    if(vars == null) {
+      return;
+    }
+    for(int i = 0; i < vars.size(); i++) {
+      Descriptor d = vars.elementAt(i);
+      if(d instanceof VarDescriptor && !d.getSymbol().equals("this")) {
+        con.addArgument(new NameNode(new NameDescriptor(d.getSymbol())));
+        cd.addField(new FieldDescriptor(new Modifiers(Modifiers.PUBLIC), ((VarDescriptor)d).getType(), d.getSymbol(), null, false));
+        cd_constructor.addParameter(((VarDescriptor)d).getType(), d.getSymbol()+"_p");
+        // add the initialize statement into this constructor
+        BlockNode obn = state.getMethodBody(cd_constructor);
+        NameNode nn=new NameNode(new NameDescriptor(d.getSymbol()));
+        NameNode fn = new NameNode (new NameDescriptor(d.getSymbol()+"_p"));
+        AssignmentNode an=new AssignmentNode(nn,fn,new AssignOperation(1));
+        obn.addFirstBlockStatement(new BlockExpressionNode(an));
+        state.addTreeCode(cd_constructor, obn);
+      }
+    }
+  }
+  
   void checkCreateObjectNode(Descriptor md, SymbolTable nametable, CreateObjectNode con,
                              TypeDescriptor td) {
     TypeDescriptor[] tdarray = new TypeDescriptor[con.numArgs()];
@@ -1066,7 +1327,12 @@ public class SemanticCheck {
 
     /* Check Array Initializers */
     if ((con.getArrayInitializer() != null)) {
-      checkArrayInitializerNode(md, nametable, con.getArrayInitializer(), td);
+      checkArrayInitializerNode(md, nametable, con.getArrayInitializer(), typetolookin);
+    }
+    
+    if(this.trialcheck) {
+      // for a trialcheck of an inline class, skip the rest process
+      return;
     }
 
     /* Check flag effects */
@@ -1105,7 +1371,25 @@ public class SemanticCheck {
       // Array's don't need constructor calls
       ClassDescriptor classtolookin = typetolookin.getClassDesc();
       checkClass(classtolookin, INIT);
-
+      if( classtolookin.isInnerClass() ) {
+       // for inner class that is declared in a static context, it does not have 
+       // lexically enclosing instances
+       if(!classtolookin.getInStaticContext()) {
+           InnerClassAddParamToCtor( (MethodDescriptor)md, ((MethodDescriptor)md).getClassDesc() , nametable, con, td );
+       }
+       if(classtolookin.getInline()) {
+         // for an inline anonymous inner class, the live local variables that are 
+         // referred to by the inline class are passed as parameters of the constructors
+         // of the inline class
+         InlineClassAddParamToCtor( (MethodDescriptor)md, classtolookin, nametable, con, td, tdarray );
+       }
+        tdarray = new TypeDescriptor[con.numArgs()];
+        for (int i = 0; i < con.numArgs(); i++) {
+          ExpressionNode en = con.getArg(i);
+          checkExpressionNode(md, nametable, en, null);
+          tdarray[i] = en.getType();
+        }
+      }
       Set methoddescriptorset = classtolookin.getMethodTable().getSet(classtolookin.getSymbol());
       MethodDescriptor bestmd = null;
 NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.hasNext(); ) {
@@ -1125,14 +1409,14 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
         if (bestmd == null)
           bestmd = currmd;
         else {
-          if (typeutil.isMoreSpecific(currmd, bestmd)) {
+          if (typeutil.isMoreSpecific(currmd, bestmd, true)) {
             bestmd = currmd;
           } else if (con.isGlobal() && match(currmd, bestmd)) {
             if (currmd.isGlobal() && !bestmd.isGlobal())
               bestmd = currmd;
             else if (currmd.isGlobal() && bestmd.isGlobal())
               throw new Error();
-          } else if (!typeutil.isMoreSpecific(bestmd, currmd)) {
+          } else if (!typeutil.isMoreSpecific(bestmd, currmd, true)) {
             throw new Error("No method is most specific:" + bestmd + " and " + currmd);
           }
 
@@ -1182,6 +1466,41 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
     }
   }
 
+  MethodDescriptor recurseSurroundingClassesM( ClassDescriptor icd, String varname ) {
+      if( null == icd || false == icd.isInnerClass() )
+           return null;
+    
+      ClassDescriptor surroundingDesc = icd.getSurroundingDesc();
+      if( null == surroundingDesc )
+           return null;
+    
+      SymbolTable methodTable = surroundingDesc.getMethodTable();
+      MethodDescriptor md = ( MethodDescriptor ) methodTable.get( varname );
+      if( null != md )
+           return md;
+      return recurseSurroundingClassesM( surroundingDesc, varname );
+  }
+
+  ExpressionNode methodInvocationExpression( ClassDescriptor icd, MethodDescriptor md, int linenum ) {
+       ClassDescriptor cd = md.getClassDesc();
+       int depth = 1;
+       int startingDepth = icd.getInnerDepth();
+
+       if( true == cd.isInnerClass() ) 
+               depth = cd.getInnerDepth();
+
+       String composed = "this";
+       NameDescriptor runningDesc = new NameDescriptor( "this" );;
+       
+       for ( int index = startingDepth; index > depth; --index ) {
+               composed = "this$" + String.valueOf( index - 1  );      
+               runningDesc = new NameDescriptor( runningDesc, composed );
+       }
+       if( false == cd.isInnerClass() )
+               runningDesc = new NameDescriptor( runningDesc, "this$" + String.valueOf(0) ); //all the way up.
+
+       return new NameNode(runningDesc);
+}
 
   void checkMethodInvokeNode(Descriptor md, SymbolTable nametable, MethodInvokeNode min, TypeDescriptor td) {
     /*Typecheck subexpressions
@@ -1245,6 +1564,25 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
       ClassDescriptor supercd=((MethodDescriptor)md).getClassDesc().getSuperDesc();
       min.methodid=supercd.getSymbol();
       typetolookin=new TypeDescriptor(supercd);
+      if(supercd.isInnerClass()&&!supercd.isStatic()&&!supercd.getInStaticContext()) {
+       // for a super class that is also an inner class with surrounding reference, add the surrounding 
+       // instance of the child instance as the parent instance's surrounding instance
+       if(((MethodDescriptor)md).isConstructor()) {
+         min.addArgument(new NameNode(new NameDescriptor("surrounding$0")));
+       } else if(((MethodDescriptor)md).getClassDesc().isInnerClass()&&!((MethodDescriptor)md).getClassDesc().isStatic()&&!((MethodDescriptor)md).getClassDesc().getInStaticContext()) {
+         min.addArgument(new NameNode(new NameDescriptor("this$0")));
+       }
+      }
+      tdarray=new TypeDescriptor[min.numArgs()];
+      for(int i=0; i<min.numArgs(); i++) {
+        ExpressionNode en=min.getArg(i);
+        checkExpressionNode(md,nametable,en,null);
+        tdarray[i]=en.getType();
+
+        if(en.getType().isClass() && en.getType().getClassDesc().isEnum()) {
+          tdarray[i] = new TypeDescriptor(TypeDescriptor.INT);
+        }
+      }
     } else if (md instanceof MethodDescriptor) {
       typetolookin=new TypeDescriptor(((MethodDescriptor)md).getClassDesc());
     } else {
@@ -1276,16 +1614,32 @@ NextMethod:
       if (bestmd==null)
         bestmd=currmd;
       else {
-        if (typeutil.isMoreSpecific(currmd,bestmd)) {
+        if (typeutil.isMoreSpecific(currmd,bestmd, false)) {
           bestmd=currmd;
-        } else if (!typeutil.isMoreSpecific(bestmd, currmd))
-          throw new Error("No method is most specific:"+bestmd+" and "+currmd);
+        } else if (!typeutil.isMoreSpecific(bestmd, currmd, false)) {
+          // if the two methods are inherited from super class/interface, use the super class' as first priority
+          if(bestmd.getClassDesc().isInterface()&&!currmd.getClassDesc().isInterface()) {
+            bestmd = currmd;
+          } else {
+            throw new Error("No method is most specific:"+bestmd+" and "+currmd);
+          }
+        }
 
         /* Is this more specific than bestmd */
       }
     }
-    if (bestmd==null)
-      throw new Error("No method found for :"+min.printNode(0)+" in class: " + classtolookin+" in "+md);
+    if (bestmd==null) {
+      // if this is an inner class, need to check the method table for the surrounding class
+      bestmd = recurseSurroundingClassesM(classtolookin, min.getMethodName());
+      if(bestmd == null)
+         throw new Error("No method found for :"+min.printNode(0)+" in class: " + classtolookin+" in "+md);
+      else {
+         // set the correct "this" expression here
+         ExpressionNode en=methodInvocationExpression(classtolookin, bestmd, min.getNumLine());
+         min.setExpression(en);
+         checkExpressionNode(md, nametable, min.getExpression(), null);
+      }
+    }
     min.setMethod(bestmd);
 
     if ((td!=null)&&(min.getType()!=null)&&!typeutil.isSuperorType(td,  min.getType()))