import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / lookup / Scope.java
index bfbb0b5..9b0209f 100644 (file)
  *******************************************************************************/
 package org.eclipse.jdt.internal.compiler.lookup;
 
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.eclipse.jdt.core.compiler.CharOperation;
 import org.eclipse.jdt.internal.compiler.ast.*;
 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
@@ -20,22 +25,19 @@ import org.eclipse.jdt.internal.compiler.util.HashtableOfObject;
 import org.eclipse.jdt.internal.compiler.util.ObjectVector;
 
 public abstract class Scope
-       implements BaseTypes, BindingIds, CompilerModifiers, ProblemReasons, TagBits, TypeConstants, TypeIds {
+       implements BaseTypes, CompilerModifiers, ProblemReasons, TagBits, TypeConstants, TypeIds {
 
        public final static int BLOCK_SCOPE = 1;
-       public final static int METHOD_SCOPE = 2;
        public final static int CLASS_SCOPE = 3;
        public final static int COMPILATION_UNIT_SCOPE = 4;
+       public final static int METHOD_SCOPE = 2;
 
-       public int kind;
-       public Scope parent;
-
-       protected Scope(int kind, Scope parent) {
-               this.kind = kind;
-               this.parent = parent;
-       }
+       public final static int NOT_COMPATIBLE = -1;
+       public final static int COMPATIBLE = 0;
+       public final static int AUTOBOX_COMPATIBLE = 1;
+       public final static int VARARGS_COMPATIBLE = 2;
 
-       /* Answer an int describing the relationship between the given types.
+   /* Answer an int describing the relationship between the given types.
        *
        *               NotRelated 
        *               EqualOrMoreSpecific : left is compatible with right
@@ -49,22 +51,128 @@ public abstract class Scope
                return NotRelated;
        }
 
-       // Internal use only
-       protected final boolean areParametersAssignable(TypeBinding[] parameters, TypeBinding[] arguments) {
-               if (parameters == arguments)
-                       return true;
+       /**
+        * Returns an array of types, where original types got substituted given a substitution.
+        * Only allocate an array if anything is different.
+        */
+       public static ReferenceBinding[] substitute(Substitution substitution, ReferenceBinding[] originalTypes) {
+           ReferenceBinding[] substitutedTypes = originalTypes;
+           for (int i = 0, length = originalTypes.length; i < length; i++) {
+               ReferenceBinding originalType = originalTypes[i];
+               ReferenceBinding substitutedParameter = (ReferenceBinding)substitution.substitute(originalType);
+               if (substitutedParameter != originalType) {
+                   if (substitutedTypes == originalTypes) {
+                       System.arraycopy(originalTypes, 0, substitutedTypes = new ReferenceBinding[length], 0, i);
+                   }
+                   substitutedTypes[i] = substitutedParameter;
+               } else if (substitutedTypes != originalTypes) {
+                   substitutedTypes[i] = originalType;
+               }
+           }
+           return substitutedTypes;
+       }
+
+       /**
+        * Returns an array of types, where original types got substituted given a substitution.
+        * Only allocate an array if anything is different.
+        */
+       public static TypeBinding[] substitute(Substitution substitution, TypeBinding[] originalTypes) {
+           TypeBinding[] substitutedTypes = originalTypes;
+           for (int i = 0, length = originalTypes.length; i < length; i++) {
+               TypeBinding originalType = originalTypes[i];
+               TypeBinding substitutedParameter = substitution.substitute(originalType);
+               if (substitutedParameter != originalType) {
+                   if (substitutedTypes == originalTypes) {
+                       System.arraycopy(originalTypes, 0, substitutedTypes = new TypeBinding[length], 0, i);
+                   }
+                   substitutedTypes[i] = substitutedParameter;
+               } else if (substitutedTypes != originalTypes) {
+                   substitutedTypes[i] = originalType;
+               }
+           }
+           return substitutedTypes;
+       }
 
-               int length = parameters.length;
-               if (length != arguments.length)
-                       return false;
+       public int kind;
+       public Scope parent;
+
+       protected Scope(int kind, Scope parent) {
+               this.kind = kind;
+               this.parent = parent;
+       }
 
-               for (int i = 0; i < length; i++)
-                       if (parameters[i] != arguments[i])
-                               if (!arguments[i].isCompatibleWith(parameters[i]))
-                                       return false;
-               return true;
+       /*
+        * Boxing primitive
+        */
+       public int boxing(int id) {
+               switch (id) {
+                       case T_int :
+                               return T_JavaLangInteger;
+                       case T_byte :
+                               return T_JavaLangByte;
+                       case T_short :
+                               return T_JavaLangShort;
+                       case T_char :
+                               return T_JavaLangCharacter;
+                       case T_long :
+                               return T_JavaLangLong;
+                       case T_float :
+                               return T_JavaLangFloat;
+                       case T_double :
+                               return T_JavaLangDouble;
+                       case T_boolean :
+                               return T_JavaLangBoolean;
+                       case T_void :
+                               return T_JavaLangVoid;
+               }
+               return id;
        }
-       
+       /*
+        * Boxing primitive
+        */
+       public TypeBinding boxing(TypeBinding type) {
+               TypeBinding boxedType;
+               switch (type.id) {
+                       case T_int :
+                               boxedType = environment().getType(JAVA_LANG_INTEGER);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_INTEGER, NotFound);                           
+                       case T_byte :
+                               boxedType = environment().getType(JAVA_LANG_BYTE);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_BYTE, NotFound);                              
+                       case T_short :
+                               boxedType = environment().getType(JAVA_LANG_SHORT);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_SHORT, NotFound);                             
+                       case T_char :
+                               boxedType = environment().getType(JAVA_LANG_CHARACTER);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_CHARACTER, NotFound);                         
+                       case T_long :
+                               boxedType = environment().getType(JAVA_LANG_LONG);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_LONG, NotFound);                              
+                       case T_float :
+                               boxedType = environment().getType(JAVA_LANG_FLOAT);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_FLOAT, NotFound);                             
+                       case T_double :
+                               boxedType = environment().getType(JAVA_LANG_DOUBLE);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_DOUBLE, NotFound);                            
+                       case T_boolean :
+                               boxedType = environment().getType(JAVA_LANG_BOOLEAN);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_BOOLEAN, NotFound);                           
+                       case T_void :
+                               boxedType = environment().getType(JAVA_LANG_VOID);
+                               if (boxedType != null) return boxedType;
+                               return new ProblemReferenceBinding(     JAVA_LANG_VOID, NotFound);                              
+               }
+               return type;
+       }       
+
        public final ClassScope classScope() {
                Scope scope = this;
                do {
@@ -97,16 +205,264 @@ public abstract class Scope
                return (CompilationUnitScope) lastScope;
        }
 
-       public ArrayBinding createArray(TypeBinding type, int dimension) {
-               if (!type.isValidBinding())
-                       return new ArrayBinding(type, dimension);
-               return environment().createArrayType(type, dimension);
+       /**
+        * Internal use only
+        * Given a method, returns null if arguments cannot be converted to parameters.
+        * Will answer a subsituted method in case the method was generic and type inference got triggered;
+        * in case the method was originally compatible, then simply answer it back.
+        */
+       protected final MethodBinding computeCompatibleMethod(MethodBinding method, TypeBinding[] arguments, InvocationSite invocationSite) {
+
+               TypeBinding[] genericTypeArguments = invocationSite.genericTypeArguments();
+               TypeBinding[] parameters = method.parameters;
+               TypeVariableBinding[] typeVariables = method.typeVariables;
+               if (parameters == arguments
+                       && (method.returnType.tagBits & HasTypeVariable) == 0 
+                       && genericTypeArguments == null
+                       && typeVariables == NoTypeVariables)
+                               return method;
+
+               int argLength = arguments.length;
+               int paramLength = parameters.length;
+               boolean isVarArgs = method.isVarargs();
+               if (argLength != paramLength)
+                       if (!isVarArgs || argLength < paramLength - 1)
+                               return null; // incompatible
+
+               if (typeVariables != NoTypeVariables) { // generic method
+                       method = ParameterizedGenericMethodBinding.computeCompatibleMethod(method, arguments, this, invocationSite);
+                       if (method == null) return null; // incompatible
+                       if (!method.isValidBinding()) return method; // bound check issue is taking precedence
+                       parameters = method.parameters; // reacquire them after type inference has performed
+               } else if (genericTypeArguments != null) {
+                       if (method instanceof ParameterizedGenericMethodBinding) {
+                               if (!((ParameterizedGenericMethodBinding) method).wasInferred) {
+                                       // attempt to invoke generic method of raw type with type hints <String>foo()
+                                       return new ProblemMethodBinding(method, method.selector, genericTypeArguments, TypeArgumentsForRawGenericMethod);
+                               }
+                       } else {
+                               return new ProblemMethodBinding(method, method.selector, genericTypeArguments, TypeParameterArityMismatch);
+                       }
+               }
+
+               if (parameterCompatibilityLevel(method, arguments) > NOT_COMPATIBLE)
+                       return method;
+               if (genericTypeArguments != null)
+                       return new ProblemMethodBinding(method, method.selector, arguments, ParameterizedMethodTypeMismatch);
+               return null; // incompatible
+       }
+       
+       protected boolean connectTypeVariables(TypeParameter[] typeParameters) {
+               boolean noProblems = true;
+               if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5) return true;
+
+               nextVariable : for (int i = 0, paramLength = typeParameters.length; i < paramLength; i++) {
+                       TypeParameter typeParameter = typeParameters[i];
+                       TypeVariableBinding typeVariable = typeParameter.binding;
+                       if (typeVariable == null) return false;
+
+                       typeVariable.superclass = getJavaLangObject();
+                       typeVariable.superInterfaces = NoSuperInterfaces;
+                       // set firstBound to the binding of the first explicit bound in parameter declaration
+                       typeVariable.firstBound = null; // first bound used to compute erasure
+
+                       TypeReference typeRef = typeParameter.type;
+                       if (typeRef == null)
+                               continue nextVariable;
+                       ReferenceBinding superType = this.kind == METHOD_SCOPE
+                               ? (ReferenceBinding) typeRef.resolveType((BlockScope)this, false/*no bound check*/)
+                               : (ReferenceBinding) typeRef.resolveType((ClassScope)this);
+                       if (superType == null) {
+                               typeVariable.tagBits |= HierarchyHasProblems;
+                               noProblems = false;
+                               continue nextVariable;
+                       }
+                       if (superType.isTypeVariable()) {
+                               TypeVariableBinding varSuperType = (TypeVariableBinding) superType;
+                               if (varSuperType.rank >= typeVariable.rank && varSuperType.declaringElement == typeVariable.declaringElement) {
+                                       problemReporter().forwardTypeVariableReference(typeParameter, varSuperType);
+                                       typeVariable.tagBits |= HierarchyHasProblems;
+                                       noProblems = false;
+                                       continue nextVariable;
+                               }
+                       }
+                       if (superType.isFinal())
+                               problemReporter().finalVariableBound(typeVariable, typeRef);
+                       typeRef.resolvedType = superType; // hold onto the problem type
+                       if (superType.isClass()) {
+                               typeVariable.superclass = superType;
+                       } else {
+                               typeVariable.superInterfaces = new ReferenceBinding[] {superType};
+                               typeVariable.modifiers |= AccInterface;
+                       }
+                       typeVariable.firstBound = superType; // first bound used to compute erasure
+
+                       TypeReference[] boundRefs = typeParameter.bounds;
+                       if (boundRefs != null) {
+                               for (int j = 0, k = boundRefs.length; j < k; j++) {
+                                       typeRef = boundRefs[j];
+                                       superType = this.kind == METHOD_SCOPE
+                                               ? (ReferenceBinding) typeRef.resolveType((BlockScope)this, false)
+                                               : (ReferenceBinding) typeRef.resolveType((ClassScope)this);
+                                       if (superType == null) {
+                                               typeVariable.tagBits |= HierarchyHasProblems;
+                                               noProblems = false;
+                                               continue nextVariable;
+                                       }
+                                       typeRef.resolvedType = superType; // hold onto the problem type
+                                       if (superType.isClass()) {
+                                               problemReporter().boundsMustBeAnInterface(typeRef, superType);
+                                               typeVariable.tagBits |= HierarchyHasProblems;
+                                               noProblems = false;
+                                               continue nextVariable;
+                                       }
+                                       if (superType.isParameterizedType()) {
+                                               ReferenceBinding match = typeVariable.superclass.findSuperTypeErasingTo((ReferenceBinding) superType.erasure());
+                                               boolean isCollision = match != null && match != superType;
+                                               for (int index = typeVariable.superInterfaces.length; !isCollision && --index >= 0;) {
+                                                       ReferenceBinding temp = typeVariable.superInterfaces[index];
+                                                       isCollision = superType != temp && superType.erasure() == temp.erasure();
+                                               }
+                                               if (isCollision) {
+                                                       problemReporter().boundHasConflictingArguments(typeRef, superType);
+                                                       typeVariable.tagBits |= HierarchyHasProblems;
+                                                       noProblems = false;
+                                                       continue nextVariable;
+                                               }
+                                       }
+                                       int size = typeVariable.superInterfaces.length;
+                                       System.arraycopy(typeVariable.superInterfaces, 0, typeVariable.superInterfaces = new ReferenceBinding[size + 1], 0, size);
+                                       typeVariable.superInterfaces[size] = superType;
+                               }
+                       }
+               }
+               return noProblems;
+       }
+
+       public TypeBinding convertToRawType(TypeBinding type) {
+               int dimension = type.dimensions();
+               TypeBinding originalType = type.leafComponentType();
+               if (originalType instanceof ReferenceBinding) {
+                       ReferenceBinding convertedType = (ReferenceBinding) originalType;
+                       ReferenceBinding originalEnclosing = originalType.enclosingType();
+                       ReferenceBinding convertedEnclosing = originalEnclosing;
+                       if (originalEnclosing != null && convertedType.isStatic() && originalEnclosing.isGenericType()) {
+                               convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing);
+                       }
+                       if (originalType.isGenericType()) {
+                               convertedType = environment().createRawType(convertedType, convertedEnclosing);
+                       } else if (originalEnclosing != convertedEnclosing) {
+                               convertedType = createParameterizedType(convertedType, null, convertedEnclosing);
+                       }
+                       if (originalType != convertedType) {
+                               return dimension > 0 ? (TypeBinding)createArrayType(convertedType, dimension) : convertedType;
+                       }
+               }
+               return type;
+       }
+//             TypeBinding leafType = type.leafComponentType();
+//             int dimension = type.dimensions();
+//             ReferenceBinding originalEnclosing = leafType.enclosingType();
+//             ReferenceBinding convertedEnclosing = originalEnclosing;
+//             if (originalEnclosing != null && ((ReferenceBinding)leafType).isStatic()) {
+//                     convertedEnclosing = (ReferenceBinding) convertToRawType(originalEnclosing);
+//             }
+//             if (leafType.isGenericType()) {
+//                     type = environment().createRawType((ReferenceBinding) leafType, convertedEnclosing);
+//                     if (dimension > 0) 
+//                             type = createArrayType(type, dimension);
+//             } else if (originalEnclosing != convertedEnclosing) {
+//                     type = createParameterizedType((ReferenceBinding)leafType, null, convertedEnclosing);
+//                     if (dimension > 0) 
+//                             type = createArrayType(type, dimension);
+//             }
+//         return type;
+
+       public ArrayBinding createArrayType(TypeBinding type, int dimension) {
+               if (type.isValidBinding())
+                       return environment().createArrayType(type, dimension);
+               // do not cache obvious invalid types
+               return new ArrayBinding(type, dimension, environment());
+       }
+       
+       public ParameterizedTypeBinding createParameterizedType(ReferenceBinding genericType, TypeBinding[] arguments, ReferenceBinding enclosingType) {
+               valid: {
+                       if (!genericType.isValidBinding()) break valid;
+                       for (int i = 0, max = arguments == null ? 0 : arguments.length; i < max; i++)
+                               if (!arguments[i].isValidBinding()) break valid;
+                       return environment().createParameterizedType(genericType, arguments, enclosingType);
+               }
+               return new ParameterizedTypeBinding(genericType, arguments, enclosingType, environment());
+       }
+       
+       public TypeVariableBinding[] createTypeVariables(TypeParameter[] typeParameters, Binding declaringElement) {
+
+               PackageBinding unitPackage = compilationUnitScope().fPackage;
+               
+               // do not construct type variables if source < 1.5
+               if (typeParameters == null || environment().options.sourceLevel < ClassFileConstants.JDK1_5)
+                       return NoTypeVariables;
+               TypeVariableBinding[] typeVariableBindings = NoTypeVariables;
+               
+               int length = typeParameters.length;
+               typeVariableBindings = new TypeVariableBinding[length];
+               HashtableOfObject knownTypeParameterNames = new HashtableOfObject(length);
+               int count = 0;
+               nextParameter : for (int i = 0; i < length; i++) {
+                       TypeParameter typeParameter = typeParameters[i];
+                       TypeVariableBinding parameterBinding = new TypeVariableBinding(typeParameter.name, declaringElement, i);
+                       parameterBinding.fPackage = unitPackage;
+                       typeParameter.binding = parameterBinding;
+                       
+                       if (knownTypeParameterNames.containsKey(typeParameter.name)) {
+                               TypeVariableBinding previousBinding = (TypeVariableBinding) knownTypeParameterNames.get(typeParameter.name);
+                               if (previousBinding != null) {
+                                       for (int j = 0; j < i; j++) {
+                                               TypeParameter previousParameter = typeParameters[j];
+                                               if (previousParameter.binding == previousBinding) {
+                                                       problemReporter().duplicateTypeParameterInType(previousParameter);
+                                                       previousParameter.binding = null;
+                                                       break;
+                                               }
+                                       }
+                               }
+                               knownTypeParameterNames.put(typeParameter.name, null); // ensure that the duplicate parameter is found & removed
+                               problemReporter().duplicateTypeParameterInType(typeParameter);
+                               typeParameter.binding = null;
+                       } else {
+                               knownTypeParameterNames.put(typeParameter.name, parameterBinding);
+                               // remember that we have seen a field with this name
+                               if (parameterBinding != null)
+                                       typeVariableBindings[count++] = parameterBinding;
+                       }
+//                             TODO should offer warnings to inform about hiding declaring, enclosing or member types                          
+//                             ReferenceBinding type = sourceType;
+//                             // check that the member does not conflict with an enclosing type
+//                             do {
+//                                     if (CharOperation.equals(type.sourceName, memberContext.name)) {
+//                                             problemReporter().hidingEnclosingType(memberContext);
+//                                             continue nextParameter;
+//                                     }
+//                                     type = type.enclosingType();
+//                             } while (type != null);
+//                             // check that the member type does not conflict with another sibling member type
+//                             for (int j = 0; j < i; j++) {
+//                                     if (CharOperation.equals(referenceContext.memberTypes[j].name, memberContext.name)) {
+//                                             problemReporter().duplicateNestedType(memberContext);
+//                                             continue nextParameter;
+//                                     }
+//                             }
+               }
+               if (count != length) {
+                       System.arraycopy(typeVariableBindings, 0, typeVariableBindings = new TypeVariableBinding[count], 0, count);
+               }
+               return typeVariableBindings;
        }
 
        public final ClassScope enclosingClassScope() {
                Scope scope = this;
                while ((scope = scope.parent) != null) {
-                       if (scope instanceof ClassScope) return (ClassScope)scope;
+                       if (scope instanceof ClassScope) return (ClassScope) scope;
                }
                return null; // may answer null if no type around
        }
@@ -114,7 +470,7 @@ public abstract class Scope
        public final MethodScope enclosingMethodScope() {
                Scope scope = this;
                while ((scope = scope.parent) != null) {
-                       if (scope instanceof MethodScope) return (MethodScope)scope;
+                       if (scope instanceof MethodScope) return (MethodScope) scope;
                }
                return null; // may answer null if no method around
        }
@@ -137,28 +493,6 @@ public abstract class Scope
                return ((CompilationUnitScope) unitScope).environment;
        }
 
-       protected void faultInReceiverType(TypeBinding type) {
-               if (type.isArrayType())
-                       type = ((ArrayBinding) type).leafComponentType;
-
-        // check on Begin bit, so as to be resilient with potential illformed binaries containing cycles (67769)
-               if (type instanceof BinaryTypeBinding && (type.tagBits & BeginHierarchyCheck) == 0) {
-                   type.tagBits |= BeginHierarchyCheck;
-                       // fault in the hierarchy of the type now so we can detect missing types instead of in storeDependencyInfo
-                       BinaryTypeBinding binaryType = (BinaryTypeBinding) type;
-                       ReferenceBinding enclosingType = binaryType.enclosingType();
-                       if (enclosingType != null)
-                               faultInReceiverType(enclosingType);
-                       ReferenceBinding superclass = binaryType.superclass();
-                       if (superclass != null)
-                               faultInReceiverType(superclass);
-                       ReferenceBinding[] interfaces = binaryType.superInterfaces();
-                       for (int i = 0, l = interfaces.length; i < l; i++)
-                               faultInReceiverType(interfaces[i]);
-                       type.tagBits |= EndHierarchyCheck;
-               }
-       }
-
        // abstract method lookup lookup (since maybe missing default abstract methods)
        public MethodBinding findDefaultAbstractMethod(
                ReferenceBinding receiverType, 
@@ -175,24 +509,34 @@ public abstract class Scope
                        matchingMethod = findMethodInSuperInterfaces(currentType, selector, found, matchingMethod);
                        currentType = currentType.superclass();
                }
+               CompilationUnitScope unitScope = compilationUnitScope();
                int foundSize = found.size;
                if (foundSize == startFoundSize) {
-                       if (matchingMethod != null) compilationUnitScope().recordTypeReferences(matchingMethod.thrownExceptions);
+                       if (matchingMethod != null)
+                               unitScope.recordTypeReferences(matchingMethod.thrownExceptions);
                        return matchingMethod; // maybe null
                }
                MethodBinding[] candidates = new MethodBinding[foundSize - startFoundSize];
                int candidatesCount = 0;
+               MethodBinding problemMethod = null;
                // argument type compatibility check
                for (int i = startFoundSize; i < foundSize; i++) {
                        MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
-                       if (areParametersAssignable(methodBinding.parameters, argumentTypes))
-                               candidates[candidatesCount++] = methodBinding;
+                       MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+                       if (compatibleMethod != null) {
+                               if (compatibleMethod.isValidBinding())
+                                       candidates[candidatesCount++] = compatibleMethod;
+                               else if (problemMethod == null)
+                                       problemMethod = compatibleMethod;
+                       }
                }
+
                if (candidatesCount == 1) {
-                       compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions);
+                       unitScope.recordTypeReferences(candidates[0].thrownExceptions);
                        return candidates[0]; 
                }
                if (candidatesCount == 0) { // try to find a close match when the parameter order is wrong or missing some parameters
+                       if (problemMethod != null) return problemMethod;
                        int argLength = argumentTypes.length;
                        nextMethod : for (int i = 0; i < foundSize; i++) {
                                MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
@@ -210,7 +554,10 @@ public abstract class Scope
                        return (MethodBinding) found.elementAt(0); // no good match so just use the first one found
                }
                // no need to check for visibility - interface methods are public
-               return mostSpecificInterfaceMethodBinding(candidates, candidatesCount);
+               boolean isCompliant14 = unitScope.environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
+               if (isCompliant14)
+                       return mostSpecificMethodBinding(candidates, candidatesCount, argumentTypes, invocationSite);
+               return mostSpecificInterfaceMethodBinding(candidates, candidatesCount, invocationSite);
        }
 
        // Internal use only
@@ -219,14 +566,15 @@ public abstract class Scope
                        return null; // know it has no member types (nor inherited member types)
 
                SourceTypeBinding enclosingSourceType = enclosingSourceType();
-               compilationUnitScope().recordReference(enclosingType.compoundName, typeName);
+               CompilationUnitScope unitScope = compilationUnitScope();
+               unitScope.recordReference(enclosingType, typeName);
                ReferenceBinding memberType = enclosingType.getMemberType(typeName);
                if (memberType != null) {
-                       compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+                       unitScope.recordTypeReference(memberType);
                        if (enclosingSourceType == null
-                                       ? memberType.canBeSeenBy(getCurrentPackage())
-                                       : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
-                               return memberType;
+                               ? memberType.canBeSeenBy(getCurrentPackage())
+                               : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
+                                       return memberType;
                        return new ProblemReferenceBinding(typeName, memberType, NotVisible);
                }
                return null;
@@ -239,14 +587,24 @@ public abstract class Scope
                TypeBinding[] argumentTypes,
                InvocationSite invocationSite) {
 
-               faultInReceiverType(receiverType);
-               compilationUnitScope().recordTypeReference(receiverType);
-               compilationUnitScope().recordTypeReferences(argumentTypes);
-               MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes);
+               CompilationUnitScope unitScope = compilationUnitScope();
+               unitScope.recordTypeReferences(argumentTypes);
+               MethodBinding exactMethod = receiverType.getExactMethod(selector, argumentTypes, unitScope);
                if (exactMethod != null) {
-                       compilationUnitScope().recordTypeReferences(exactMethod.thrownExceptions);
-                       if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this))
+                       unitScope.recordTypeReferences(exactMethod.thrownExceptions);
+                       // special treatment for Object.getClass() in 1.5 mode (substitute parameterized return type)
+                       if (receiverType.isInterface() || exactMethod.canBeSeenBy(receiverType, invocationSite, this)) {
+                               if (receiverType.id != T_JavaLangObject
+                                       && argumentTypes == NoParameters
+                                   && CharOperation.equals(selector, GETCLASS)
+                                   && exactMethod.returnType.isParameterizedType()/*1.5*/) {
+                                               return ParameterizedMethodBinding.instantiateGetClass(receiverType, exactMethod, this);
+                           }
+                               // targeting a generic method could find an exact match with variable return type
+                               if (exactMethod.typeVariables != NoTypeVariables || invocationSite.genericTypeArguments() != null)
+                                       exactMethod = computeCompatibleMethod(exactMethod, argumentTypes, invocationSite);
                                return exactMethod;
+                       }
                }
                return null;
        }
@@ -263,28 +621,29 @@ public abstract class Scope
        */
        public FieldBinding findField(TypeBinding receiverType, char[] fieldName, InvocationSite invocationSite, boolean needResolve) {
                if (receiverType.isBaseType()) return null;
+
+               CompilationUnitScope unitScope = compilationUnitScope();
+               unitScope.recordTypeReference(receiverType);
                if (receiverType.isArrayType()) {
                        TypeBinding leafType = receiverType.leafComponentType();
-                       if (leafType instanceof ReferenceBinding) {
+                       if (leafType instanceof ReferenceBinding)
                                if (!((ReferenceBinding) leafType).canBeSeenBy(this))
                                        return new ProblemFieldBinding((ReferenceBinding)leafType, fieldName, ReceiverTypeNotVisible);
-                       }
                        if (CharOperation.equals(fieldName, LENGTH))
                                return ArrayBinding.ArrayLength;
                        return null;
                }
 
-               faultInReceiverType(receiverType);
-               compilationUnitScope().recordTypeReference(receiverType);
-
                ReferenceBinding currentType = (ReferenceBinding) receiverType;
                if (!currentType.canBeSeenBy(this))
                        return new ProblemFieldBinding(currentType, fieldName, ReceiverTypeNotVisible);
 
                FieldBinding field = currentType.getField(fieldName, true /*resolve*/);
                if (field != null) {
-                       if (field.canBeSeenBy(currentType, invocationSite, this))
-                               return field;
+                       if (invocationSite == null
+                               ? field.canBeSeenBy(getCurrentPackage())
+                               : field.canBeSeenBy(currentType, invocationSite, this))
+                                       return field;
                        return new ProblemFieldBinding(field /* closest match*/, field.declaringClass, fieldName, NotVisible);
                }
                // collect all superinterfaces of receiverType until the field is found in a supertype
@@ -296,21 +655,21 @@ public abstract class Scope
                // we could hold onto the not visible field for extra error reporting
                while (keepLooking) {
                        ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+                       if (itsInterfaces == null) { // needed for statically imported types which don't know their hierarchy yet
+                               ((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
+                               itsInterfaces = currentType.superInterfaces();
+                       }
                        if (itsInterfaces != NoSuperInterfaces) {
                                if (interfacesToVisit == null)
                                        interfacesToVisit = new ReferenceBinding[5][];
                                if (++lastPosition == interfacesToVisit.length)
-                                       System.arraycopy(
-                                               interfacesToVisit,
-                                               0,
-                                               interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
-                                               0,
-                                               lastPosition);
+                                       System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
                                interfacesToVisit[lastPosition] = itsInterfaces;
                        }
                        if ((currentType = currentType.superclass()) == null)
                                break;
 
+                       unitScope.recordTypeReference(currentType);
                        if ((field = currentType.getField(fieldName, needResolve)) != null) {
                                keepLooking = false;
                                if (field.canBeSeenBy(receiverType, invocationSite, this)) {
@@ -334,6 +693,7 @@ public abstract class Scope
                                        if ((anInterface.tagBits & InterfaceVisited) == 0) {
                                                // if interface as not already been visited
                                                anInterface.tagBits |= InterfaceVisited;
+                                               unitScope.recordTypeReference(anInterface);
                                                if ((field = anInterface.getField(fieldName, true /*resolve*/)) != null) {
                                                        if (visibleField == null) {
                                                                visibleField = field;
@@ -345,12 +705,7 @@ public abstract class Scope
                                                        ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
                                                        if (itsInterfaces != NoSuperInterfaces) {
                                                                if (++lastPosition == interfacesToVisit.length)
-                                                                       System.arraycopy(
-                                                                               interfacesToVisit,
-                                                                               0,
-                                                                               interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
-                                                                               0,
-                                                                               lastPosition);
+                                                                       System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
                                                                interfacesToVisit[lastPosition] = itsInterfaces;
                                                        }
                                                }
@@ -382,14 +737,15 @@ public abstract class Scope
 
                SourceTypeBinding enclosingSourceType = enclosingSourceType();
                PackageBinding currentPackage = getCurrentPackage();
-               compilationUnitScope().recordReference(enclosingType.compoundName, typeName);
+               CompilationUnitScope unitScope = compilationUnitScope();
+               unitScope.recordReference(enclosingType, typeName);
                ReferenceBinding memberType = enclosingType.getMemberType(typeName);
                if (memberType != null) {
-                       compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+                       unitScope.recordTypeReference(memberType);
                        if (enclosingSourceType == null
-                                       ? memberType.canBeSeenBy(currentPackage)
-                                       : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
-                               return memberType;
+                               ? memberType.canBeSeenBy(currentPackage)
+                               : memberType.canBeSeenBy(enclosingType, enclosingSourceType))
+                                       return memberType;
                        return new ProblemReferenceBinding(typeName, memberType, NotVisible);
                }
 
@@ -403,24 +759,23 @@ public abstract class Scope
                // we could hold onto the not visible field for extra error reporting
                while (keepLooking) {
                        ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+                       if (itsInterfaces == null) { // needed for statically imported types which don't know their hierarchy yet
+                               ((SourceTypeBinding) currentType).scope.connectTypeHierarchy();
+                               itsInterfaces = currentType.superInterfaces();
+                       }
                        if (itsInterfaces != NoSuperInterfaces) {
                                if (interfacesToVisit == null)
                                        interfacesToVisit = new ReferenceBinding[5][];
                                if (++lastPosition == interfacesToVisit.length)
-                                       System.arraycopy(
-                                               interfacesToVisit,
-                                               0,
-                                               interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
-                                               0,
-                                               lastPosition);
+                                       System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
                                interfacesToVisit[lastPosition] = itsInterfaces;
                        }
                        if ((currentType = currentType.superclass()) == null)
                                break;
 
-                       compilationUnitScope().recordReference(currentType.compoundName, typeName);
+                       unitScope.recordReference(currentType, typeName);
                        if ((memberType = currentType.getMemberType(typeName)) != null) {
-                               compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+                               unitScope.recordTypeReference(memberType);
                                keepLooking = false;
                                if (enclosingSourceType == null
                                        ? memberType.canBeSeenBy(currentPackage)
@@ -444,9 +799,9 @@ public abstract class Scope
                                        if ((anInterface.tagBits & InterfaceVisited) == 0) {
                                                // if interface as not already been visited
                                                anInterface.tagBits |= InterfaceVisited;
-                                               compilationUnitScope().recordReference(anInterface.compoundName, typeName);
+                                               unitScope.recordReference(anInterface, typeName);
                                                if ((memberType = anInterface.getMemberType(typeName)) != null) {
-                                                       compilationUnitScope().recordTypeReference(memberType); // to record supertypes
+                                                       unitScope.recordTypeReference(memberType);
                                                        if (visibleMemberType == null) {
                                                                visibleMemberType = memberType;
                                                        } else {
@@ -457,12 +812,7 @@ public abstract class Scope
                                                        ReferenceBinding[] itsInterfaces = anInterface.superInterfaces();
                                                        if (itsInterfaces != NoSuperInterfaces) {
                                                                if (++lastPosition == interfacesToVisit.length)
-                                                                       System.arraycopy(
-                                                                               interfacesToVisit,
-                                                                               0,
-                                                                               interfacesToVisit = new ReferenceBinding[lastPosition * 2][],
-                                                                               0,
-                                                                               lastPosition);
+                                                                       System.arraycopy(interfacesToVisit, 0, interfacesToVisit = new ReferenceBinding[lastPosition * 2][], 0, lastPosition);
                                                                interfacesToVisit[lastPosition] = itsInterfaces;
                                                        }
                                                }
@@ -495,13 +845,13 @@ public abstract class Scope
 
                ReferenceBinding currentType = receiverType;
                MethodBinding matchingMethod = null;
-               ObjectVector found = new ObjectVector(); //TODO should rewrite to remove #matchingMethod since found is allocated anyway
+               ObjectVector found = new ObjectVector(); //TODO (kent) should rewrite to remove #matchingMethod since found is allocated anyway
 
-               faultInReceiverType(receiverType);
-               compilationUnitScope().recordTypeReference(receiverType);
-               compilationUnitScope().recordTypeReferences(argumentTypes);
+               CompilationUnitScope unitScope = compilationUnitScope();
+               unitScope.recordTypeReferences(argumentTypes);
 
                if (currentType.isInterface()) {
+                       unitScope.recordTypeReference(currentType);
                        MethodBinding[] currentMethods = currentType.getMethods(selector);
                        int currentLength = currentMethods.length;
                        if (currentLength == 1) {
@@ -513,31 +863,31 @@ public abstract class Scope
                        currentType = getJavaLangObject();
                }
 
-               boolean isCompliant14 = compilationUnitScope().environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
+               boolean isCompliant14 = unitScope.environment.options.complianceLevel >= ClassFileConstants.JDK1_4;
                // superclass lookup
                ReferenceBinding classHierarchyStart = currentType;
                while (currentType != null) {
+                       unitScope.recordTypeReference(currentType);
                        MethodBinding[] currentMethods = currentType.getMethods(selector);
                        int currentLength = currentMethods.length;
-                       
-                       /*
-                        * if 1.4 compliant, must filter out redundant protected methods from superclasses
-                        */
-                       if (isCompliant14){                      
-                               nextMethod: for (int i = 0; i < currentLength; i++){
+
+                       if (isCompliant14 && matchingMethod != null || found.size > 0) {
+                               nextMethod: for (int i = 0; i < currentLength; i++) {
                                        MethodBinding currentMethod = currentMethods[i];
+                                       // if 1.4 compliant, must filter out redundant protected methods from superclasses
                                        // protected method need to be checked only - default access is already dealt with in #canBeSeen implementation
                                        // when checking that p.C -> q.B -> p.A cannot see default access members from A through B.
-                                       if ((currentMethod.modifiers & AccProtected) == 0) continue nextMethod;
-                                       if (matchingMethod != null){
-                                               if (currentMethod.areParametersEqual(matchingMethod)){
+                                       // if ((currentMethod.modifiers & AccProtected) == 0) continue nextMethod;
+                                       // BUT we can also ignore any overridden method since we already know the better match (fixes 80028)
+                                       if (matchingMethod != null) {
+                                               if (currentMethod.areParametersEqual(matchingMethod)) {
                                                        currentLength--;
                                                        currentMethods[i] = null; // discard this match
                                                        continue nextMethod;
                                                }
                                        } else {
                                                for (int j = 0, max = found.size; j < max; j++) {
-                                                       if (((MethodBinding)found.elementAt(j)).areParametersEqual(currentMethod)){
+                                                       if (((MethodBinding) found.elementAt(j)).areParametersEqual(currentMethod)) {
                                                                currentLength--;
                                                                currentMethods[i] = null;
                                                                continue nextMethod;
@@ -546,7 +896,7 @@ public abstract class Scope
                                        }
                                }
                        }
-                       
+
                        if (currentLength == 1 && matchingMethod == null && found.size == 0) {
                                matchingMethod = currentMethods[0];
                        } else if (currentLength > 0) {
@@ -573,41 +923,65 @@ public abstract class Scope
                MethodBinding[] candidates = null;
                int candidatesCount = 0;
                boolean checkedMatchingMethod = false; // is matchingMethod meeting argument expectation ?
+               MethodBinding problemMethod = null;
                if (foundSize > 0) {
                        // argument type compatibility check
                        for (int i = 0; i < foundSize; i++) {
                                MethodBinding methodBinding = (MethodBinding) found.elementAt(i);
-                               if (areParametersAssignable(methodBinding.parameters, argumentTypes)) {
-                                       switch (candidatesCount) {
-                                               case 0: 
-                                                       matchingMethod = methodBinding; // if only one match, reuse matchingMethod
-                                                       checkedMatchingMethod = true; // matchingMethod is known to exist and match params here
-                                                       break;
-                                               case 1:
-                                                       candidates = new MethodBinding[foundSize]; // only lazily created if more than one match
-                                                       candidates[0] = matchingMethod; // copy back
-                                                       matchingMethod = null;
-                                                       // fall through
-                                               default:
-                                                       candidates[candidatesCount] = methodBinding;
+                               MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+                               if (compatibleMethod != null) {
+                                       if (compatibleMethod.isValidBinding()) {
+                                               switch (candidatesCount) {
+                                                       case 0: 
+                                                               matchingMethod = compatibleMethod; // if only one match, reuse matchingMethod
+                                                               checkedMatchingMethod = true; // matchingMethod is known to exist and match params here
+                                                               break;
+                                                       case 1:
+                                                               candidates = new MethodBinding[foundSize]; // only lazily created if more than one match
+                                                               candidates[0] = matchingMethod; // copy back
+                                                               matchingMethod = null;
+                                                               // fall through
+                                                       default:
+                                                               candidates[candidatesCount] = compatibleMethod;
+                                               }
+                                               candidatesCount++;
+                                       } else if (problemMethod == null) {
+                                               problemMethod = compatibleMethod;
                                        }
-                                       candidatesCount++;
                                }
                        }
                }
+               if (candidatesCount > 0)
+                       problemMethod = null; // forget the problem method if candidates were found
+
                // if only one matching method left (either from start or due to elimination of rivals), then match is in matchingMethod
                if (matchingMethod != null) {
-                       if (checkedMatchingMethod || areParametersAssignable(matchingMethod.parameters, argumentTypes)) {
+                       if (!checkedMatchingMethod) {
+                               MethodBinding compatibleMethod = computeCompatibleMethod(matchingMethod, argumentTypes, invocationSite);
+                               if (compatibleMethod != null) {
+                                       if (compatibleMethod.isValidBinding()) {
+                                               matchingMethod = compatibleMethod;
+                                               checkedMatchingMethod = true;
+                                       } else {
+                                               problemMethod = compatibleMethod;
+                                       }
+                               }
+                       }
+                       if (checkedMatchingMethod) {
                                // (if no default abstract) must explicitly look for one instead, which could be a better match
                                if (!matchingMethod.canBeSeenBy(receiverType, invocationSite, this)) {
                                        // ignore matching method (to be consistent with multiple matches, none visible (matching method is then null)
-                                       MethodBinding interfaceMethod = findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, null, found);                                             
+                                       MethodBinding interfaceMethod =
+                                               findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, null, found);                                             
                                        if (interfaceMethod != null) return interfaceMethod;
-                                       compilationUnitScope().recordTypeReferences(matchingMethod.thrownExceptions);
+                                       unitScope.recordTypeReferences(matchingMethod.thrownExceptions);
                                        return matchingMethod;
                                }
                        } 
-                       return findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
+                       matchingMethod =
+                               findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
+                       if (matchingMethod != null) return matchingMethod;
+                       return problemMethod;
                }
 
                // no match was found, try to find a close match when the parameter order is wrong or missing some parameters
@@ -615,6 +989,7 @@ public abstract class Scope
                        MethodBinding interfaceMethod =
                                findDefaultAbstractMethod(receiverType, selector, argumentTypes, invocationSite, classHierarchyStart, matchingMethod, found);
                        if (interfaceMethod != null) return interfaceMethod;
+                       if (problemMethod != null) return problemMethod;
 
                        int argLength = argumentTypes.length;
                        foundSize = found.size;
@@ -631,9 +1006,23 @@ public abstract class Scope
                                }
                                return methodBinding;
                        }
+                       if (found.size == 0) return null;
                        return (MethodBinding) found.elementAt(0); // no good match so just use the first one found
                }
 
+               // check for duplicate parameterized methods
+               if (unitScope.environment.options.sourceLevel >= ClassFileConstants.JDK1_5) {
+                       for (int i = 0; i < candidatesCount; i++) {
+                               MethodBinding current = candidates[i];
+                               if (current instanceof ParameterizedGenericMethodBinding)
+                                       current = ((ParameterizedGenericMethodBinding) current).originalMethod;
+                               if (current instanceof ParameterizedMethodBinding)
+                                       for (int j = i + 1; j < candidatesCount; j++)
+                                               if (current.declaringClass == candidates[j].declaringClass && current.areParametersEqual(candidates[j]))
+                                                       return new ProblemMethodBinding(candidates[i].selector, candidates[i].parameters, Ambiguous);
+                       }
+               }
+
                // tiebreak using visibility check
                int visiblesCount = 0;
                for (int i = 0; i < candidatesCount; i++) {
@@ -647,7 +1036,7 @@ public abstract class Scope
                        }
                }
                if (visiblesCount == 1) {
-                       compilationUnitScope().recordTypeReferences(candidates[0].thrownExceptions);
+                       unitScope.recordTypeReferences(candidates[0].thrownExceptions);
                        return candidates[0];
                }
                if (visiblesCount == 0) {
@@ -657,10 +1046,10 @@ public abstract class Scope
                        return new ProblemMethodBinding(candidates[0], candidates[0].selector, candidates[0].parameters, NotVisible);
                }
                if (isCompliant14)
-                       return mostSpecificMethodBinding(candidates, visiblesCount);
+                       return mostSpecificMethodBinding(candidates, visiblesCount, argumentTypes, invocationSite);
                return candidates[0].declaringClass.isClass()
-                       ? mostSpecificClassMethodBinding(candidates, visiblesCount)
-                       : mostSpecificInterfaceMethodBinding(candidates, visiblesCount);
+                       ? mostSpecificClassMethodBinding(candidates, visiblesCount, invocationSite)
+                       : mostSpecificInterfaceMethodBinding(candidates, visiblesCount, invocationSite);
        }
        
        // Internal use only
@@ -680,15 +1069,27 @@ public abstract class Scope
                MethodBinding methodBinding = object.getExactMethod(selector, argumentTypes);
                if (methodBinding != null) {
                        // handle the method clone() specially... cannot be protected or throw exceptions
-                       if (argumentTypes == NoParameters && CharOperation.equals(selector, CLONE))
-                               return new UpdatedMethodBinding(
-                                       environment().options.targetJDK >= ClassFileConstants.JDK1_4 ? (TypeBinding)receiverType : (TypeBinding)object, // remember its array type for codegen purpose on target>=1.4.0
-                                       (methodBinding.modifiers ^ AccProtected) | AccPublic,
-                                       CLONE,
-                                       methodBinding.returnType,
-                                       argumentTypes,
-                                       null,
-                                       object);
+                       if (argumentTypes == NoParameters) {
+                           switch (selector[0]) {
+                               case 'c': 
+                                   if (CharOperation.equals(selector, CLONE)) {
+                                                       return new UpdatedMethodBinding(
+                                                               environment().options.targetJDK >= ClassFileConstants.JDK1_4 ? (TypeBinding)receiverType : (TypeBinding)object, // remember its array type for codegen purpose on target>=1.4.0
+                                                               (methodBinding.modifiers & ~AccProtected) | AccPublic,
+                                                               CLONE,
+                                                               methodBinding.returnType,
+                                                               argumentTypes,
+                                                               null,
+                                                               object);
+                                   }
+                                   break;
+                               case 'g': 
+                                   if (CharOperation.equals(selector, GETCLASS) && methodBinding.returnType.isParameterizedType()/*1.5*/) {
+                                                       return ParameterizedMethodBinding.instantiateGetClass(receiverType, methodBinding, this);
+                                   }
+                                   break;
+                           }
+                       }
                        if (methodBinding.canBeSeenBy(receiverType, invocationSite, this))
                                return methodBinding;
                }
@@ -697,18 +1098,15 @@ public abstract class Scope
                if (methodBinding == null)
                        return new ProblemMethodBinding(selector, argumentTypes, NotFound);
                if (methodBinding.isValidBinding()) {
-                       if (!areParametersAssignable(methodBinding.parameters, argumentTypes))
-                               return new ProblemMethodBinding(
-                                       methodBinding,
-                                       selector,
-                                       argumentTypes,
-                                       NotFound);
+                       MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+                       if (compatibleMethod == null)
+                               return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
+                       if (!compatibleMethod.isValidBinding())
+                               return compatibleMethod;
+
+                       methodBinding = compatibleMethod;
                        if (!methodBinding.canBeSeenBy(receiverType, invocationSite, this))
-                               return new ProblemMethodBinding(
-                                       methodBinding,
-                                       selector,
-                                       methodBinding.parameters,
-                                       NotVisible);
+                               return new ProblemMethodBinding(methodBinding, selector, methodBinding.parameters, NotVisible);
                }
                return methodBinding;
        }
@@ -738,6 +1136,7 @@ public abstract class Scope
                                                // if interface as not already been visited
                                                currentType.tagBits |= InterfaceVisited;
 
+                                               compilationUnitScope().recordTypeReference(currentType);
                                                MethodBinding[] currentMethods = currentType.getMethods(selector);
                                                int currentLength = currentMethods.length;
                                                if (currentLength == 1 && matchingMethod == null && found.size == 0) {
@@ -795,7 +1194,7 @@ public abstract class Scope
                return null;
        }
        
-       public TypeBinding getBaseType(char[] name) {
+       public static TypeBinding getBaseType(char[] name) {
                // list should be optimized (with most often used first)
                int length = name.length;
                if (length > 2 && length < 8) {
@@ -858,7 +1257,7 @@ public abstract class Scope
        }
 
        /* API
-     * 
+        *      
         *      Answer the binding that corresponds to the argument name.
         *      flag is a mask of the following values VARIABLE (= FIELD or LOCAL), TYPE, PACKAGE.
         *      Only bindings corresponding to the mask can be answered.
@@ -881,10 +1280,10 @@ public abstract class Scope
                try {
                        Binding binding = null;
                        FieldBinding problemField = null;
-                       if ((mask & VARIABLE) != 0) {
+                       if ((mask & Binding.VARIABLE) != 0) {
                                boolean insideStaticContext = false;
                                boolean insideConstructorCall = false;
-       
+
                                FieldBinding foundField = null;
                                // can be a problem field which is answered if a valid field is not found
                                ProblemFieldBinding foundInsideProblem = null;
@@ -918,10 +1317,25 @@ public abstract class Scope
                                                case CLASS_SCOPE :
                                                        ClassScope classScope = (ClassScope) scope;
                                                        SourceTypeBinding enclosingType = classScope.referenceContext.binding;
-                                                       FieldBinding fieldBinding =
-                                                               classScope.findField(enclosingType, name, invocationSite, needResolve);
+                                                       FieldBinding fieldBinding = classScope.findField(enclosingType, name, invocationSite, needResolve);
                                                        // Use next line instead if willing to enable protected access accross inner types
                                                        // FieldBinding fieldBinding = findField(enclosingType, name, invocationSite);
+                                                       
+//                                                     SourceTypeBinding initialType = this.enclosingSourceType();
+//                                                     if ((fieldBinding == null || !fieldBinding.isValidBinding()) && enclosingType.hasMemberTypes()) { // check member enums
+//                                                             ReferenceBinding[] memberTypes = enclosingType.memberTypes();
+//                                                             for (int i = 0, length = memberTypes.length; i < length; i++) {
+//                                                                     ReferenceBinding memberType = memberTypes[i];
+//                                                                     if (memberType != initialType && memberType.isEnum()) { // do not find one's field through its enclosing members
+//                                                                             FieldBinding enumField = ((SourceTypeBinding)memberType).scope.findField(memberType, name, invocationSite, needResolve);
+//                                                                             if (enumField != null && (enumField.modifiers & AccEnum) != 0) {
+//                                                                                     // grant access to enum constants of enclosing members
+//                                                                                     // TODO (kent) need to revisit to see whether should walk sibling enums and issue an ambiguous match
+//                                                                                     return enumField;
+//                                                                             }
+//                                                                     }
+//                                                             }
+//                                                     }
                                                        if (fieldBinding != null) { // skip it if we did not find anything
                                                                if (fieldBinding.problemId() == Ambiguous) {
                                                                        if (foundField == null || foundField.problemId() == NotVisible)
@@ -934,7 +1348,7 @@ public abstract class Scope
                                                                                name,
                                                                                InheritedNameHidesEnclosingName);
                                                                }
-       
+
                                                                ProblemFieldBinding insideProblem = null;
                                                                if (fieldBinding.isValidBinding()) {
                                                                        if (!fieldBinding.isStatic()) {
@@ -954,8 +1368,7 @@ public abstract class Scope
                                                                                                        NonStaticReferenceInStaticContext);
                                                                                }
                                                                        }
-                                                                       if (enclosingType == fieldBinding.declaringClass
-                                                                               || environment().options.complianceLevel >= ClassFileConstants.JDK1_4){
+                                                                       if (enclosingType == fieldBinding.declaringClass || environment().options.complianceLevel >= ClassFileConstants.JDK1_4) {
                                                                                // found a valid field in the 'immediate' scope (ie. not inherited)
                                                                                // OR in 1.4 mode (inherited shadows enclosing)
                                                                                if (foundField == null) {
@@ -977,10 +1390,8 @@ public abstract class Scope
                                                                                                        InheritedNameHidesEnclosingName);
                                                                        }
                                                                }
-       
-                                                               if (foundField == null
-                                                                       || (foundField.problemId() == NotVisible
-                                                                               && fieldBinding.problemId() != NotVisible)) {
+
+                                                               if (foundField == null || (foundField.problemId() == NotVisible && fieldBinding.problemId() != NotVisible)) {
                                                                        // only remember the fieldBinding if its the first one found or the previous one was not visible & fieldBinding is...
                                                                        foundDepth = depth;
                                                                        foundActualReceiverType = enclosingType;
@@ -1002,12 +1413,12 @@ public abstract class Scope
                                        }
                                        scope = scope.parent;
                                }
-       
+
                                if (foundInsideProblem != null)
                                        return foundInsideProblem;
                                if (foundField != null) {
-                                       if (foundField.isValidBinding()){
-                                               if (foundDepth > 0){
+                                       if (foundField.isValidBinding()) {
+                                               if (foundDepth > 0) {
                                                        invocationSite.setDepth(foundDepth);
                                                        invocationSite.setActualReceiverType(foundActualReceiverType);
                                                }
@@ -1015,24 +1426,69 @@ public abstract class Scope
                                        }
                                        problemField = foundField;
                                }
+
+                               if (environment().options.complianceLevel >= ClassFileConstants.JDK1_5) {
+                                       // at this point the scope is a compilation unit scope & need to check for imported static fields
+                                       CompilationUnitScope unitScope = (CompilationUnitScope) scope;
+                                       ImportBinding[] imports = unitScope.imports;
+                                       if (imports != null) {
+                                               // check single static imports
+                                               for (int i = 0, length = imports.length; i < length; i++) {
+                                                       ImportBinding importBinding = imports[i];
+                                                       if (importBinding.isStatic() && !importBinding.onDemand) {
+                                                               if (CharOperation.equals(importBinding.compoundName[importBinding.compoundName.length - 1], name)) {
+                                                                       if (unitScope.resolveSingleImport(importBinding) != null && importBinding.resolvedImport instanceof FieldBinding) {
+                                                                               ImportReference importReference = importBinding.reference;
+                                                                               if (importReference != null) importReference.used = true;
+                                                                               return importBinding.resolvedImport; // already know its visible
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               // check on demand imports
+                                               boolean foundInImport = false;
+                                               for (int i = 0, length = imports.length; i < length; i++) {
+                                                       ImportBinding importBinding = imports[i];
+                                                       if (importBinding.isStatic() && importBinding.onDemand) {
+                                                               Binding resolvedImport = importBinding.resolvedImport;
+                                                               if (resolvedImport instanceof ReferenceBinding) {
+                                                                       FieldBinding temp = findField((ReferenceBinding) resolvedImport, name, invocationSite, needResolve);
+                                                                       if (temp != null) {
+                                                                               if (!temp.isValidBinding()) {
+                                                                                       problemField = temp;
+                                                                               } else if (temp.isStatic()) {
+                                                                                       ImportReference importReference = importBinding.reference;
+                                                                                       if (importReference != null) importReference.used = true;
+                                                                                       if (foundInImport)
+                                                                                               // Answer error binding -- import on demand conflict; name found in two import on demand packages.
+                                                                                               return new ProblemReferenceBinding(name, Ambiguous);
+                                                                                       foundField = temp;
+                                                                                       foundInImport = true;
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                               if (foundField != null) return foundField;
+                                       }
+                               }
                        }
-       
+
                        // We did not find a local or instance variable.
-                       if ((mask & TYPE) != 0) {
+                       if ((mask & Binding.TYPE) != 0) {
                                if ((binding = getBaseType(name)) != null)
                                        return binding;
-                               binding = getTypeOrPackage(name, (mask & PACKAGE) == 0 ? TYPE : TYPE | PACKAGE);
-                               if (binding.isValidBinding() || mask == TYPE)
+                               binding = getTypeOrPackage(name, (mask & Binding.PACKAGE) == 0 ? Binding.TYPE : Binding.TYPE | Binding.PACKAGE);
+                               if (binding.isValidBinding() || mask == Binding.TYPE)
                                        return binding;
                                // answer the problem type binding if we are only looking for a type
-                       } else if ((mask & PACKAGE) != 0) {
+                       } else if ((mask & Binding.PACKAGE) != 0) {
                                compilationUnitScope().recordSimpleReference(name);
                                if ((binding = environment().getTopLevelPackage(name)) != null)
                                        return binding;
                        }
                        if (problemField != null) return problemField;
                        return new ProblemBinding(name, enclosingSourceType(), NotFound);
-
                } catch (AbortCompilation e) {
                        e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
                        throw e;
@@ -1041,29 +1497,40 @@ public abstract class Scope
 
        public MethodBinding getConstructor(ReferenceBinding receiverType, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
                try {
-                       faultInReceiverType(receiverType);
-                       compilationUnitScope().recordTypeReference(receiverType);
-                       compilationUnitScope().recordTypeReferences(argumentTypes);
+                       CompilationUnitScope unitScope = compilationUnitScope();
+                       unitScope.recordTypeReference(receiverType);
+                       unitScope.recordTypeReferences(argumentTypes);
                        MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes);
-                       if (methodBinding != null && methodBinding.canBeSeenBy(invocationSite, this))
+                       if (methodBinding != null && methodBinding.canBeSeenBy(invocationSite, this)) {
+                           // targeting a non generic constructor with type arguments ?
+                           if (invocationSite.genericTypeArguments() != null)
+                               methodBinding = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);                          
                                return methodBinding;
-                       MethodBinding[] methods = receiverType.getMethods(ConstructorDeclaration.ConstantPoolName);
+                       }
+                       MethodBinding[] methods = receiverType.getMethods(TypeConstants.INIT);
                        if (methods == NoMethods)
                                return new ProblemMethodBinding(
-                                       ConstructorDeclaration.ConstantPoolName,
+                                       TypeConstants.INIT,
                                        argumentTypes,
                                        NotFound);
-       
+
                        MethodBinding[] compatible = new MethodBinding[methods.length];
                        int compatibleIndex = 0;
-                       for (int i = 0, length = methods.length; i < length; i++)
-                               if (areParametersAssignable(methods[i].parameters, argumentTypes))
-                                       compatible[compatibleIndex++] = methods[i];
-                       if (compatibleIndex == 0)
-                               return new ProblemMethodBinding(
-                                       ConstructorDeclaration.ConstantPoolName,
-                                       argumentTypes,
-                                       NotFound);
+                       MethodBinding problemMethod = null;
+                       for (int i = 0, length = methods.length; i < length; i++) {
+                               MethodBinding compatibleMethod = computeCompatibleMethod(methods[i], argumentTypes, invocationSite);
+                               if (compatibleMethod != null) {
+                                       if (compatibleMethod.isValidBinding())
+                                               compatible[compatibleIndex++] = compatibleMethod;
+                                       else if (problemMethod == null)
+                                               problemMethod = compatibleMethod;
+                               }
+                       }
+                       if (compatibleIndex == 0) {
+                               if (problemMethod == null)
+                                       return new ProblemMethodBinding(TypeConstants.INIT, argumentTypes, NotFound);
+                               return problemMethod;
+                       }
                        // need a more descriptive error... cannot convert from X to Y
        
                        MethodBinding[] visible = new MethodBinding[compatibleIndex];
@@ -1077,10 +1544,11 @@ public abstract class Scope
                        if (visibleIndex == 0)
                                return new ProblemMethodBinding(
                                        compatible[0],
-                                       ConstructorDeclaration.ConstantPoolName,
+                                       TypeConstants.INIT,
                                        compatible[0].parameters,
                                        NotVisible);
-                       return mostSpecificClassMethodBinding(visible, visibleIndex);
+                       // all of visible are from the same declaringClass, even before 1.4 we can call this method instead of mostSpecificClassMethodBinding
+                       return mostSpecificMethodBinding(visible, visibleIndex, argumentTypes, invocationSite);
                } catch (AbortCompilation e) {
                        e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
                        throw e;
@@ -1106,26 +1574,22 @@ public abstract class Scope
                                if (!methodScope.isInsideInitializer()){
                                        // check method modifiers to see if deprecated
                                        MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding;
-                                       if (context != null) {
+                                       if (context != null)
                                                return context.modifiers;
-                                       }
                                } else {
-                                       SourceTypeBinding type = ((BlockScope)this).referenceType().binding;
+                                       SourceTypeBinding type = ((BlockScope) this).referenceType().binding;
 
                                        // inside field declaration ? check field modifier to see if deprecated
-                                       if (methodScope.initializedField != null) {
+                                       if (methodScope.initializedField != null)
                                                return methodScope.initializedField.modifiers;
-                                       }
-                                       if (type != null) {
+                                       if (type != null)
                                                return type.modifiers;
-                                       }
                                }
                                break;
                        case Scope.CLASS_SCOPE :
                                ReferenceBinding context = ((ClassScope)this).referenceType().binding;
-                               if (context != null) {
+                               if (context != null)
                                        return context.modifiers;
-                               }
                                break;
                }
                return -1;
@@ -1143,7 +1607,7 @@ public abstract class Scope
                } catch (AbortCompilation e) {
                        e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
                        throw e;
-               }
+               }                       
        }
 
        /* API
@@ -1159,17 +1623,14 @@ public abstract class Scope
         * 
         *      If no visible method is discovered, an error binding is answered.
         */
-       public MethodBinding getImplicitMethod(
-               char[] selector,
-               TypeBinding[] argumentTypes,
-               InvocationSite invocationSite) {
+       public MethodBinding getImplicitMethod(char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
 
                boolean insideStaticContext = false;
                boolean insideConstructorCall = false;
                MethodBinding foundMethod = null;
-               ProblemMethodBinding foundFuzzyProblem = null;
+               MethodBinding foundFuzzyProblem = null;
                // the weird method lookup case (matches method name in scope, then arg types, then visibility)
-               ProblemMethodBinding foundInsideProblem = null;
+               MethodBinding foundInsideProblem = null;
                // inside Constructor call or inside static context
                Scope scope = this;
                int depth = 0;
@@ -1185,26 +1646,16 @@ public abstract class Scope
                                        SourceTypeBinding receiverType = classScope.referenceContext.binding;
                                        boolean isExactMatch = true;
                                        // retrieve an exact visible match (if possible)
+                                       // compilationUnitScope().recordTypeReference(receiverType);   not needed since receiver is the source type
                                        MethodBinding methodBinding =
                                                (foundMethod == null)
-                                                       ? classScope.findExactMethod(
-                                                               receiverType,
-                                                               selector,
-                                                               argumentTypes,
-                                                               invocationSite)
-                                                       : classScope.findExactMethod(
-                                                               receiverType,
-                                                               foundMethod.selector,
-                                                               foundMethod.parameters,
-                                                               invocationSite);
-                                       //                                              ? findExactMethod(receiverType, selector, argumentTypes, invocationSite)
-                                       //                                              : findExactMethod(receiverType, foundMethod.selector, foundMethod.parameters, invocationSite);
+                                                       ? classScope.findExactMethod(receiverType, selector, argumentTypes, invocationSite)
+                                                       : classScope.findExactMethod(receiverType, foundMethod.selector, foundMethod.parameters, invocationSite);
                                        if (methodBinding == null) {
                                                // answers closest approximation, may not check argumentTypes or visibility
                                                isExactMatch = false;
-                                               methodBinding =
-                                                       classScope.findMethod(receiverType, selector, argumentTypes, invocationSite);
-                                               //                                      methodBinding = findMethod(receiverType, selector, argumentTypes, invocationSite);
+                                               methodBinding = classScope.findMethod(receiverType, selector, argumentTypes, invocationSite);
+                                               // methodBinding = findMethod(receiverType, selector, argumentTypes, invocationSite);
                                        }
                                        if (methodBinding != null) { // skip it if we did not find anything
                                                if (methodBinding.problemId() == Ambiguous) {
@@ -1219,26 +1670,25 @@ public abstract class Scope
                                                                argumentTypes,
                                                                InheritedNameHidesEnclosingName);
                                                }
-                                               ProblemMethodBinding fuzzyProblem = null;
-                                               ProblemMethodBinding insideProblem = null;
+                                               MethodBinding fuzzyProblem = null;
+                                               MethodBinding insideProblem = null;
                                                if (methodBinding.isValidBinding()) {
                                                        if (!isExactMatch) {
-                                                               if (!areParametersAssignable(methodBinding.parameters, argumentTypes)) {
-                                                                       if (foundMethod == null || foundMethod.problemId() == NotVisible){
+                                                               MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+                                                               if (compatibleMethod == null) {
+                                                                       if (foundMethod == null || foundMethod.problemId() == NotVisible)
                                                                                // inherited mismatch is reported directly, not looking at enclosing matches
                                                                                return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
-                                                                       }
                                                                        // make the user qualify the method, likely wants the first inherited method (javac generates an ambiguous error instead)
-                                                                       fuzzyProblem = new ProblemMethodBinding(selector, methodBinding.parameters, InheritedNameHidesEnclosingName);
-
-                                                               } else if (!methodBinding.canBeSeenBy(receiverType, invocationSite, classScope)) {
-                                                                       // using <classScope> instead of <this> for visibility check does grant all access to innerclass
-                                                                       fuzzyProblem =
-                                                                               new ProblemMethodBinding(
-                                                                                       methodBinding,
-                                                                                       selector,
-                                                                                       methodBinding.parameters,
-                                                                                       NotVisible);
+                                                                       fuzzyProblem = new ProblemMethodBinding(methodBinding, selector, methodBinding.parameters, InheritedNameHidesEnclosingName);
+                                                               } else if (!compatibleMethod.isValidBinding()) {
+                                                                       fuzzyProblem = compatibleMethod;
+                                                               } else {
+                                                                       methodBinding = compatibleMethod;
+                                                                       if (!methodBinding.canBeSeenBy(receiverType, invocationSite, classScope)) {
+                                                                               // using <classScope> instead of <this> for visibility check does grant all access to innerclass
+                                                                               fuzzyProblem = new ProblemMethodBinding(methodBinding, selector, methodBinding.parameters, NotVisible);
+                                                                       }
                                                                }
                                                        }
                                                        if (fuzzyProblem == null && !methodBinding.isStatic()) {
@@ -1258,10 +1708,10 @@ public abstract class Scope
                                                                                        NonStaticReferenceInStaticContext);
                                                                }
                                                        }
-                                                       
+
                                                        if (receiverType == methodBinding.declaringClass
                                                                || (receiverType.getMethods(selector)) != NoMethods
-                                                               || ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= ClassFileConstants.JDK1_4)){
+                                                               || ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= ClassFileConstants.JDK1_4)) {
                                                                // found a valid method in the 'immediate' scope (ie. not inherited)
                                                                // OR the receiverType implemented a method with the correct name
                                                                // OR in 1.4 mode (inherited visible shadows enclosing)
@@ -1289,12 +1739,10 @@ public abstract class Scope
                                                        }
                                                }
 
-                                               if (foundMethod == null
-                                                       || (foundMethod.problemId() == NotVisible
-                                                               && methodBinding.problemId() != NotVisible)) {
+                                               if (foundMethod == null || (foundMethod.problemId() == NotVisible && methodBinding.problemId() != NotVisible)) {
                                                        // only remember the methodBinding if its the first one found or the previous one was not visible & methodBinding is...
                                                        // remember that private methods are visible if defined directly by an enclosing class
-                                                       if (depth > 0){
+                                                       if (depth > 0) {
                                                                invocationSite.setDepth(depth);
                                                                invocationSite.setActualReceiverType(receiverType);
                                                        }
@@ -1325,6 +1773,53 @@ public abstract class Scope
                        return foundInsideProblem;
                if (foundMethod != null)
                        return foundMethod;
+
+               if (insideStaticContext && environment().options.complianceLevel >= ClassFileConstants.JDK1_5) {
+                       // at this point the scope is a compilation unit scope & need to check for imported static methods
+                       CompilationUnitScope unitScope = (CompilationUnitScope) scope;
+                       ImportBinding[] imports = unitScope.imports;
+                       if (imports != null) {
+                               // check on demand imports
+                               boolean foundInImport = false;
+                               for (int i = 0, length = imports.length; i < length; i++) {
+                                       ImportBinding importBinding = imports[i];
+                                       if (importBinding.isStatic() && importBinding.onDemand) {
+                                               Binding resolvedImport = importBinding.resolvedImport;
+                                               if (resolvedImport instanceof ReferenceBinding) {
+                                                       // answers closest approximation, may not check argumentTypes or visibility
+                                                       MethodBinding temp = findMethod((ReferenceBinding) resolvedImport, selector, argumentTypes, invocationSite);
+                                                       if (temp != null) {
+                                                               if (!temp.isValidBinding()) {
+                                                                       if (foundMethod == null)
+                                                                               foundMethod = temp;
+                                                               } else if (temp.isStatic()) {
+                                                                       MethodBinding compatibleMethod = computeCompatibleMethod(temp, argumentTypes, invocationSite);
+                                                                       if (compatibleMethod != null) {
+                                                                               if (compatibleMethod.isValidBinding()) {
+                                                                                       if (compatibleMethod.canBeSeenBy(unitScope.fPackage)) {
+                                                                                               ImportReference importReference = importBinding.reference;
+                                                                                               if (importReference != null) importReference.used = true;
+                                                                                               if (foundInImport)
+                                                                                                       // Answer error binding -- import on demand conflict; name found in two import on demand types.
+                                                                                                       return new ProblemMethodBinding(compatibleMethod, selector, compatibleMethod.parameters, Ambiguous);
+                                                                                               foundMethod = compatibleMethod;
+                                                                                               foundInImport = true;
+                                                                                       } else if (foundMethod == null) {
+                                                                                               foundMethod = new ProblemMethodBinding(compatibleMethod, selector, compatibleMethod.parameters, NotVisible);
+                                                                                       }
+                                                                               }
+                                                                       } else if (foundMethod == null) {
+                                                                               foundMethod = new ProblemMethodBinding(temp, selector, argumentTypes, NotFound);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+                       if (foundMethod != null)
+                               return foundMethod;
+               }
                return new ProblemMethodBinding(selector, argumentTypes, NotFound);
        }
 
@@ -1336,7 +1831,16 @@ public abstract class Scope
                problemReporter().isClassPathCorrect(JAVA_IO_SERIALIZABLE, referenceCompilationUnit());
                return null; // will not get here since the above error aborts the compilation
        }
-
+       
+       public final ReferenceBinding getJavaLangAnnotationAnnotation() {
+               compilationUnitScope().recordQualifiedReference(JAVA_LANG_ANNOTATION_ANNOTATION);
+               ReferenceBinding type = environment().getType(JAVA_LANG_ANNOTATION_ANNOTATION);
+               if (type != null) return type;
+       
+               problemReporter().isClassPathCorrect(JAVA_LANG_ANNOTATION_ANNOTATION, referenceCompilationUnit());
+               return null; // will not get here since the above error aborts the compilation
+       }
+       
        public final ReferenceBinding getJavaLangAssertionError() {
                compilationUnitScope().recordQualifiedReference(JAVA_LANG_ASSERTIONERROR);
                ReferenceBinding type = environment().getType(JAVA_LANG_ASSERTIONERROR);
@@ -1362,7 +1866,14 @@ public abstract class Scope
                problemReporter().isClassPathCorrect(JAVA_LANG_CLONEABLE, referenceCompilationUnit());
                return null; // will not get here since the above error aborts the compilation
        }
-
+       public final ReferenceBinding getJavaLangEnum() {
+               compilationUnitScope().recordQualifiedReference(JAVA_LANG_ENUM);
+               ReferenceBinding type = environment().getType(JAVA_LANG_ENUM);
+               if (type != null) return type;
+       
+               problemReporter().isClassPathCorrect(JAVA_LANG_ENUM, referenceCompilationUnit());
+               return null; // will not get here since the above error aborts the compilation
+       }
        public final ReferenceBinding getJavaLangError() {
                compilationUnitScope().recordQualifiedReference(JAVA_LANG_ERROR);
                ReferenceBinding type = environment().getType(JAVA_LANG_ERROR);
@@ -1371,7 +1882,14 @@ public abstract class Scope
                problemReporter().isClassPathCorrect(JAVA_LANG_ERROR, referenceCompilationUnit());
                return null; // will not get here since the above error aborts the compilation
        }
-
+       public final ReferenceBinding getJavaLangIterable() {
+               compilationUnitScope().recordQualifiedReference(JAVA_LANG_ITERABLE);
+               ReferenceBinding type = environment().getType(JAVA_LANG_ITERABLE);
+               if (type != null) return type;
+       
+               problemReporter().isClassPathCorrect(JAVA_LANG_ITERABLE, referenceCompilationUnit());
+               return null; // will not get here since the above error aborts the compilation
+       }
        public final ReferenceBinding getJavaLangObject() {
                compilationUnitScope().recordQualifiedReference(JAVA_LANG_OBJECT);
                ReferenceBinding type = environment().getType(JAVA_LANG_OBJECT);
@@ -1407,6 +1925,14 @@ public abstract class Scope
                problemReporter().isClassPathCorrect(JAVA_LANG_THROWABLE, referenceCompilationUnit());
                return null; // will not get here since the above error aborts the compilation
        }
+       public final ReferenceBinding getJavaUtilIterator() {
+               compilationUnitScope().recordQualifiedReference(JAVA_UTIL_ITERATOR);
+               ReferenceBinding type = environment().getType(JAVA_UTIL_ITERATOR);
+               if (type != null) return type;
+       
+               problemReporter().isClassPathCorrect(JAVA_UTIL_ITERATOR, referenceCompilationUnit());
+               return null; // will not get here since the above error aborts the compilation
+       }
 
        /* Answer the type binding corresponding to the typeName argument, relative to the enclosingType.
        */
@@ -1418,11 +1944,13 @@ public abstract class Scope
 
        public MethodBinding getMethod(TypeBinding receiverType, char[] selector, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
                try {
-                       if (receiverType.isArrayType())
-                               return findMethodForArray((ArrayBinding) receiverType, selector, argumentTypes, invocationSite);
                        if (receiverType.isBaseType())
                                return new ProblemMethodBinding(selector, argumentTypes, NotFound);
-       
+
+                       compilationUnitScope().recordTypeReference(receiverType);
+                       if (receiverType.isArrayType())
+                               return findMethodForArray((ArrayBinding) receiverType, selector, argumentTypes, invocationSite);
+
                        ReferenceBinding currentType = (ReferenceBinding) receiverType;
                        if (!currentType.canBeSeenBy(this))
                                return new ProblemMethodBinding(selector, argumentTypes, ReceiverTypeNotVisible);
@@ -1431,32 +1959,64 @@ public abstract class Scope
                        MethodBinding methodBinding = findExactMethod(currentType, selector, argumentTypes, invocationSite);
                        if (methodBinding != null) return methodBinding;
        
+                       // TODO (kent) performance - we are accumulating super methods which are *hidden* during the walk (see testcase from bug 69141)
                        // answers closest approximation, may not check argumentTypes or visibility
                        methodBinding = findMethod(currentType, selector, argumentTypes, invocationSite);
                        if (methodBinding == null)
                                return new ProblemMethodBinding(selector, argumentTypes, NotFound);
                        if (methodBinding.isValidBinding()) {
-                               if (!areParametersAssignable(methodBinding.parameters, argumentTypes))
-                                       return new ProblemMethodBinding(
-                                               methodBinding,
-                                               selector,
-                                               argumentTypes,
-                                               NotFound);
+                               MethodBinding compatibleMethod = computeCompatibleMethod(methodBinding, argumentTypes, invocationSite);
+                               if (compatibleMethod == null)
+                                       return new ProblemMethodBinding(methodBinding, selector, argumentTypes, NotFound);
+                               if (!compatibleMethod.isValidBinding())
+                                       return compatibleMethod;
+       
+                               methodBinding = compatibleMethod;
                                if (!methodBinding.canBeSeenBy(currentType, invocationSite, this))
-                                       return new ProblemMethodBinding(
-                                               methodBinding,
-                                               selector,
-                                               methodBinding.parameters,
-                                               NotVisible);
+                                       return new ProblemMethodBinding( methodBinding, selector, methodBinding.parameters, NotVisible);
                        }
                        return methodBinding;
-                       
                } catch (AbortCompilation e) {
                        e.updateContext(invocationSite, referenceCompilationUnit().compilationResult);
                        throw e;
                }
        }
 
+       /* Answer the package from the compoundName or null if it begins with a type.
+       * Intended to be used while resolving a qualified type name.
+       *
+       * NOTE: If a problem binding is returned, senders should extract the compound name
+       * from the binding & not assume the problem applies to the entire compoundName.
+       */
+       public final Binding getPackage(char[][] compoundName) {
+               compilationUnitScope().recordQualifiedReference(compoundName);
+               Binding binding = getTypeOrPackage(compoundName[0], Binding.TYPE | Binding.PACKAGE);
+               if (binding == null)
+                       return new ProblemReferenceBinding(compoundName[0], NotFound);
+               if (!binding.isValidBinding())
+                       return (ReferenceBinding) binding;
+
+               if (!(binding instanceof PackageBinding)) return null; // compoundName does not start with a package
+
+               int currentIndex = 1;
+               PackageBinding packageBinding = (PackageBinding) binding;
+               while (currentIndex < compoundName.length) {
+                       binding = packageBinding.getTypeOrPackage(compoundName[currentIndex++]);
+                       if (binding == null)
+                               return new ProblemReferenceBinding(
+                                       CharOperation.subarray(compoundName, 0, currentIndex),
+                                       NotFound);
+                       if (!binding.isValidBinding())
+                               return new ProblemReferenceBinding(
+                                       CharOperation.subarray(compoundName, 0, currentIndex),
+                                       binding.problemId());
+                       if (!(binding instanceof PackageBinding))
+                               return packageBinding;
+                       packageBinding = (PackageBinding) binding;
+               }
+               return new ProblemReferenceBinding(compoundName, NotFound);
+       }
+
        /* Answer the type binding that corresponds the given name, starting the lookup in the receiver.
        * The name provided is a simple source name (e.g., "Object" , "Point", ...)
        */
@@ -1467,7 +2027,34 @@ public abstract class Scope
                // Would like to remove this test and require senders to specially handle base types
                TypeBinding binding = getBaseType(name);
                if (binding != null) return binding;
-               return (ReferenceBinding) getTypeOrPackage(name, TYPE);
+               return (ReferenceBinding) getTypeOrPackage(name, Binding.TYPE);
+       }
+
+       /* Answer the type binding that corresponds to the given name, starting the lookup in the receiver
+       * or the packageBinding if provided.
+       * The name provided is a simple source name (e.g., "Object" , "Point", ...)
+       */
+       public final TypeBinding getType(char[] name, PackageBinding packageBinding) {
+               if (packageBinding == null)
+                       return getType(name);
+
+               Binding binding = packageBinding.getTypeOrPackage(name);
+               if (binding == null)
+                       return new ProblemReferenceBinding(
+                               CharOperation.arrayConcat(packageBinding.compoundName, name),
+                               NotFound);
+               if (!binding.isValidBinding())
+                       return new ProblemReferenceBinding(
+                               CharOperation.arrayConcat(packageBinding.compoundName, name),
+                               binding.problemId());
+
+               ReferenceBinding typeBinding = (ReferenceBinding) binding;
+               if (!typeBinding.canBeSeenBy(this))
+                       return new ProblemReferenceBinding(
+                               CharOperation.arrayConcat(packageBinding.compoundName, name),
+                               typeBinding,
+                               NotVisible);
+               return typeBinding;
        }
 
        /* Answer the type binding corresponding to the compoundName.
@@ -1475,17 +2062,17 @@ public abstract class Scope
        * NOTE: If a problem binding is returned, senders should extract the compound name
        * from the binding & not assume the problem applies to the entire compoundName.
        */
-       public final TypeBinding getType(char[][] compoundName) {
-               int typeNameLength = compoundName.length;
+       public final TypeBinding getType(char[][] compoundName, int typeNameLength) {
                if (typeNameLength == 1) {
                        // Would like to remove this test and require senders to specially handle base types
                        TypeBinding binding = getBaseType(compoundName[0]);
                        if (binding != null) return binding;
                }
 
-               compilationUnitScope().recordQualifiedReference(compoundName);
+               CompilationUnitScope unitScope = compilationUnitScope();
+               unitScope.recordQualifiedReference(compoundName);
                Binding binding =
-                       getTypeOrPackage(compoundName[0], typeNameLength == 1 ? TYPE : TYPE | PACKAGE);
+                       getTypeOrPackage(compoundName[0], typeNameLength == 1 ? Binding.TYPE : Binding.TYPE | Binding.PACKAGE);
                if (binding == null)
                        return new ProblemReferenceBinding(compoundName[0], NotFound);
                if (!binding.isValidBinding())
@@ -1518,7 +2105,7 @@ public abstract class Scope
 
                // binding is now a ReferenceBinding
                ReferenceBinding typeBinding = (ReferenceBinding) binding;
-               compilationUnitScope().recordTypeReference(typeBinding); // to record supertypes
+               unitScope.recordTypeReference(typeBinding);
                if (checkVisibility) // handles the fall through case
                        if (!typeBinding.canBeSeenBy(this))
                                return new ProblemReferenceBinding(
@@ -1549,7 +2136,8 @@ public abstract class Scope
        final Binding getTypeOrPackage(char[] name, int mask) {
                Scope scope = this;
                ReferenceBinding foundType = null;
-               if ((mask & TYPE) == 0) {
+               boolean insideStaticContext = false;
+               if ((mask & Binding.TYPE) == 0) {
                        Scope next = scope;
                        while ((next = scope.parent) != null)
                                scope = next;
@@ -1557,6 +2145,13 @@ public abstract class Scope
                        done : while (true) { // done when a COMPILATION_UNIT_SCOPE is found
                                switch (scope.kind) {
                                        case METHOD_SCOPE :
+                                               MethodScope methodScope = (MethodScope) scope;
+                                               AbstractMethodDeclaration methodDecl = methodScope.referenceMethod();
+                                               if (methodDecl != null && methodDecl.binding != null) {
+                                                       TypeVariableBinding typeVariable = methodDecl.binding.getTypeVariable(name);
+                                                       if (typeVariable != null)       return typeVariable;
+                                               }
+                                               insideStaticContext |= methodScope.isStatic;
                                        case BLOCK_SCOPE :
                                                ReferenceBinding localType = ((BlockScope) scope).findLocalType(name); // looks in this scope only
                                                if (localType != null) {
@@ -1567,7 +2162,24 @@ public abstract class Scope
                                                break;
                                        case CLASS_SCOPE :
                                                SourceTypeBinding sourceType = ((ClassScope) scope).referenceContext.binding;
-                                               // 6.5.5.1 - simple name favors member type over top-level type in same unit
+                                               if (sourceType.isHierarchyBeingConnected()) {
+                                                       // type variables take precedence over the source type, ex. class X <X> extends X == class X <Y> extends Y 
+                                                       TypeVariableBinding typeVariable = sourceType.getTypeVariable(name);
+                                                       if (typeVariable != null)
+                                                               return typeVariable;
+                                                       if (CharOperation.equals(name, sourceType.sourceName))
+                                                               return sourceType;
+                                                       break;
+                                               }
+                                               // type variables take precedence over member types
+                                               TypeVariableBinding typeVariable = sourceType.getTypeVariable(name);
+                                               if (typeVariable != null) {
+                                                       if (insideStaticContext) // do not consider this type modifiers: access is legite within same type
+                                                               return new ProblemReferenceBinding(name, NonStaticReferenceInStaticContext);
+                                                       return typeVariable;
+                                               }
+                                               insideStaticContext |= (sourceType.modifiers & AccStatic) != 0; // not isStatic()
+                                               // 6.5.5.1 - member types have precedence over top-level type in same unit
                                                ReferenceBinding memberType = findMemberType(name, sourceType);
                                                if (memberType != null) { // skip it if we did not find anything
                                                        if (memberType.problemId() == Ambiguous) {
@@ -1584,10 +2196,9 @@ public abstract class Scope
                                                                        // OR in 1.4 mode (inherited shadows enclosing)
                                                                        if (foundType == null)
                                                                                return memberType; 
-                                                                       if (foundType.isValidBinding())
-                                                                               // if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
-                                                                               if (foundType != memberType)
-                                                                                       return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
+                                                                       // if a valid type was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
+                                                                       if (foundType.isValidBinding() && foundType != memberType)
+                                                                               return new ProblemReferenceBinding(name, InheritedNameHidesEnclosingName);
                                                                }
                                                        }
                                                        if (foundType == null || (foundType.problemId() == NotVisible && memberType.problemId() != NotVisible))
@@ -1613,7 +2224,7 @@ public abstract class Scope
                CompilationUnitScope unitScope = (CompilationUnitScope) scope;
                PackageBinding currentPackage = unitScope.fPackage; 
                // ask for the imports + name
-               if ((mask & TYPE) != 0) {
+               if ((mask & Binding.TYPE) != 0) {
                        // check single type imports.
 
                        ImportBinding[] imports = unitScope.imports;
@@ -1632,9 +2243,10 @@ public abstract class Scope
                                                ImportBinding typeImport = imports[i];
                                                if (!typeImport.onDemand) {
                                                        if (CharOperation.equals(typeImport.compoundName[typeImport.compoundName.length - 1], name)) {
-                                                               if (unitScope.resolveSingleTypeImport(typeImport) != null) {
+                                                               if (unitScope.resolveSingleImport(typeImport) != null) {
                                                                        ImportReference importReference = typeImport.reference;
-                                                                       if (importReference != null) importReference.used = true;
+                                                                       if (importReference != null)
+                                                                               importReference.used = true;
                                                                        return typeImport.resolvedImport; // already know its visible
                                                                }
                                                        }
@@ -1657,7 +2269,9 @@ public abstract class Scope
                                                Binding resolvedImport = someImport.resolvedImport;
                                                ReferenceBinding temp = resolvedImport instanceof PackageBinding
                                                        ? findType(name, (PackageBinding) resolvedImport, currentPackage)
-                                                       : findDirectMemberType(name, (ReferenceBinding) resolvedImport);
+                                                       : (someImport.isStatic()
+                                                               ? findMemberType(name, (ReferenceBinding) resolvedImport) // static imports are allowed to see inherited member types
+                                                               : findDirectMemberType(name, (ReferenceBinding) resolvedImport));
                                                if (temp != null) {
                                                        if (temp.isValidBinding()) {
                                                                ImportReference importReference = someImport.reference;
@@ -1678,7 +2292,7 @@ public abstract class Scope
                }
 
                unitScope.recordSimpleReference(name);
-               if ((mask & PACKAGE) != 0) {
+               if ((mask & Binding.PACKAGE) != 0) {
                        PackageBinding packageBinding = unitScope.environment.getTopLevelPackage(name);
                        if (packageBinding != null) return packageBinding;
                }
@@ -1689,13 +2303,16 @@ public abstract class Scope
        }
 
        // Added for code assist... NOT Public API
+       // DO NOT USE to resolve import references since this method assumes 'A.B' is relative to a single type import of 'p1.A'
+       // when it may actually mean the type B in the package A
+       // use CompilationUnitScope.getImport(char[][]) instead
        public final Binding getTypeOrPackage(char[][] compoundName) {
                int nameLength = compoundName.length;
                if (nameLength == 1) {
                        TypeBinding binding = getBaseType(compoundName[0]);
                        if (binding != null) return binding;
                }
-               Binding binding = getTypeOrPackage(compoundName[0], TYPE | PACKAGE);
+               Binding binding = getTypeOrPackage(compoundName[0], Binding.TYPE | Binding.PACKAGE);
                if (!binding.isValidBinding()) return binding;
 
                int currentIndex = 1;
@@ -1721,7 +2338,17 @@ public abstract class Scope
                        checkVisibility = true;
                }
                // binding is now a ReferenceBinding
+               ReferenceBinding qualifiedType = null;
+
                ReferenceBinding typeBinding = (ReferenceBinding) binding;
+               if (typeBinding.isGenericType()) {
+                       qualifiedType = this.environment().createRawType(typeBinding, qualifiedType);
+               } else {
+                       qualifiedType = (qualifiedType != null && (qualifiedType.isRawType() || qualifiedType.isParameterizedType()))
+                               ? this.createParameterizedType(typeBinding, null, qualifiedType)
+                               : typeBinding;
+               }
+
                if (checkVisibility) // handles the fall through case
                        if (!typeBinding.canBeSeenBy(this))
                                return new ProblemReferenceBinding(
@@ -1731,18 +2358,63 @@ public abstract class Scope
 
                while (currentIndex < nameLength) {
                        typeBinding = getMemberType(compoundName[currentIndex++], typeBinding);
+
+                       if (typeBinding.isGenericType()) {
+                               qualifiedType = this.environment().createRawType(typeBinding, qualifiedType);
+                       } else {
+                               qualifiedType = (qualifiedType != null && (qualifiedType.isRawType() || qualifiedType.isParameterizedType()))
+                                       ? this.createParameterizedType(typeBinding, null, qualifiedType)
+                                       : typeBinding;
+                       }
+
                        // checks visibility
-                       if (!typeBinding.isValidBinding())
+                       if (!qualifiedType.isValidBinding())
                                return new ProblemReferenceBinding(
                                        CharOperation.subarray(compoundName, 0, currentIndex),
-                                       typeBinding.problemId());
+                                       qualifiedType.problemId());
                }
-               return typeBinding;
+               return qualifiedType;
+       }
+       
+       // 5.1.10
+       public TypeBinding[] greaterLowerBound(TypeBinding[] types) {
+               if (types == null) return null;
+               int length = types.length;
+               TypeBinding[] result = types;
+               int removed = 0;
+               for (int i = 0; i < length; i++) {
+                       TypeBinding iType = result[i];
+                       for (int j = 0; j < length; j++) {
+                               if (i == j) continue;
+                               TypeBinding jType = result[j];
+                               if (jType == null) continue;
+                               if (iType.isCompatibleWith(jType)) { // if Vi <: Vj, Vj is removed
+                                       if (result == types) { // defensive copy
+                                               System.arraycopy(result, 0, result = new TypeBinding[length], 0, length);
+                                       }
+                                       result[j] = null;
+                                       removed ++;
+                               }
+                       }
+               }
+               if (removed == 0) return result;
+               TypeBinding[] trimmedResult = new TypeBinding[length - removed];
+               for (int i = 0, index = 0; i < length; i++) {
+                       TypeBinding iType = result[i];
+                       if (iType != null) {
+                               trimmedResult[index++] = iType;
+                       }
+               }
+               return trimmedResult;
+       }
+
+       public boolean isBoxingCompatibleWith(TypeBinding left, TypeBinding right) {
+               return left.isBaseType() != right.isBaseType() && environment().isBoxingCompatibleWith(left, right);
        }
 
        /* Answer true if the scope is nested inside a given field declaration.
-     * Note: it works as long as the scope.fieldDeclarationIndex is reflecting the field being traversed 
-     * e.g. during name resolution.
+        * Note: it works as long as the scope.fieldDeclarationIndex is reflecting the field being traversed 
+        * e.g. during name resolution.
        */
        public final boolean isDefinedInField(FieldBinding field) {
                Scope scope = this;
@@ -1763,10 +2435,9 @@ public abstract class Scope
                do {
                        if (scope instanceof MethodScope) {
                                ReferenceContext refContext = ((MethodScope) scope).referenceContext;
-                               if (refContext instanceof AbstractMethodDeclaration
-                                               && ((AbstractMethodDeclaration)refContext).binding == method) {
-                                       return true;
-                               }
+                               if (refContext instanceof AbstractMethodDeclaration)
+                                       if (((AbstractMethodDeclaration) refContext).binding == method)
+                                               return true;
                        }
                        scope = scope.parent;
                } while (scope != null);
@@ -1787,8 +2458,7 @@ public abstract class Scope
                        unitScope = scope;
 
                // test that the enclosingType is not part of the compilation unit
-               SourceTypeBinding[] topLevelTypes =
-                       ((CompilationUnitScope) unitScope).topLevelTypes;
+               SourceTypeBinding[] topLevelTypes = ((CompilationUnitScope) unitScope).topLevelTypes;
                for (int i = topLevelTypes.length; --i >= 0;)
                        if (topLevelTypes[i] == enclosingType)
                                return true;
@@ -1801,9 +2471,8 @@ public abstract class Scope
                Scope scope = this;
                do {
                        if (scope instanceof ClassScope)
-                               if (((ClassScope) scope).referenceContext.binding == type){
+                               if (((ClassScope) scope).referenceContext.binding == type)
                                        return true;
-                               }
                        scope = scope.parent;
                } while (scope != null);
                return false;
@@ -1817,29 +2486,136 @@ public abstract class Scope
                                if (!methodScope.isInsideInitializer()){
                                        // check method modifiers to see if deprecated
                                        MethodBinding context = ((AbstractMethodDeclaration)methodScope.referenceContext).binding;
-                                       if (context != null && context.isViewedAsDeprecated()) {
+                                       if (context != null && context.isViewedAsDeprecated())
                                                return true;
-                                       }
                                } else {
                                        SourceTypeBinding type = ((BlockScope)this).referenceType().binding;
                                        // inside field declaration ? check field modifier to see if deprecated
-                                       if (methodScope.initializedField != null && methodScope.initializedField.isViewedAsDeprecated()) {
+                                       if (methodScope.initializedField != null && methodScope.initializedField.isViewedAsDeprecated())
                                                return true;
-                                       }
-                                       if (type != null && type.isViewedAsDeprecated()) {
+                                       if (type != null && type.isViewedAsDeprecated())
                                                return true;
-                                       }
                                }
                                break;
                        case Scope.CLASS_SCOPE :
                                ReferenceBinding context = ((ClassScope)this).referenceType().binding;
-                               if (context != null && context.isViewedAsDeprecated()) {
+                               if (context != null && context.isViewedAsDeprecated())
                                        return true;
-                               }
                                break;
                }
                return false;
        }
+       private TypeBinding leastContainingInvocation(TypeBinding mec, List invocations) {
+               int length = invocations.size();
+               if (length == 0) return mec;
+               if (length == 1) return (TypeBinding) invocations.get(0);
+               int argLength = mec.typeVariables().length;
+               if (argLength == 0) return mec; // should be caught by no invocation check
+
+               // infer proper parameterized type from invocations
+               TypeBinding[] bestArguments = new TypeBinding[argLength];
+               for (int i = 0; i < length; i++) {
+                       TypeBinding invocation = (TypeBinding)invocations.get(i);
+                       TypeVariableBinding[] invocationVariables = invocation.typeVariables();
+                       if (invocation.isGenericType()) {
+                               for (int j = 0; j < argLength; j++) {
+                                       TypeBinding bestArgument = leastContainingTypeArgument(bestArguments[j], invocationVariables[j], (ReferenceBinding) mec, j);
+                                       if (bestArgument == null) return null;
+                                       bestArguments[j] = bestArgument;
+                               }
+                       } else if (invocation.isParameterizedType()) {
+                               ParameterizedTypeBinding parameterizedType = (ParameterizedTypeBinding)invocation;
+                               for (int j = 0; j < argLength; j++) {
+                                       TypeBinding bestArgument = leastContainingTypeArgument(bestArguments[j], parameterizedType.arguments[j], (ReferenceBinding) mec, j);
+                                       if (bestArgument == null) return null;
+                                       bestArguments[j] = bestArgument;
+                               }
+                       } else if (invocation.isRawType()) {
+                               return invocation; // raw type is taking precedence
+                       }
+               }
+               return createParameterizedType((ReferenceBinding) mec.erasure(), bestArguments, null);
+       }
+       
+       // JLS 15.12.2
+       private TypeBinding leastContainingTypeArgument(TypeBinding u, TypeBinding v, ReferenceBinding genericType, int rank) {
+               if (u == null) return v;
+               if (u == v) return u;
+               if (v.isWildcard()) {
+                       WildcardBinding wildV = (WildcardBinding) v;
+                       if (u.isWildcard()) {
+                               WildcardBinding wildU = (WildcardBinding) u;
+                               switch (wildU.kind) {
+                                       // ? extends U
+                                       case Wildcard.EXTENDS :
+                                               switch(wildV.kind) {
+                                                       // ? extends U, ? extends V
+                                                       case Wildcard.EXTENDS :  
+                                                               TypeBinding lub = lowerUpperBound(new TypeBinding[]{wildU.bound,wildV.bound});
+                                                               if (lub == null) return null;
+                                                               return environment().createWildcard(genericType, rank, lub, Wildcard.EXTENDS);  
+                                                       // ? extends U, ? SUPER V
+                                                       case Wildcard.SUPER : 
+                                                               if (wildU.bound == wildV.bound) return wildU.bound;
+                                                               return environment().createWildcard(genericType, rank, null, Wildcard.UNBOUND);
+                                               }
+                                               break;
+                                               // ? super U
+                                       case Wildcard.SUPER : 
+                                               // ? super U, ? super V
+                                               if (wildU.kind == Wildcard.SUPER) {
+                                                       TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{wildU.bound,wildV.bound});
+                                                       if (glb == null) return null;
+                                                       return environment().createWildcard(genericType, rank, glb[0], Wildcard.SUPER); // TODO (philippe) need to capture entire bounds
+                                               }
+                               }                               
+                       } else {
+                               switch (wildV.kind) {
+                                       // U, ? extends V
+                                       case Wildcard.EXTENDS :
+                                               TypeBinding lub = lowerUpperBound(new TypeBinding[]{u,wildV.bound});
+                                               if (lub == null) return null;
+                                               return environment().createWildcard(genericType, rank, lub, Wildcard.EXTENDS);  
+                                       // U, ? super V
+                                       case Wildcard.SUPER :
+                                               TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{u,wildV.bound});
+                                               if (glb == null) return null;
+                                               return environment().createWildcard(genericType, rank, glb[0], Wildcard.SUPER); // TODO (philippe) need to capture entire bounds
+                                       case Wildcard.UNBOUND :
+                               }
+                       }
+               } else if (u.isWildcard()) {
+                       WildcardBinding wildU = (WildcardBinding) u;
+                       switch (wildU.kind) {
+                               // U, ? extends V
+                               case Wildcard.EXTENDS :
+                                       TypeBinding lub = lowerUpperBound(new TypeBinding[]{wildU.bound, v});
+                                       if (lub == null) return null;
+                                       return environment().createWildcard(genericType, rank, lub, Wildcard.EXTENDS);  
+                               // U, ? super V
+                               case Wildcard.SUPER :
+                                       TypeBinding[] glb = greaterLowerBound(new TypeBinding[]{wildU.bound, v});
+                                       if (glb == null) return null;
+                                       return environment().createWildcard(genericType, rank, glb[0], Wildcard.SUPER); // TODO (philippe) need to capture entire bounds                
+                               case Wildcard.UNBOUND :
+                       }
+               }
+               TypeBinding lub = lowerUpperBound(new TypeBinding[]{u,v});
+               if (lub == null) return null;
+               return environment().createWildcard(genericType, rank, lub, Wildcard.EXTENDS);
+       }
+
+       // 15.12.2
+       public TypeBinding lowerUpperBound(TypeBinding[] types) {
+               
+               if (types.length == 1) {
+                       TypeBinding type = types[0];
+                       return type == null ? VoidBinding : type;
+               }
+               ArrayList invocations = new ArrayList(1);
+               TypeBinding mec = minimalErasedCandidate(types, invocations);
+               return leastContainingInvocation(mec, invocations);
+       }
        
        public final MethodScope methodScope() {
                Scope scope = this;
@@ -1851,6 +2627,143 @@ public abstract class Scope
                return null;
        }
 
+       /**
+        * Returns the most specific type compatible with all given types.
+        * (i.e. most specific common super type)
+        * If no types is given, will return VoidBinding. If not compatible 
+        * reference type is found, returns null.
+        */
+       private TypeBinding minimalErasedCandidate(TypeBinding[] types, List invocations) {
+               Map allInvocations = new HashMap(2);
+               int length = types.length;
+               int indexOfFirst = -1, actualLength = 0;
+               for (int i = 0; i < length; i++) {
+                       TypeBinding type = types[i];
+                       if (type == null) continue;
+                       if (type.isBaseType()) return null;
+                       if (indexOfFirst < 0) indexOfFirst = i;
+                       actualLength ++;
+               }
+               switch (actualLength) {
+                       case 0: return VoidBinding;
+                       case 1: return types[indexOfFirst];
+               }
+
+               // record all supertypes of type
+               // intersect with all supertypes of otherType
+               TypeBinding firstType = types[indexOfFirst];
+               TypeBinding[] superTypes;
+               int superLength;
+               if (firstType.isBaseType()) {
+                       return null; 
+               } else if (firstType.isArrayType()) {
+                       superLength = 4;
+                       if (firstType.erasure() != firstType) {
+                               ArrayList someInvocations = new ArrayList(1);
+                               someInvocations.add(firstType);
+                               allInvocations.put(firstType.erasure(), someInvocations);
+                       }
+                       superTypes = new TypeBinding[] {
+                                       firstType.erasure(), 
+                                       getJavaIoSerializable(),
+                                       getJavaLangCloneable(),
+                                       getJavaLangObject(),
+                       };
+               } else {
+                       ArrayList typesToVisit = new ArrayList(5);
+                       if (firstType.erasure() != firstType) {
+                               ArrayList someInvocations = new ArrayList(1);
+                               someInvocations.add(firstType);
+                               allInvocations.put(firstType.erasure(), someInvocations);
+                       }                       
+                       typesToVisit.add(firstType.erasure());
+                       ReferenceBinding currentType = (ReferenceBinding)firstType;
+                       for (int i = 0, max = 1; i < max; i++) {
+                               currentType = (ReferenceBinding) typesToVisit.get(i);
+                               TypeBinding itsSuperclass = currentType.superclass();
+                               if (itsSuperclass != null) {
+                                       TypeBinding itsSuperclassErasure = itsSuperclass.erasure();
+                                       if (!typesToVisit.contains(itsSuperclassErasure)) {
+                                               if (itsSuperclassErasure != itsSuperclass) {
+                                                       ArrayList someInvocations = new ArrayList(1);
+                                                       someInvocations.add(itsSuperclass);
+                                                       allInvocations.put(itsSuperclassErasure, someInvocations);
+                                               }
+                                               typesToVisit.add(itsSuperclassErasure);
+                                               max++;
+                                       }
+                               }
+                               ReferenceBinding[] itsInterfaces = currentType.superInterfaces();
+                               for (int j = 0, count = itsInterfaces.length; j < count; j++) {
+                                       TypeBinding itsInterface = itsInterfaces[j];
+                                       TypeBinding itsInterfaceErasure = itsInterface.erasure();
+                                       if (!typesToVisit.contains(itsInterfaceErasure)) {
+                                               if (itsInterfaceErasure != itsInterface) {
+                                                       ArrayList someInvocations = new ArrayList(1);
+                                                       someInvocations.add(itsInterface);
+                                                       allInvocations.put(itsInterfaceErasure, someInvocations);
+                                               }                                               
+                                               typesToVisit.add(itsInterfaceErasure);
+                                               max++;
+                                       }
+                               }
+                       }
+                       superLength = typesToVisit.size();
+                       superTypes = new TypeBinding[superLength];
+                       typesToVisit.toArray(superTypes);
+               }
+               int remaining = superLength;
+               nextOtherType: for (int i = indexOfFirst+1; i < length; i++) {
+                       TypeBinding otherType = types[i];
+                       if (otherType == null)
+                               continue nextOtherType;
+                       else if (otherType.isArrayType()) {
+                               nextSuperType: for (int j = 0; j < superLength; j++) {
+                                       TypeBinding superType = superTypes[j];
+                                       if (superType == null || superType == otherType) continue nextSuperType;
+                                       switch (superType.id) {
+                                               case T_JavaIoSerializable :
+                                               case T_JavaLangCloneable :
+                                               case T_JavaLangObject :
+                                                       continue nextSuperType;
+                                       }
+                                       superTypes[j] = null;
+                                       if (--remaining == 0) return null;
+                                       
+                               }
+                               continue nextOtherType;
+                       }
+                       ReferenceBinding otherRefType = (ReferenceBinding) otherType;
+                       nextSuperType: for (int j = 0; j < superLength; j++) {
+                               TypeBinding superType = superTypes[j];
+                               if (superType == null) continue nextSuperType;
+                               if (otherRefType.erasure().isCompatibleWith(superType)) {
+                                       TypeBinding match = otherRefType.findSuperTypeErasingTo((ReferenceBinding)superType);
+                                               if (match != null && match.erasure() != match) { // match can be null: interface.findSuperTypeErasingTo(Object)
+                                                       ArrayList someInvocations = (ArrayList) allInvocations.get(superType);
+                                                       if (someInvocations == null) someInvocations = new ArrayList(1);
+                                                       someInvocations.add(match);
+                                                       allInvocations.put(superType, someInvocations);
+                                               }                                               
+                                       break nextSuperType;
+                               } else {
+                                       superTypes[j] = null;
+                                       if (--remaining == 0) return null;
+                               }
+                       }                               
+               }
+               // per construction, first non-null supertype is most specific common supertype
+               for (int i = 0; i < superLength; i++) {
+                       TypeBinding superType = superTypes[i];
+                       if (superType != null) {
+                               List matchingInvocations = (List)allInvocations.get(superType);
+                               if (matchingInvocations != null) invocations.addAll(matchingInvocations);
+                               return superType;
+                       }
+               }
+               return null;
+       }
+       
        // Internal use only
        /* All methods in visible are acceptable matches for the method in question...
        * The methods defined by the receiver type appear before those defined by its
@@ -1861,29 +2774,28 @@ public abstract class Scope
        * is defined by a superclass, when a lesser match is defined by the receiver type
        * or a closer superclass.
        */
-       protected final MethodBinding mostSpecificClassMethodBinding(MethodBinding[] visible, int visibleSize) {
-
-               MethodBinding method = null;
+       protected final MethodBinding mostSpecificClassMethodBinding(MethodBinding[] visible, int visibleSize, InvocationSite invocationSite) {
+               MethodBinding problemMethod = null;
                MethodBinding previous = null;
-
                nextVisible : for (int i = 0; i < visibleSize; i++) {
-                       method = visible[i];
-                                               
+                       MethodBinding method = visible[i];
                        if (previous != null && method.declaringClass != previous.declaringClass)
                                break; // cannot answer a method farther up the hierarchy than the first method found
-                       if (!method.isStatic()) previous = method;  // no ambiguity for static methods
+
+                       if (!method.isStatic()) previous = method; // no ambiguity for static methods
                        for (int j = 0; j < visibleSize; j++) {
                                if (i == j) continue;
-                               MethodBinding next = visible[j];
-                               if (!areParametersAssignable(next.parameters, method.parameters))
+                               if (!visible[j].areParametersCompatibleWith(method.parameters))
                                        continue nextVisible;
                        }
                        compilationUnitScope().recordTypeReferences(method.thrownExceptions);
                        return method;
                }
-               return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+               if (problemMethod == null)
+                       return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+               return problemMethod;
        }
-
+       
        // Internal use only
        /* All methods in visible are acceptable matches for the method in question...
        * Since the receiver type is an interface, we ignore the possibility that 2 inherited
@@ -1913,42 +2825,53 @@ public abstract class Scope
                public void foo(I i, X x) { i.bar(x); }
        }
        */
-       protected final MethodBinding mostSpecificInterfaceMethodBinding(MethodBinding[] visible, int visibleSize) {
-               MethodBinding method = null;
+       protected final MethodBinding mostSpecificInterfaceMethodBinding(MethodBinding[] visible, int visibleSize, InvocationSite invocationSite) {
+               MethodBinding problemMethod = null;
                nextVisible : for (int i = 0; i < visibleSize; i++) {
-                       method = visible[i];
+                       MethodBinding method = visible[i];
                        for (int j = 0; j < visibleSize; j++) {
                                if (i == j) continue;
-                               MethodBinding next = visible[j];
-                               if (!areParametersAssignable(next.parameters, method.parameters))
+                               if (!visible[j].areParametersCompatibleWith(method.parameters))
                                        continue nextVisible;
                        }
                        compilationUnitScope().recordTypeReferences(method.thrownExceptions);
                        return method;
                }
-               return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+               if (problemMethod == null)
+                       return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
+               return problemMethod;
        }
 
-       
-       // Internal use only
-       /* All methods in visible are acceptable matches for the method in question...
-       * Since 1.4, the inherited ambiguous case has been removed from mostSpecificClassMethodBinding
-       */
-       protected final MethodBinding mostSpecificMethodBinding(MethodBinding[] visible, int visibleSize) {
-               MethodBinding method = null;
-               nextVisible : for (int i = 0; i < visibleSize; i++) {
-                       method = visible[i];
-                       for (int j = 0; j < visibleSize; j++) {
-                               if (i == j) continue;
-                               MethodBinding next = visible[j];
-                               if (!areParametersAssignable(next.parameters, method.parameters))
-                                       continue nextVisible;
+       protected final MethodBinding mostSpecificMethodBinding(MethodBinding[] visible, int visibleSize, TypeBinding[] argumentTypes, InvocationSite invocationSite) {
+               int[] compatibilityLevels = new int[visibleSize];
+               for (int i = 0; i < visibleSize; i++)
+                       compatibilityLevels[i] = parameterCompatibilityLevel(visible[i], argumentTypes);
+
+               for (int level = 0; level <= 2; level++) {
+                       nextVisible : for (int i = 0; i < visibleSize; i++) {
+                               if (compatibilityLevels[i] != level) continue nextVisible; // skip this method for now
+                               MethodBinding method = visible[i];
+                               for (int j = 0; j < visibleSize; j++) {
+                                       if (i == j || compatibilityLevels[j] != level) continue;
+                                       // tiebreak generic methods using variant where type params are substituted by their erasures
+                                       if (!visible[j].tiebreakMethod().areParametersCompatibleWith(method.tiebreakMethod().parameters)) {
+                                               if (method.isVarargs() && visible[j].isVarargs()) {
+                                                       int paramLength = method.parameters.length;
+                                                       if (paramLength == visible[j].parameters.length && paramLength == argumentTypes.length + 1) {
+                                                               TypeBinding elementsType = ((ArrayBinding) visible[j].parameters[paramLength - 1]).elementsType();
+                                                               if (method.parameters[paramLength - 1].isCompatibleWith(elementsType))
+                                                                       continue; // special case to choose between 2 varargs methods when the last arg is missing
+                                                       }
+                                               }
+                                               continue nextVisible;
+                                       }
+                               }
+                               compilationUnitScope().recordTypeReferences(method.thrownExceptions);
+                               return method;
                        }
-                       compilationUnitScope().recordTypeReferences(method.thrownExceptions);
-                       return method;
                }
                return new ProblemMethodBinding(visible[0].selector, visible[0].parameters, Ambiguous);
-       }
+       }       
 
        public final ClassScope outerMostClassScope() {
                ClassScope lastClassScope = null;
@@ -1972,6 +2895,55 @@ public abstract class Scope
                return lastMethodScope; // may answer null if no method around
        }
 
+       protected int parameterCompatibilityLevel(MethodBinding method, TypeBinding[] arguments) {
+               TypeBinding[] parameters = method.parameters;
+               int paramLength = parameters.length;
+               int argLength = arguments.length;
+               int lastIndex = argLength;
+               int level = COMPATIBLE; // no autoboxing or varargs support needed
+               if (method.isVarargs()) {
+                       lastIndex = paramLength - 1;
+                       if (paramLength == argLength) { // accept X or X[] but not X[][]
+                               TypeBinding param = parameters[lastIndex]; // is an ArrayBinding by definition
+                               TypeBinding arg = arguments[lastIndex];
+                               if (param != arg && !arg.isCompatibleWith(param)) {
+                                       if (isBoxingCompatibleWith(arg, param)) {
+                                               level = AUTOBOX_COMPATIBLE; // autoboxing support needed
+                                       } else {
+                                               // expect X[], called with X
+                                               param = ((ArrayBinding) param).elementsType();
+                                               if (!arg.isCompatibleWith(param) && !isBoxingCompatibleWith(arg, param))
+                                                       return NOT_COMPATIBLE;
+                                               level = VARARGS_COMPATIBLE; // varargs support needed
+                                       }
+                               }
+                       } else {
+                               if (paramLength < argLength) { // all remainig argument types must be compatible with the elementsType of varArgType
+                                       TypeBinding param = ((ArrayBinding) parameters[lastIndex]).elementsType();
+                                       for (int i = lastIndex; i < argLength; i++) {
+                                               TypeBinding arg = arguments[i];
+                                               if (param != arg && !arg.isCompatibleWith(param) && !isBoxingCompatibleWith(arg, param))
+                                                       return NOT_COMPATIBLE;
+                                       }
+                               }  else if (lastIndex != argLength) { // can call foo(int i, X ... x) with foo(1) but NOT foo();
+                                       return NOT_COMPATIBLE;
+                               }
+                               level = VARARGS_COMPATIBLE; // varargs support needed
+                       }
+                       // now compare standard arguments from 0 to lastIndex
+               }
+               for (int i = 0; i < lastIndex; i++) {
+                       TypeBinding param = parameters[i];
+                       TypeBinding arg = arguments[i];
+                       if (arg != param && !arg.isCompatibleWith(param)) {
+                               if (!isBoxingCompatibleWith(arg, param))
+                                       return NOT_COMPATIBLE;
+                               level = AUTOBOX_COMPATIBLE; // autoboxing support needed
+                       }
+               }
+               return level;
+       }
+
        public abstract ProblemReporter problemReporter();
 
        public final CompilationUnitDeclaration referenceCompilationUnit() {
@@ -1997,4 +2969,56 @@ public abstract class Scope
                } while (scope != null);
                return null;
        }
+       /*
+        * Unboxing primitive
+        */
+       public int unboxing(int id) {
+               switch (id) {
+                       case T_JavaLangInteger :
+                               return T_int;
+                       case T_JavaLangByte :
+                               return T_byte;
+                       case T_JavaLangShort :
+                               return T_short;
+                       case T_JavaLangCharacter :
+                               return T_char;
+                       case T_JavaLangLong :
+                               return T_long;
+                       case T_JavaLangFloat :
+                               return T_float;
+                       case T_JavaLangDouble :
+                               return T_double;
+                       case T_JavaLangBoolean :
+                               return T_boolean;
+                       case T_JavaLangVoid :
+                               return T_void;
+               }
+               return id;
+       }
+       /*
+        * Unboxing primitive
+        */
+       public TypeBinding unboxing(TypeBinding type) {
+               switch (type.id) {
+                       case T_JavaLangInteger :
+                               return IntBinding;
+                       case T_JavaLangByte :
+                               return ByteBinding;
+                       case T_JavaLangShort :
+                               return ShortBinding;            
+                       case T_JavaLangCharacter :
+                               return CharBinding;                             
+                       case T_JavaLangLong :
+                               return LongBinding;
+                       case T_JavaLangFloat :
+                               return FloatBinding;
+                       case T_JavaLangDouble :
+                               return DoubleBinding;
+                       case T_JavaLangBoolean :
+                               return BooleanBinding;
+                       case T_JavaLangVoid :
+                               return VoidBinding;
+               }
+               return type;
+       }               
 }