Changes to MGC class library and fix a bug regarding nested inline class declaration
[IRC.git] / Robust / src / IR / Tree / SemanticCheck.java
index 55b6f77e7c1547c76dfdae244b0efdd2ae717865..dc08789b384c65b0a51cab3ba4ce225c8bb19530 100644 (file)
@@ -10,6 +10,9 @@ public class SemanticCheck {
   Stack loopstack;
   HashSet toanalyze;
   HashMap<ClassDescriptor, Integer> completed;
+  HashMap<ClassDescriptor, Vector<VarDescriptor>> inlineClass2LiveVars;
+  boolean trialcheck = false;
+  Vector<ClassDescriptor> inlineClassWithTrialCheck;
 
   public static final int NOCHECK=0;
   public static final int REFERENCE=1;
@@ -32,6 +35,8 @@ public class SemanticCheck {
     this.toanalyze=new HashSet();
     this.completed=new HashMap<ClassDescriptor, Integer>();
     this.checkAll=checkAll;
+    this.inlineClass2LiveVars = new HashMap<ClassDescriptor, Vector<VarDescriptor>>();
+    this.inlineClassWithTrialCheck = new Vector<ClassDescriptor>();
   }
 
   public ClassDescriptor getClass(ClassDescriptor context, String classname) {
@@ -116,6 +121,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();
@@ -137,39 +168,7 @@ public class SemanticCheck {
       } else {
         ClassDescriptor cd = (ClassDescriptor) obj;
         toanalyze.remove(cd);
-        if(cd.getInline()) {
-          getClass(cd, cd.getSymbol());
-          // 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);
-            getClass(surroundingcd, surroundingcd.getSymbol());
-            for (Iterator method_it = surroundingcd.getMethods(); method_it.hasNext(); ) {
-              MethodDescriptor md = (MethodDescriptor) method_it.next();
-              try {
-                checkMethodBody(surroundingcd, md);
-              } catch (Error e) {
-                System.out.println("Error in " + md);
-                throw e;
-              }
-            }
-          }
-        } else {
-          // 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);
       }
     }
   }
@@ -324,8 +323,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);
@@ -336,7 +336,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.inlineClassWithTrialCheck.contains(cd)) && (superdesc!=null)) {
       Set possiblematches=superdesc.getMethodTable().getSet(md.getSymbol());
       for(Iterator methodit=possiblematches.iterator(); methodit.hasNext(); ) {
         MethodDescriptor matchmd=(MethodDescriptor)methodit.next();
@@ -431,6 +432,8 @@ public class SemanticCheck {
     if ((d==null)||
         (d instanceof FieldDescriptor)) {
       nametable.add(vd);
+    } else if((md instanceof MethodDescriptor) && (((MethodDescriptor)md).getClassDesc().getInline()) && this.inlineClassWithTrialCheck.contains(((MethodDescriptor)md).getClassDesc())) {
+      // 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)
@@ -443,6 +446,8 @@ public class SemanticCheck {
     if ((d==null)||
         (d instanceof FieldDescriptor)) {
       nametable.add(vd);
+    } else if((md instanceof MethodDescriptor) && (((MethodDescriptor)md).getClassDesc().getInline()) && this.inlineClassWithTrialCheck.contains(((MethodDescriptor)md).getClassDesc())) {
+      // 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");
   }
@@ -720,6 +725,23 @@ public class SemanticCheck {
          }
          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()) {
@@ -862,6 +884,21 @@ public class SemanticCheck {
                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();
 
@@ -883,6 +920,28 @@ public class SemanticCheck {
        FieldAccessNode theFieldNode = ( FieldAccessNode )translateNameDescriptorintoExpression( idDesc, linenum );
        return theFieldNode;
   }
+  
+  Descriptor searchSurroundingNameTable(ClassDescriptor cd, String varname) {
+    Descriptor d = null;
+    if(cd.getInline()&&this.trialcheck) {
+      d = cd.getSurroundingNameTable().get(varname);
+    } else {
+      return d;
+    }
+    if(null == d) {
+      d = searchSurroundingNameTable(cd.getSurroundingDesc(), 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);
+      }
+    }
+    return d;
+  }
 
   void checkNameNode(Descriptor md, SymbolTable nametable, NameNode nn, TypeDescriptor td) {
     NameDescriptor nd=nn.getName();
@@ -913,8 +972,12 @@ public class SemanticCheck {
                        nn.setExpression(( ExpressionNode )theFieldNode);
                        checkExpressionNode(md,nametable,( ExpressionNode )theFieldNode,td);
                        return;         
+               } else {
+                   // for the trial check of an inline class, cache the unknown var
+                   d = searchSurroundingNameTable(cd, varname);
                }
        }
+       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();
@@ -964,6 +1027,7 @@ public class SemanticCheck {
             throw new Error("Name "+varname+" undefined in: "+md);         
           }
         }
+       }
       }
 
       if (d instanceof VarDescriptor) {
@@ -1036,31 +1100,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.dereference());
-      vec_type.add(ain.getVarInitializer(i).getType());
     }
     if (td==null)
-      throw new Error();
-
+       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) {
@@ -1151,12 +1219,15 @@ public class SemanticCheck {
 
   void InnerClassAddParamToCtor( MethodDescriptor md, ClassDescriptor cd, SymbolTable nametable, 
                                 CreateObjectNode con, TypeDescriptor td ) {
-       
+    if(this.inlineClassWithTrialCheck.contains(cd)) {
+      // this class has done this with its first trial check
+      return;
+    }
        TypeDescriptor cdsType = new TypeDescriptor( cd );
        ExpressionNode conExp = con.getSurroundingClassExpression();
        //System.out.println( "The surrounding class expression si " + con );
        if( null == conExp ) {
-               if( md.isStatic() ) {
+               if( md.isStatic()) {
                        throw new Error("trying to instantiate inner class: " +  con.getType() + " in a static scope" );
                }
                VarDescriptor thisVD = md.getThis();
@@ -1177,34 +1248,101 @@ public class SemanticCheck {
        //System.out.println( " the modified createObjectNode is " + con.printNode( 0 ) + "\n" );
 }
   
-  // add all the vars in the surrounding context of the inline class into the inline 
-  // classes field table and pass them to the inline class' constructors
-  // TODO: BUGFIX. There need not add all the local vars of the surrounding context 
-  // into the inline class. Should only add those that are referred to inside the inline
-  // class. Also these local vars should be final. But currently we've lost those 
+  void trialSemanticCheck(ClassDescriptor cd) {
+    if(this.inlineClassWithTrialCheck.contains(cd)) {
+      // this inline class has done trial check
+      return;
+    }
+    if(!cd.getInline()) {
+      throw new Error("Error! Try to do a trial check on a non-inline class " + cd.getSymbol());
+    }
+    boolean settrial = false;
+    if(!trialcheck) {
+      trialcheck = true;
+      settrial = 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;
+      }
+    }
+    this.inlineClassWithTrialCheck.add(cd);
+    if(settrial) {
+      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 ) {
-      Iterator it_values = nametable.getAllValueSet().iterator();
-      while(it_values.hasNext()) {
-         Descriptor d = (Descriptor)it_values.next();
-         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));
-             for(Iterator it_methods = cd.getMethods(); it_methods.hasNext();) {
-                 MethodDescriptor imd = (MethodDescriptor)it_methods.next();
-                 if(imd.isConstructor()) {
-                     imd.addParameter(((VarDescriptor)d).getType(), d.getSymbol()+"_p");
-                     // add the initialize statement into this constructor
-                     BlockNode obn = state.getMethodBody(imd);
-                     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(imd, obn);
-                 }
-             }
-         }
+  void InlineClassAddParamToCtor(MethodDescriptor md, ClassDescriptor cd , SymbolTable nametable, CreateObjectNode con, TypeDescriptor td, TypeDescriptor[] tdarray ) {
+    if(this.inlineClassWithTrialCheck.contains(cd)) {
+      // this class has done this with its first trial check
+      return;
+    }
+    // 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);
+      if(null != min) {
+       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,
@@ -1264,18 +1402,23 @@ public class SemanticCheck {
       ClassDescriptor classtolookin = typetolookin.getClassDesc();
       checkClass(classtolookin, INIT);
       if( classtolookin.isInnerClass() ) {
-       InnerClassAddParamToCtor( (MethodDescriptor)md, ((MethodDescriptor)md).getClassDesc() , nametable, con, td );
+       // 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, all the local variables are passed as
-         // parameters of the constructors of the inline class
-         InlineClassAddParamToCtor( (MethodDescriptor)md, classtolookin, nametable, con, td );
+         // 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();
-        }
+        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;
@@ -1296,14 +1439,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);
           }
 
@@ -1451,6 +1594,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 {
@@ -1482,10 +1644,18 @@ 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 if(!bestmd.getClassDesc().isInterface()&&currmd.getClassDesc().isInterface()) {
+            // maintain the non-interface one
+          } else {
+            throw new Error("No method is most specific:"+bestmd+" and "+currmd);
+          }
+        }
 
         /* Is this more specific than bestmd */
       }