improved PHP parser
[phpeclipse.git] / net.sourceforge.phpeclipse / src / net / sourceforge / phpdt / internal / compiler / lookup / BlockScope.java
index 51f82b0..a3b1d92 100644 (file)
@@ -1,25 +1,22 @@
 /*******************************************************************************
- * Copyright (c) 2000, 2001, 2002 International Business Machines Corp. and others.
+ * Copyright (c) 2000, 2003 IBM Corporation and others.
  * All rights reserved. This program and the accompanying materials 
- * are made available under the terms of the Common Public License v0.5 
+ * are made available under the terms of the Common Public License v1.0
  * which accompanies this distribution, and is available at
- * http://www.eclipse.org/legal/cpl-v05.html
+ * http://www.eclipse.org/legal/cpl-v10.html
  * 
  * Contributors:
  *     IBM Corporation - initial API and implementation
- ******************************************************************************/
+ *******************************************************************************/
 package net.sourceforge.phpdt.internal.compiler.lookup;
 
-import net.sourceforge.phpdt.internal.compiler.ast.AbstractMethodDeclaration;
-import net.sourceforge.phpdt.internal.compiler.ast.Argument;
-import net.sourceforge.phpdt.internal.compiler.ast.AstNode;
-import net.sourceforge.phpdt.internal.compiler.ast.ConstructorDeclaration;
-import net.sourceforge.phpdt.internal.compiler.ast.TypeDeclaration;
-import net.sourceforge.phpdt.internal.compiler.codegen.CodeStream;
-import net.sourceforge.phpdt.internal.compiler.impl.CompilerOptions;
-import net.sourceforge.phpdt.internal.compiler.impl.Constant;
+import net.sourceforge.phpdt.internal.compiler.lookup.ReferenceBinding;
+
+import net.sourceforge.phpdt.core.compiler.CharOperation;
 import net.sourceforge.phpdt.internal.compiler.problem.ProblemReporter;
-import net.sourceforge.phpdt.internal.compiler.util.CharOperation;
+import net.sourceforge.phpeclipse.internal.compiler.ast.AbstractMethodDeclaration;
+import net.sourceforge.phpeclipse.internal.compiler.ast.ConstructorDeclaration;
+import net.sourceforge.phpeclipse.internal.compiler.ast.TypeDeclaration;
 
 public class BlockScope extends Scope {
 
@@ -30,10 +27,13 @@ public class BlockScope extends Scope {
        public int offset; // for variable allocation throughout scopes
        public int maxOffset; // for variable allocation throughout scopes
 
-       // finally scopes must be shifted behind respective try scope
+       // finally scopes must be shifted behind respective try&catch scope(s) so as to avoid
+       // collisions of secret variables (return address, save value).
        public BlockScope[] shiftScopes; 
 
        public final static VariableBinding[] EmulationPathToImplicitThis = {};
+       public final static VariableBinding[] NoEnclosingInstanceInConstructorCall = {};
+       public final static VariableBinding[] NoEnclosingInstanceInStaticContext = {};
 
        public Scope[] subscopes = new Scope[1]; // need access from code assist
        public int scopeIndex = 0; // need access from code assist
@@ -100,8 +100,8 @@ public class BlockScope extends Scope {
                } while ((scope = scope.parent) instanceof BlockScope);
 
                ClassScope localTypeScope = new ClassScope(this, localType);
-               localTypeScope.buildLocalTypeBinding(enclosingSourceType());
                addSubscope(localTypeScope);
+               localTypeScope.buildLocalTypeBinding(enclosingSourceType());
        }
 
        /* Insert a local variable into a given scope, updating its position
@@ -140,7 +140,7 @@ public class BlockScope extends Scope {
 
        /* Answer true if the receiver is suitable for assigning final blank fields.
         *
-        * i.e. is inside an initializer, a constructor or a clinit 
+        * in other words, it is inside an initializer, a constructor or a clinit 
         */
        public final boolean allowBlankFinalFieldAssignment(FieldBinding binding) {
 
@@ -151,9 +151,8 @@ public class BlockScope extends Scope {
                if (methodScope.isStatic != binding.isStatic())
                        return false;
                return methodScope.isInsideInitializer() // inside initializer
-               || ((AbstractMethodDeclaration) methodScope.referenceContext)
-                       .isInitializationMethod();
-               // inside constructor or clinit
+                               || ((AbstractMethodDeclaration) methodScope.referenceContext)
+                                       .isInitializationMethod(); // inside constructor or clinit
        }
        String basicToString(int tab) {
                String newLine = "\n"; //$NON-NLS-1$
@@ -187,100 +186,88 @@ public class BlockScope extends Scope {
        /* Compute variable positions in scopes given an initial position offset
         * ignoring unused local variables.
         * 
-        * Special treatment to have Try secret return address variables located at non
-        * colliding positions. Return addresses are not allocated initially, but gathered
-        * and allocated behind all other variables.
+        * No argument is expected here (ilocal is the first non-argument local of the outermost scope)
+        * Arguments are managed by the MethodScope method
         */
-       public void computeLocalVariablePositions(
-               int initOffset,
-               CodeStream codeStream) {
-
-               this.offset = initOffset;
-               this.maxOffset = initOffset;
-
-               // local variable init
-               int ilocal = 0, maxLocals = 0, localsLength = locals.length;
-               while ((maxLocals < localsLength) && (locals[maxLocals] != null))
-                       maxLocals++;
-               boolean hasMoreVariables = maxLocals > 0;
-
-               // scope init
-               int iscope = 0, maxScopes = 0, subscopesLength = subscopes.length;
-               while ((maxScopes < subscopesLength) && (subscopes[maxScopes] != null))
-                       maxScopes++;
-               boolean hasMoreScopes = maxScopes > 0;
-
-               // iterate scopes and variables in parallel
-               while (hasMoreVariables || hasMoreScopes) {
-                       if (hasMoreScopes
-                               && (!hasMoreVariables || (subscopes[iscope].startIndex() <= ilocal))) {
-                               // consider subscope first
-                               if (subscopes[iscope] instanceof BlockScope) {
-                                       BlockScope subscope = (BlockScope) subscopes[iscope];
-                                       int subOffset = subscope.shiftScopes == null ? this.offset : subscope.maxShiftedOffset();
-                                       subscope.computeLocalVariablePositions(subOffset, codeStream);
-                                       if (subscope.maxOffset > this.maxOffset)
-                                               this.maxOffset = subscope.maxOffset;
-                               }
-                               hasMoreScopes = ++iscope < maxScopes;
-                       } else {
-                               // consider variable first
-                               LocalVariableBinding local = locals[ilocal];
-
-                               // check if variable is actually used, and may force it to be preserved
-                               boolean generatesLocal =
-                                       (local.used && (local.constant == Constant.NotAConstant)) || local.isArgument;
-                               if (!local.used
-                                       && (local.declaration != null) // unused (and non secret) local
-                                       && ((local.declaration.bits & AstNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable
-                                       if (local.isArgument) // method argument
-                                               this.problemReporter().unusedArgument(local.declaration);
-                                       else if (!(local.declaration instanceof Argument))  // do not report unused catch arguments
-                                               this.problemReporter().unusedLocalVariable(local.declaration);
-                               }
-                               if (!generatesLocal) {
-                                       if (local.declaration != null
-                                               && environment().options.preserveAllLocalVariables) {
-                                               generatesLocal = true; // force it to be preserved in the generated code
-                                               local.used = true;
-                                       }
-                               }
-                               if (generatesLocal) {
-
-                                       if (local.declaration != null) {
-                                               codeStream.record(local);
-                                               // record user local variables for attribute generation
-                                       }
-                                       // allocate variable position
-                                       local.resolvedPosition = this.offset;
-
-                                       // check for too many arguments/local variables
-                                       if (local.isArgument) {
-                                               if (this.offset > 0xFF) { // no more than 255 words of arguments
-                                                       this.problemReporter().noMoreAvailableSpaceForArgument(local, local.declaration);
-                                               }
-                                       } else {
-                                               if (this.offset > 0xFFFF) { // no more than 65535 words of locals
-                                                       this.problemReporter().noMoreAvailableSpaceForLocal(
-                                                               local, local.declaration == null ? (AstNode)this.methodScope().referenceContext : local.declaration);
-                                               }
-                                       }
-
-                                       // increment offset
-                                       if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
-                                               this.offset += 2;
-                                       } else {
-                                               this.offset++;
-                                       }
-                               } else {
-                                       local.resolvedPosition = -1; // not generated
-                               }
-                               hasMoreVariables = ++ilocal < maxLocals;
-                       }
-               }
-               if (this.offset > this.maxOffset)
-                       this.maxOffset = this.offset;
-       }
+//     void computeLocalVariablePositions(int ilocal, int initOffset, CodeStream codeStream) {
+//
+//             this.offset = initOffset;
+//             this.maxOffset = initOffset;
+//
+//             // local variable init
+//             int maxLocals = this.localIndex;
+//             boolean hasMoreVariables = ilocal < maxLocals;
+//
+//             // scope init
+//             int iscope = 0, maxScopes = this.scopeIndex;
+//             boolean hasMoreScopes = maxScopes > 0;
+//
+//             // iterate scopes and variables in parallel
+//             while (hasMoreVariables || hasMoreScopes) {
+//                     if (hasMoreScopes
+//                             && (!hasMoreVariables || (subscopes[iscope].startIndex() <= ilocal))) {
+//                             // consider subscope first
+//                             if (subscopes[iscope] instanceof BlockScope) {
+//                                     BlockScope subscope = (BlockScope) subscopes[iscope];
+//                                     int subOffset = subscope.shiftScopes == null ? this.offset : subscope.maxShiftedOffset();
+//                                     subscope.computeLocalVariablePositions(0, subOffset, codeStream);
+//                                     if (subscope.maxOffset > this.maxOffset)
+//                                             this.maxOffset = subscope.maxOffset;
+//                             }
+//                             hasMoreScopes = ++iscope < maxScopes;
+//                     } else {
+//                             
+//                             // consider variable first
+//                             LocalVariableBinding local = locals[ilocal]; // if no local at all, will be locals[ilocal]==null
+//                             
+//                             // check if variable is actually used, and may force it to be preserved
+//                             boolean generateCurrentLocalVar = (local.useFlag == LocalVariableBinding.USED && (local.constant == Constant.NotAConstant));
+//                                     
+//                             // do not report fake used variable
+//                             if (local.useFlag == LocalVariableBinding.UNUSED
+//                                     && (local.declaration != null) // unused (and non secret) local
+//                                     && ((local.declaration.bits & ASTNode.IsLocalDeclarationReachableMASK) != 0)) { // declaration is reachable
+//                                             
+//                                     if (!(local.declaration instanceof Argument))  // do not report unused catch arguments
+//                                             this.problemReporter().unusedLocalVariable(local.declaration);
+//                             }
+//                             
+//                             // could be optimized out, but does need to preserve unread variables ?
+////                           if (!generateCurrentLocalVar) {
+////                                   if (local.declaration != null && environment().options.preserveAllLocalVariables) {
+////                                           generateCurrentLocalVar = true; // force it to be preserved in the generated code
+////                                           local.useFlag = LocalVariableBinding.USED;
+////                                   }
+////                           }
+//                             
+//                             // allocate variable
+//                             if (generateCurrentLocalVar) {
+//
+//                                     if (local.declaration != null) {
+//                                             codeStream.record(local); // record user-defined local variables for attribute generation
+//                                     }
+//                                     // assign variable position
+//                                     local.resolvedPosition = this.offset;
+//
+//                                     if ((local.type == LongBinding) || (local.type == DoubleBinding)) {
+//                                             this.offset += 2;
+//                                     } else {
+//                                             this.offset++;
+//                                     }
+//                                     if (this.offset > 0xFFFF) { // no more than 65535 words of locals
+//                                             this.problemReporter().noMoreAvailableSpaceForLocal(
+//                                                     local, 
+//                                                     local.declaration == null ? (ASTNode)this.methodScope().referenceContext : local.declaration);
+//                                     }
+//                             } else {
+//                                     local.resolvedPosition = -1; // not generated
+//                             }
+//                             hasMoreVariables = ++ilocal < maxLocals;
+//                     }
+//             }
+//             if (this.offset > this.maxOffset)
+//                     this.maxOffset = this.offset;
+//     }
 
        /* Answer true if the variable name already exists within the receiver's scope.
         */
@@ -322,57 +309,6 @@ public class BlockScope extends Scope {
                }
        }
 
-       /*
-        * Record the suitable binding denoting a synthetic field or constructor argument,
-        * mapping to a given actual enclosing instance type in the scope context.
-        * Skip it if the enclosingType is actually the current scope's enclosing type.
-        */
-
-       public void emulateOuterAccess(
-               ReferenceBinding targetEnclosingType,
-               boolean useDirectReference) {
-
-               ReferenceBinding currentType = enclosingSourceType();
-               if (currentType.isNestedType()
-                       && currentType != targetEnclosingType){
-                       /*&& !targetEnclosingType.isSuperclassOf(currentType)*/
-
-                       if (useDirectReference) {
-                               // the target enclosing type is not in scope, we directly refer it
-                               // must also add a synthetic field if we're not inside a constructor
-                               NestedTypeBinding currentNestedType = (NestedTypeBinding) currentType;
-                               if (methodScope().isInsideInitializerOrConstructor())
-                                       currentNestedType.addSyntheticArgument(targetEnclosingType);
-                               else
-                                       currentNestedType.addSyntheticArgumentAndField(targetEnclosingType);
-                                       
-                       } else { // indirect reference sequence
-                               int depth = 0;
-                               
-                               // saturate all the way up until reaching compatible enclosing type
-                               while (currentType.isLocalType()){
-                                       NestedTypeBinding currentNestedType = (NestedTypeBinding) currentType;
-                                       currentType = currentNestedType.enclosingType;
-                                       
-                                       if (depth == 0){
-                                               if (methodScope().isInsideInitializerOrConstructor()) {
-                                                       // must also add a synthetic field if we're not inside a constructor
-                                                       currentNestedType.addSyntheticArgument(currentType);
-                                               } else {
-                                                       currentNestedType.addSyntheticArgumentAndField(currentType);
-                                               }                                       
-                                       } else if (currentNestedType == targetEnclosingType 
-                                                                               || targetEnclosingType.isSuperclassOf(currentNestedType)) {
-                                                       break;
-                                       } else {
-                                               currentNestedType.addSyntheticArgumentAndField(currentType);
-                                       } 
-                                       depth++;
-                               }
-                       }
-               }
-       }
-
        /* Note that it must never produce a direct access to the targetEnclosingType,
         * but instead a field sequence (this$2.this$1.this$0) so as to handle such a test case:
         *
@@ -484,7 +420,7 @@ public class BlockScope extends Scope {
                                        if (!((ReferenceBinding) binding).canBeSeenBy(this))
                                                return new ProblemReferenceBinding(
                                                        CharOperation.subarray(compoundName, 0, currentIndex),
-                                                       binding,
+                                                       (ReferenceBinding)binding,
                                                        NotVisible);
                                        break foundType;
                                }
@@ -503,7 +439,7 @@ public class BlockScope extends Scope {
                        char[] nextName = compoundName[currentIndex++];
                        invocationSite.setFieldIndex(currentIndex);
                        invocationSite.setActualReceiverType(typeBinding);
-                       if ((binding = findField(typeBinding, nextName, invocationSite)) != null) {
+                       if ((mask & FIELD) != 0 && (binding = findField(typeBinding, nextName, invocationSite)) != null) {
                                if (!binding.isValidBinding())
                                        return new ProblemFieldBinding(
                                                ((FieldBinding) binding).declaringClass,
@@ -511,11 +447,19 @@ public class BlockScope extends Scope {
                                                binding.problemId());
                                break; // binding is now a field
                        }
-                       if ((binding = findMemberType(nextName, typeBinding)) == null)
-                               return new ProblemBinding(
-                                       CharOperation.subarray(compoundName, 0, currentIndex),
-                                       typeBinding,
-                                       NotFound);
+                       if ((binding = findMemberType(nextName, typeBinding)) == null) {
+                               if ((mask & FIELD) != 0) {
+                                       return new ProblemBinding(
+                                               CharOperation.subarray(compoundName, 0, currentIndex),
+                                               typeBinding,
+                                               NotFound);
+                               } else {
+                                       return new ProblemReferenceBinding(
+                                               CharOperation.subarray(compoundName, 0, currentIndex),
+                                               typeBinding,
+                                               NotFound);
+                               }
+                       }
                        if (!binding.isValidBinding())
                                return new ProblemReferenceBinding(
                                        CharOperation.subarray(compoundName, 0, currentIndex),
@@ -580,7 +524,7 @@ public class BlockScope extends Scope {
                                        if (!((ReferenceBinding) binding).canBeSeenBy(this))
                                                return new ProblemReferenceBinding(
                                                        CharOperation.subarray(compoundName, 0, currentIndex),
-                                                       binding, 
+                                                       (ReferenceBinding)binding, 
                                                        NotVisible);
                                        break foundType;
                                }
@@ -743,27 +687,27 @@ public class BlockScope extends Scope {
                                                                                                NonStaticReferenceInStaticContext);
                                                                        }
                                                                }
-                                                               if (enclosingType == fieldBinding.declaringClass
-                                                                       || environment().options.complianceLevel >= CompilerOptions.JDK1_4){
-                                                                       // found a valid field in the 'immediate' scope (ie. not inherited)
-                                                                       // OR in 1.4 mode (inherited shadows enclosing)
-                                                                       if (foundField == null) {
-                                                                               if (depth > 0){
-                                                                                       invocationSite.setDepth(depth);
-                                                                                       invocationSite.setActualReceiverType(enclosingType);
-                                                                               }
-                                                                               // return the fieldBinding if it is not declared in a superclass of the scope's binding (i.e. "inherited")
-                                                                               return insideProblem == null ? fieldBinding : insideProblem;
-                                                                       }
-                                                                       if (foundField.isValidBinding())
-                                                                               // if a valid field was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
-                                                                               if (foundField.declaringClass != fieldBinding.declaringClass)
-                                                                                       // ie. have we found the same field - do not trust field identity yet
-                                                                                       return new ProblemFieldBinding(
-                                                                                               fieldBinding.declaringClass,
-                                                                                               name,
-                                                                                               InheritedNameHidesEnclosingName);
-                                                               }
+//                                                             if (enclosingType == fieldBinding.declaringClass
+//                                                                     || environment().options.complianceLevel >= CompilerOptions.JDK1_4){
+//                                                                     // found a valid field in the 'immediate' scope (ie. not inherited)
+//                                                                     // OR in 1.4 mode (inherited shadows enclosing)
+//                                                                     if (foundField == null) {
+//                                                                             if (depth > 0){
+//                                                                                     invocationSite.setDepth(depth);
+//                                                                                     invocationSite.setActualReceiverType(enclosingType);
+//                                                                             }
+//                                                                             // return the fieldBinding if it is not declared in a superclass of the scope's binding (that is, inherited)
+//                                                                             return insideProblem == null ? fieldBinding : insideProblem;
+//                                                                     }
+//                                                                     if (foundField.isValidBinding())
+//                                                                             // if a valid field was found, complain when another is found in an 'immediate' enclosing type (that is, not inherited)
+//                                                                             if (foundField.declaringClass != fieldBinding.declaringClass)
+//                                                                                     // ie. have we found the same field - do not trust field identity yet
+//                                                                                     return new ProblemFieldBinding(
+//                                                                                             fieldBinding.declaringClass,
+//                                                                                             name,
+//                                                                                             InheritedNameHidesEnclosingName);
+//                                                             }
                                                        }
 
                                                        if (foundField == null
@@ -824,86 +768,6 @@ public class BlockScope extends Scope {
                else
                        return new ProblemBinding(name, enclosingSourceType(), NotFound);
        }
-       
-       /*
-        * This retrieves the argument that maps to an enclosing instance of the suitable type,
-        *      if not found then answers nil -- do not create one
-        *
-        *              #implicitThis                                                           :  the implicit this will be ok
-        *              #((arg) this$n)                                                         : available as a constructor arg
-        *              #((arg) this$n access$m... access$p)            : available as as a constructor arg + a sequence of synthetic accessors to synthetic fields
-        *              #((fieldDescr) this$n access#m... access$p)     : available as a first synthetic field + a sequence of synthetic accessors to synthetic fields
-        *              nil                                                                                                                             : not found
-        *
-        */
-       public Object[] getCompatibleEmulationPath(ReferenceBinding targetEnclosingType) {
-
-               MethodScope currentMethodScope = this.methodScope();
-               SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
-
-               // identity check
-               if (!currentMethodScope.isStatic 
-                       && !currentMethodScope.isConstructorCall
-                       && (sourceType == targetEnclosingType
-                               || targetEnclosingType.isSuperclassOf(sourceType))) {
-                       return EmulationPathToImplicitThis; // implicit this is good enough
-               }
-               if (!sourceType.isNestedType()
-                       || sourceType.isStatic()) { // no emulation from within non-inner types
-                       return null;
-               }
-               boolean insideConstructor =
-                       currentMethodScope.isInsideInitializerOrConstructor();
-               // use synthetic constructor arguments if possible
-               if (insideConstructor) {
-                       SyntheticArgumentBinding syntheticArg;
-                       if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, this, false)) != null) {
-                               return new Object[] { syntheticArg };
-                       }
-               }
-
-               // use a direct synthetic field then
-               if (!currentMethodScope.isStatic) {
-                       FieldBinding syntheticField;
-                       if ((syntheticField = sourceType.getSyntheticField(targetEnclosingType, this, false)) != null) {
-                               return new Object[] { syntheticField };
-                       }
-                       // could be reached through a sequence of enclosing instance link (nested members)
-                       Object[] path = new Object[2]; // probably at least 2 of them
-                       ReferenceBinding currentType = sourceType.enclosingType();
-                       if (insideConstructor) {
-                               path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument((SourceTypeBinding) currentType, this, false);
-                       } else {
-                               path[0] =
-                                       sourceType.getSyntheticField((SourceTypeBinding) currentType, this, false);
-                       }
-                       if (path[0] != null) { // keep accumulating
-                               int count = 1;
-                               ReferenceBinding currentEnclosingType;
-                               while ((currentEnclosingType = currentType.enclosingType()) != null) {
-                                       //done?
-                                       if (currentType == targetEnclosingType
-                                               || targetEnclosingType.isSuperclassOf(currentType))
-                                               break;
-                                       syntheticField = ((NestedTypeBinding) currentType).getSyntheticField((SourceTypeBinding) currentEnclosingType, this, false);
-                                       if (syntheticField == null)
-                                               break;
-                                       // append inside the path
-                                       if (count == path.length) {
-                                               System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count);
-                                       }
-                                       // private access emulation is necessary since synthetic field is private
-                                       path[count++] = ((SourceTypeBinding) syntheticField.declaringClass).addSyntheticMethod(syntheticField, true);
-                                       currentType = currentEnclosingType;
-                               }
-                               if (currentType == targetEnclosingType
-                                       || targetEnclosingType.isSuperclassOf(currentType)) {
-                                       return path;
-                               }
-                       }
-               }
-               return null;
-       }
 
        /* API
         *
@@ -922,18 +786,18 @@ public class BlockScope extends Scope {
                compilationUnitScope().recordTypeReference(receiverType);
                compilationUnitScope().recordTypeReferences(argumentTypes);
                MethodBinding methodBinding = receiverType.getExactConstructor(argumentTypes);
-               if (methodBinding != null)
+               if (methodBinding != null) {
                        if (methodBinding.canBeSeenBy(invocationSite, this))
                                return methodBinding;
-
+               }
                MethodBinding[] methods =
                        receiverType.getMethods(ConstructorDeclaration.ConstantPoolName);
-               if (methods == NoMethods)
+               if (methods == NoMethods) {
                        return new ProblemMethodBinding(
                                ConstructorDeclaration.ConstantPoolName,
                                argumentTypes,
                                NotFound);
-
+               }
                MethodBinding[] compatible = new MethodBinding[methods.length];
                int compatibleIndex = 0;
                for (int i = 0, length = methods.length; i < length; i++)
@@ -957,8 +821,9 @@ public class BlockScope extends Scope {
                        return visible[0];
                if (visibleIndex == 0)
                        return new ProblemMethodBinding(
+                               compatible[0],
                                ConstructorDeclaration.ConstantPoolName,
-                               argumentTypes,
+                               compatible[0].parameters,
                                NotVisible);
                return mostSpecificClassMethodBinding(visible, visibleIndex);
        }
@@ -967,9 +832,9 @@ public class BlockScope extends Scope {
         * This retrieves the argument that maps to an enclosing instance of the suitable type,
         *      if not found then answers nil -- do not create one
      * 
-        *                      #implicitThis                                                                   :  the implicit this will be ok
-        *                      #((arg) this$n)                                                         : available as a constructor arg
-        *              #((arg) this$n ... this$p)                              : available as as a constructor arg + a sequence of fields
+        *              #implicitThis                                           : the implicit this will be ok
+        *              #((arg) this$n)                                         : available as a constructor arg
+        *              #((arg) this$n ... this$p)                      : available as as a constructor arg + a sequence of fields
         *              #((fieldDescr) this$n ... this$p)       : available as a sequence of fields
         *              nil                                                                                                     : not found
         *
@@ -1012,80 +877,108 @@ public class BlockScope extends Scope {
         * This retrieves the argument that maps to an enclosing instance of the suitable type,
         *      if not found then answers nil -- do not create one
         *
-        *              #implicitThis                                                           :  the implicit this will be ok
+        *              #implicitThis                                                           :  the implicit this will be ok
         *              #((arg) this$n)                                                         : available as a constructor arg
         *              #((arg) this$n access$m... access$p)            : available as as a constructor arg + a sequence of synthetic accessors to synthetic fields
         *              #((fieldDescr) this$n access#m... access$p)     : available as a first synthetic field + a sequence of synthetic accessors to synthetic fields
-        *              nil                                                                             : not found
-        *
-        *      EXACT MATCH VERSION - no type compatibility is performed
+        *              nil                                                                                                                             : not found
+        *      jls 15.9.2
         */
-       public Object[] getExactEmulationPath(ReferenceBinding targetEnclosingType) {
-
+       public Object[] getEmulationPath(
+                       ReferenceBinding targetEnclosingType, 
+                       boolean onlyExactMatch,
+                       boolean ignoreEnclosingArgInConstructorCall) {
+               //TODO: (philippe) investigate why exactly test76 fails if ignoreEnclosingArgInConstructorCall is always false
                MethodScope currentMethodScope = this.methodScope();
                SourceTypeBinding sourceType = currentMethodScope.enclosingSourceType();
 
                // identity check
                if (!currentMethodScope.isStatic 
-                       && !currentMethodScope.isConstructorCall
-                       && (sourceType == targetEnclosingType)) {
+                       && (!currentMethodScope.isConstructorCall || ignoreEnclosingArgInConstructorCall)
+                       && (sourceType == targetEnclosingType
+                               || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(sourceType)))) {
+                       if (currentMethodScope.isConstructorCall) {
+                               return NoEnclosingInstanceInConstructorCall;
+                       }
+                       if (currentMethodScope.isStatic){
+                               return NoEnclosingInstanceInStaticContext;
+                       }
                        return EmulationPathToImplicitThis; // implicit this is good enough
                }
-               if (!sourceType.isNestedType()
-                       || sourceType.isStatic()) { // no emulation from within non-inner types
+               if (!sourceType.isNestedType() || sourceType.isStatic()) { // no emulation from within non-inner types
+                       if (currentMethodScope.isConstructorCall) {
+                               return NoEnclosingInstanceInConstructorCall;
+                       }
+                               if (currentMethodScope.isStatic){
+                                       return NoEnclosingInstanceInStaticContext;
+                               }
                        return null;
                }
-
-               boolean insideConstructor =
-                       currentMethodScope.isInsideInitializerOrConstructor();
+               boolean insideConstructor = currentMethodScope.isInsideInitializerOrConstructor();
                // use synthetic constructor arguments if possible
                if (insideConstructor) {
                        SyntheticArgumentBinding syntheticArg;
-                       if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, this, true)) != null) {
+                       if ((syntheticArg = ((NestedTypeBinding) sourceType).getSyntheticArgument(targetEnclosingType, onlyExactMatch)) != null) {
                                return new Object[] { syntheticArg };
                        }
                }
+
                // use a direct synthetic field then
-               if (!currentMethodScope.isStatic) {
-                       FieldBinding syntheticField;
-                       if ((syntheticField = sourceType.getSyntheticField(targetEnclosingType, this, true)) != null) {
-                               return new Object[] { syntheticField };
+               if (currentMethodScope.isStatic) {
+                       return NoEnclosingInstanceInStaticContext;
+               }
+               FieldBinding syntheticField = sourceType.getSyntheticField(targetEnclosingType, onlyExactMatch);
+               if (syntheticField != null) {
+                       if (currentMethodScope.isConstructorCall){
+                               return NoEnclosingInstanceInConstructorCall;
                        }
-                       // could be reached through a sequence of enclosing instance link (nested members)
-                       Object[] path = new Object[2]; // probably at least 2 of them
-                       ReferenceBinding currentType = sourceType.enclosingType();
-                       if (insideConstructor) {
-                               path[0] =
-                                       ((NestedTypeBinding) sourceType).getSyntheticArgument((SourceTypeBinding) currentType,  this, true);
-                       } else {
-                               path[0] =
-                                       sourceType.getSyntheticField((SourceTypeBinding) currentType, this, true);
+                       return new Object[] { syntheticField };
+               }
+               // could be reached through a sequence of enclosing instance link (nested members)
+               Object[] path = new Object[2]; // probably at least 2 of them
+               ReferenceBinding currentType = sourceType.enclosingType();
+               if (insideConstructor) {
+                       path[0] = ((NestedTypeBinding) sourceType).getSyntheticArgument((SourceTypeBinding) currentType, onlyExactMatch);
+               } else {
+                       if (currentMethodScope.isConstructorCall){
+                               return NoEnclosingInstanceInConstructorCall;
                        }
-                       if (path[0] != null) { // keep accumulating
-                               int count = 1;
-                               ReferenceBinding currentEnclosingType;
-                               while ((currentEnclosingType = currentType.enclosingType()) != null) {
-                                       //done?
-                                       if (currentType == targetEnclosingType)
-                                               break;
-                                       syntheticField =
-                                               ((NestedTypeBinding) currentType).getSyntheticField(
-                                                       (SourceTypeBinding) currentEnclosingType,
-                                                       this,
-                                                       true);
-                                       if (syntheticField == null)
-                                               break;
-                                       // append inside the path
-                                       if (count == path.length) {
-                                               System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count);
+                       path[0] = sourceType.getSyntheticField((SourceTypeBinding) currentType, onlyExactMatch);
+               }
+               if (path[0] != null) { // keep accumulating
+                       
+                       int count = 1;
+                       ReferenceBinding currentEnclosingType;
+                       while ((currentEnclosingType = currentType.enclosingType()) != null) {
+
+                               //done?
+                               if (currentType == targetEnclosingType
+                                       || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(currentType)))        break;
+
+                               if (currentMethodScope != null) {
+                                       currentMethodScope = currentMethodScope.enclosingMethodScope();
+                                       if (currentMethodScope != null && currentMethodScope.isConstructorCall){
+                                               return NoEnclosingInstanceInConstructorCall;
+                                       }
+                                       if (currentMethodScope != null && currentMethodScope.isStatic){
+                                               return NoEnclosingInstanceInStaticContext;
                                        }
-                                       // private access emulation is necessary since synthetic field is private
-                                       path[count++] = ((SourceTypeBinding) syntheticField.declaringClass).addSyntheticMethod(syntheticField, true);
-                                       currentType = currentEnclosingType;
                                }
-                               if (currentType == targetEnclosingType) {
-                                       return path;
+                               
+                               syntheticField = ((NestedTypeBinding) currentType).getSyntheticField((SourceTypeBinding) currentEnclosingType, onlyExactMatch);
+                               if (syntheticField == null) break;
+
+                               // append inside the path
+                               if (count == path.length) {
+                                       System.arraycopy(path, 0, (path = new Object[count + 1]), 0, count);
                                }
+                               // private access emulation is necessary since synthetic field is private
+                               path[count++] = ((SourceTypeBinding) syntheticField.declaringClass).addSyntheticMethod(syntheticField, true);
+                               currentType = currentEnclosingType;
+                       }
+                       if (currentType == targetEnclosingType
+                               || (!onlyExactMatch && targetEnclosingType.isSuperclassOf(currentType))) {
+                               return path;
                        }
                }
                return null;
@@ -1202,15 +1095,15 @@ public class BlockScope extends Scope {
                                                                                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, argumentTypes, InheritedNameHidesEnclosingName);
+                                                                       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,
-                                                                                       argumentTypes,
-                                                                                       methodBinding.declaringClass,
+                                                                                       methodBinding.parameters,
                                                                                        NotVisible);
                                                                }
                                                        }
@@ -1230,33 +1123,33 @@ public class BlockScope extends Scope {
                                                                }
                                                        }
                                                        
-                                                       if (receiverType == methodBinding.declaringClass
-                                                               || (receiverType.getMethods(selector)) != NoMethods
-                                                               || ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= CompilerOptions.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)
-                                                               if (foundMethod == null) {
-                                                                       if (depth > 0){
-                                                                               invocationSite.setDepth(depth);
-                                                                               invocationSite.setActualReceiverType(receiverType);
-                                                                       }
-                                                                       // return the methodBinding if it is not declared in a superclass of the scope's binding (i.e. "inherited")
-                                                                       if (fuzzyProblem != null)
-                                                                               return fuzzyProblem;
-                                                                       if (insideProblem != null)
-                                                                               return insideProblem;
-                                                                       return methodBinding;
-                                                               }
-                                                               // if a method was found, complain when another is found in an 'immediate' enclosing type (ie. not inherited)
-                                                               // NOTE: Unlike fields, a non visible method hides a visible method
-                                                               if (foundMethod.declaringClass != methodBinding.declaringClass)
-                                                                       // ie. have we found the same method - do not trust field identity yet
-                                                                       return new ProblemMethodBinding(
-                                                                               methodBinding.selector,
-                                                                               methodBinding.parameters,
-                                                                               InheritedNameHidesEnclosingName);
-                                                       }
+//                                                     if (receiverType == methodBinding.declaringClass
+//                                                             || (receiverType.getMethods(selector)) != NoMethods
+//                                                             || ((fuzzyProblem == null || fuzzyProblem.problemId() != NotVisible) && environment().options.complianceLevel >= CompilerOptions.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)
+//                                                             if (foundMethod == null) {
+//                                                                     if (depth > 0){
+//                                                                             invocationSite.setDepth(depth);
+//                                                                             invocationSite.setActualReceiverType(receiverType);
+//                                                                     }
+//                                                                     // return the methodBinding if it is not declared in a superclass of the scope's binding (that is, inherited)
+//                                                                     if (fuzzyProblem != null)
+//                                                                             return fuzzyProblem;
+//                                                                     if (insideProblem != null)
+//                                                                             return insideProblem;
+//                                                                     return methodBinding;
+//                                                             }
+//                                                             // if a method was found, complain when another is found in an 'immediate' enclosing type (that is, not inherited)
+//                                                             // NOTE: Unlike fields, a non visible method hides a visible method
+//                                                             if (foundMethod.declaringClass != methodBinding.declaringClass)
+//                                                                     // ie. have we found the same method - do not trust field identity yet
+//                                                                     return new ProblemMethodBinding(
+//                                                                             methodBinding.selector,
+//                                                                             methodBinding.parameters,
+//                                                                             InheritedNameHidesEnclosingName);
+//                                                     }
                                                }
 
                                                if (foundMethod == null
@@ -1327,8 +1220,7 @@ public class BlockScope extends Scope {
 
                ReferenceBinding currentType = (ReferenceBinding) receiverType;
                if (!currentType.canBeSeenBy(this))
-                       return new ProblemMethodBinding(selector, argumentTypes, NotVisible);
-               // *** Need a new problem id - TypeNotVisible?
+                       return new ProblemMethodBinding(selector, argumentTypes, ReceiverTypeNotVisible);
 
                // retrieve an exact visible match (if possible)
                MethodBinding methodBinding =
@@ -1350,9 +1242,9 @@ public class BlockScope extends Scope {
                                        NotFound);
                        if (!methodBinding.canBeSeenBy(currentType, invocationSite, this))
                                return new ProblemMethodBinding(
+                                       methodBinding,
                                        selector,
-                                       argumentTypes,
-                                       methodBinding.declaringClass,
+                                       methodBinding.parameters,
                                        NotVisible);
                }
                return methodBinding;
@@ -1384,25 +1276,10 @@ public class BlockScope extends Scope {
         * Code responsible to request some more emulation work inside the invocation type, so as to supply
         * correct synthetic arguments to any allocation of the target type.
         */
-       public void propagateInnerEmulation(
-               ReferenceBinding targetType,
-               boolean isEnclosingInstanceSupplied,
-               boolean useDirectReference) {
-
-               // perform some emulation work in case there is some and we are inside a local type only
-               // propage emulation of the enclosing instances
-               ReferenceBinding[] syntheticArgumentTypes;
-               if ((syntheticArgumentTypes = targetType.syntheticEnclosingInstanceTypes())
-                       != null) {
-                       for (int i = 0, max = syntheticArgumentTypes.length; i < max; i++) {
-                               ReferenceBinding syntheticArgType = syntheticArgumentTypes[i];
-                               // need to filter out the one that could match a supplied enclosing instance
-                               if (!(isEnclosingInstanceSupplied
-                                       && (syntheticArgType == targetType.enclosingType()))) {
-                                       this.emulateOuterAccess(syntheticArgType, useDirectReference);
-                               }
-                       }
-               }
+       public void propagateInnerEmulation(ReferenceBinding targetType, boolean isEnclosingInstanceSupplied) {
+
+               // no need to propagate enclosing instances, they got eagerly allocated already.
+               
                SyntheticArgumentBinding[] syntheticArguments;
                if ((syntheticArguments = targetType.syntheticOuterLocalVariables()) != null) {
                        for (int i = 0, max = syntheticArguments.length; i < max; i++) {
@@ -1418,7 +1295,7 @@ public class BlockScope extends Scope {
 
        /* Answer the reference type of this scope.
         *
-        * i.e. the nearest enclosing type of this scope.
+        * It is the nearest enclosing type of this scope.
         */
        public TypeDeclaration referenceType() {
 
@@ -1442,4 +1319,4 @@ public class BlockScope extends Scope {
                                s += ((BlockScope) subscopes[i]).toString(tab + 1) + "\n"; //$NON-NLS-1$
                return s;
        }
-}
\ No newline at end of file
+}