Bug fix of inner class: only add LIVE local variables that are referred to in an...
[IRC.git] / Robust / src / IR / Tree / SemanticCheck.java
index 1f14bf6ed88ff296a80f708640d2dc9aef929745..406591e6b10d058314b280bef677edaf6eae55a4 100644 (file)
@@ -10,10 +10,9 @@ public class SemanticCheck {
   Stack loopstack;
   HashSet toanalyze;
   HashMap<ClassDescriptor, Integer> completed;
+  HashMap<ClassDescriptor, Vector<VarDescriptor>> inlineClass2LiveVars;
+  boolean trialcheck = false;
 
-  //This is the class mappings for a particular file based
-  //on the import names. Maps class to canonical class name.
-  static Hashtable singleImportMap;
   public static final int NOCHECK=0;
   public static final int REFERENCE=1;
   public static final int INIT=2;
@@ -35,20 +34,15 @@ 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) {
     return getClass(context, classname, INIT);
   }
-  public ClassDescriptor getClass(ClassDescriptor context, String classname, int fullcheck) {
-    if (context!=null) {
-//      System.out.println(context.getSymbol() + " is looking for " + classname);
-      Hashtable remaptable=context.getSingleImportMappings();
-      classname=remaptable.containsKey(classname)?((String)remaptable.get(classname)):classname;
-    }
-    ClassDescriptor cd=typeutil.getClass(classname, toanalyze);
+  public ClassDescriptor getClass(ClassDescriptor context, String classnameIn, int fullcheck) {
+    ClassDescriptor cd=typeutil.getClass(context, classnameIn, toanalyze);
     checkClass(cd, fullcheck);
-
     return cd;
   }
 
@@ -64,17 +58,28 @@ public class SemanticCheck {
       if (fullcheck>=REFERENCE&&oldstatus<INIT) {
         //Set superclass link up
         if (cd.getSuper()!=null) {
-          cd.setSuper(getClass(cd, cd.getSuper(), fullcheck));
-          if(cd.getSuperDesc().isInterface()) {
-            throw new Error("Error! Class " + cd.getSymbol() + " extends interface " + cd.getSuper());
-          }
-          // Link together Field, Method, and Flag tables so classes
-          // inherit these from their superclasses
-          if (oldstatus<REFERENCE) {
-            cd.getFieldTable().setParent(cd.getSuperDesc().getFieldTable());
-            cd.getMethodTable().setParent(cd.getSuperDesc().getMethodTable());
-            cd.getFlagTable().setParent(cd.getSuperDesc().getFlagTable());
-          }
+         ClassDescriptor superdesc=getClass(cd, cd.getSuper(), fullcheck);
+         if (superdesc.isInnerClass()) {
+           cd.setAsInnerClass();
+         }
+         if (superdesc.isInterface()) {
+           if (cd.getInline()) {
+             cd.setSuper(null);
+             cd.getSuperInterface().add(superdesc.getSymbol());
+           } else {
+             throw new Error("Error! Class " + cd.getSymbol() + " extends interface " + cd.getSuper());
+           }
+         } else {
+           cd.setSuperDesc(superdesc);
+
+           // Link together Field, Method, and Flag tables so classes
+           // inherit these from their superclasses
+           if (oldstatus<REFERENCE) {
+             cd.getFieldTable().setParent(cd.getSuperDesc().getFieldTable());
+             cd.getMethodTable().setParent(cd.getSuperDesc().getMethodTable());
+             cd.getFlagTable().setParent(cd.getSuperDesc().getFlagTable());
+           }
+         }
         }
         // Link together Field, Method tables do classes inherit these from
         // their ancestor interfaces
@@ -86,8 +91,8 @@ public class SemanticCheck {
           }
           if (oldstatus<REFERENCE) {
             cd.addSuperInterfaces(superif);
-            cd.getFieldTable().addParentIF(superif.getFieldTable());
             cd.getMethodTable().addParentIF(superif.getMethodTable());
+            cd.getFieldTable().addParentIF(superif.getFieldTable());
           }
         }
       }
@@ -95,15 +100,51 @@ public class SemanticCheck {
         /* Check to see that fields are well typed */
         for(Iterator field_it=cd.getFields(); field_it.hasNext(); ) {
           FieldDescriptor fd=(FieldDescriptor)field_it.next();
+         try {
           checkField(cd,fd);
+         } catch (Error e) {
+           System.out.println("Class/Field in "+cd+":"+fd);
+           throw e;
+         }
         }
         for(Iterator method_it=cd.getMethods(); method_it.hasNext(); ) {
           MethodDescriptor md=(MethodDescriptor)method_it.next();
+         try {
           checkMethod(cd,md);
+         } catch (Error e) {
+           System.out.println("Class/Method in "+cd+":"+md);
+           throw e;
+         }
         }
       }
     }
   }
+  
+  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();
@@ -125,21 +166,7 @@ public class SemanticCheck {
       } else {
         ClassDescriptor cd = (ClassDescriptor) obj;
         toanalyze.remove(cd);
-        //set the class mappings based on imports.
-        singleImportMap = cd.getSingleImportMappings();
-
-        // 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);
       }
     }
   }
@@ -294,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);
@@ -382,6 +410,7 @@ public class SemanticCheck {
 
     case Kind.SESENode:
     case Kind.GenReachNode:
+    case Kind.GenDefReachNode:
       // do nothing, no semantic check for SESEs
       return;
     }
@@ -619,25 +648,78 @@ public class SemanticCheck {
     if (typeutil.isCastable(etd, cast_type))
       return;
 
+    //rough hack to handle interfaces...should clean up
+    if (etd.isClass()&&cast_type.isClass()) {
+      ClassDescriptor cdetd=etd.getClassDesc();
+      ClassDescriptor cdcast_type=cast_type.getClassDesc();
+
+      if (cdetd.isInterface()&&!cdcast_type.getModifier().isFinal())
+       return;
+      
+      if (cdcast_type.isInterface()&&!cdetd.getModifier().isFinal())
+       return;
+    }
     /* Different branches */
     /* TODO: change if add interfaces */
     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);
     TypeDescriptor ltd=left.getType();
+    if (!ltd.isArray())
+      checkClass(ltd.getClassDesc(), INIT);
     String fieldname=fan.getFieldName();
 
     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();
+       }
+      }
+
       if(ltd.getClassDesc().isEnum()) {
         int value = ltd.getClassDesc().getEnumConstant(fieldname);
         if(-1 == value) {
@@ -659,8 +741,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);
@@ -743,6 +839,49 @@ 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();
+       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) {
@@ -753,14 +892,38 @@ 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(!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();
@@ -807,10 +970,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) {
@@ -860,8 +1025,6 @@ public class SemanticCheck {
 
     if (td!=null) {
       if (!typeutil.isSuperorType(td, ofn.getType())) {
-        System.out.println(td);
-        System.out.println(ofn.getType());
         throw new Error("Type of rside not compatible with type of lside"+ofn.printNode(0));
       }
     }
@@ -885,48 +1048,13 @@ 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());
+      checkExpressionNode(md, nametable, ain.getVarInitializer(i), td.dereference());
       vec_type.add(ain.getVarInitializer(i).getType());
     }
-    // descide the type of this variableInitializerNode
-    TypeDescriptor out_type = vec_type.elementAt(0);
-    for(int i = 1; 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);
-      //out_type.setStatic();
-    }
-    ain.setType(out_type);
+    if (td==null)
+      throw new Error();
+
+    ain.setType(td);
   }
 
   void checkAssignmentNode(Descriptor md, SymbolTable nametable, AssignmentNode an, TypeDescriptor td) {
@@ -1031,7 +1159,106 @@ 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_construtor = null;
+    for(Iterator it_methods = cd.getMethods(); it_methods.hasNext();) {
+      MethodDescriptor imd = (MethodDescriptor)it_methods.next();
+      if(imd.isConstructor()) {
+       cd_construtor = 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_construtor);
+      bn.addFirstBlockStatement(ben);
+    }
+    for(int i = 0 ; i < tdarray.length; i++) {
+      assert(null!=min);
+      TypeDescriptor itd = tdarray[i];
+      cd_construtor.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);
+    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_construtor.addParameter(((VarDescriptor)d).getType(), d.getSymbol()+"_p");
+       // add the initialize statement into this constructor
+       BlockNode obn = state.getMethodBody(cd_construtor);
+       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_construtor, obn);
+      }
+    }
+  }
+  
   void checkCreateObjectNode(Descriptor md, SymbolTable nametable, CreateObjectNode con,
                              TypeDescriptor td) {
     TypeDescriptor[] tdarray = new TypeDescriptor[con.numArgs()];
@@ -1049,7 +1276,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 */
@@ -1088,8 +1320,22 @@ public class SemanticCheck {
       // Array's don't need constructor calls
       ClassDescriptor classtolookin = typetolookin.getClassDesc();
       checkClass(classtolookin, INIT);
-
-      Set methoddescriptorset = classtolookin.getMethodTable().getSet(typetolookin.getSymbol());
+      if( classtolookin.isInnerClass() ) {
+       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(); ) {
         MethodDescriptor currmd = (MethodDescriptor) methodit.next();
@@ -1122,8 +1368,9 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
           /* Is this more specific than bestmd */
         }
       }
-      if (bestmd == null)
+      if (bestmd == null) {
         throw new Error("No method found for " + con.printNode(0) + " in " + md);
+      }
       con.setConstructor(bestmd);
     }
   }
@@ -1164,6 +1411,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
@@ -1178,6 +1460,7 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
       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);
       }
@@ -1186,9 +1469,6 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
     if (min.getExpression()!=null) {
       checkExpressionNode(md,nametable,min.getExpression(),null);
       typetolookin=min.getExpression().getType();
-      //if (typetolookin==null)
-      //throw new Error(md+" has null return type");
-
     } else if (min.getBaseName()!=null) {
       String rootname=min.getBaseName().getRoot();
       if (rootname.equals("super")) {
@@ -1207,7 +1487,7 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
         checkExpressionNode(md, nametable, min.getExpression(), null);
         typetolookin=min.getExpression().getType();
       } else {
-        if(!min.getBaseName().getSymbol().equals("System.out")) {
+        if(!min.getBaseName().getSymbol().equals("System.out")||state.JNI) {
           ExpressionNode nn = translateNameDescriptorintoExpression(min.getBaseName(),min.getNumLine());
           checkExpressionNode(md, nametable, nn, null);
           typetolookin = nn.getType();
@@ -1218,12 +1498,8 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
           }
         } else {
           //we have a type
-          ClassDescriptor cd = null;
-          //if (min.getBaseName().getSymbol().equals("System.out"))
-          cd=getClass(null, "System");
-          /*else {
-             cd=getClass(min.getBaseName().getSymbol());
-             }*/
+          ClassDescriptor cd = getClass(null, "System");
+
           if (cd==null)
             throw new Error("md = "+ md.toString()+ "  "+min.getBaseName()+" undefined");
           typetolookin=new TypeDescriptor(cd);
@@ -1240,11 +1516,9 @@ NextMethod: for (Iterator methodit = methoddescriptorset.iterator(); methodit.ha
       throw new Error("Unknown method call to "+min.getMethodName()+"in task"+md.getSymbol());
     }
     if (!typetolookin.isClass())
-      throw new Error("Error with method call to "+min.getMethodName());
+      throw new Error("Error with method call to "+min.getMethodName()+" in class "+typetolookin);
     ClassDescriptor classtolookin=typetolookin.getClassDesc();
-    checkClass(classtolookin, INIT);
-    //System.out.println("Method name="+min.getMethodName());
-
+    checkClass(classtolookin, REFERENCE);
     Set methoddescriptorset=classtolookin.getMethodTable().getSet(min.getMethodName());
     MethodDescriptor bestmd=null;
 NextMethod:
@@ -1274,8 +1548,18 @@ NextMethod:
         /* 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()))
@@ -1536,8 +1820,6 @@ NextMethod:
 
     if (td!=null)
       if (!typeutil.isSuperorType(td, on.getType())) {
-        System.out.println(td);
-        System.out.println(on.getType());
         throw new Error("Type of rside not compatible with type of lside"+on.printNode(0));
       }
   }