import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / FieldReference.java
index 9c4a86d..1e00105 100644 (file)
@@ -21,11 +21,16 @@ public class FieldReference extends Reference implements InvocationSite {
 
        public Expression receiver;
        public char[] token;
-       public FieldBinding binding, codegenBinding;
+       public FieldBinding binding;                                                                                                                    // exact binding resulting from lookup
+       protected FieldBinding codegenBinding;                                                                  // actual binding used for code generation (if no synthetic accessor)
+       public MethodBinding[] syntheticAccessors; // [0]=read accessor [1]=write accessor
+       public static final int READ = 0;
+       public static final int WRITE = 1;
+       
        public long nameSourcePosition; //(start<<32)+end
-       MethodBinding syntheticReadAccessor, syntheticWriteAccessor;
        public TypeBinding receiverType;
-
+       public TypeBinding genericCast;
+       
        public FieldReference(char[] source, long pos) {
 
                token = source;
@@ -33,7 +38,7 @@ public class FieldReference extends Reference implements InvocationSite {
                //by default the position are the one of the field (not true for super access)
                sourceStart = (int) (pos >>> 32);
                sourceEnd = (int) (pos & 0x00000000FFFFFFFFL);
-               bits |= BindingIds.FIELD;
+               bits |= Binding.FIELD;
 
        }
 
@@ -53,7 +58,7 @@ public class FieldReference extends Reference implements InvocationSite {
                                currentScope.problemReporter().uninitializedBlankFinalField(binding, this);
                                // we could improve error msg here telling "cannot use compound assignment on final blank field"
                        }
-                       manageSyntheticReadAccessIfNecessary(currentScope, flowInfo);
+                       manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
                }
                flowInfo =
                        receiver
@@ -66,7 +71,7 @@ public class FieldReference extends Reference implements InvocationSite {
                                        .analyseCode(currentScope, flowContext, flowInfo)
                                        .unconditionalInits();
                }
-               manageSyntheticWriteAccessIfNecessary(currentScope, flowInfo);
+               manageSyntheticAccessIfNecessary(currentScope, flowInfo, false /*write-access*/);
 
                // check if assigning a final field 
                if (binding.isFinal()) {
@@ -107,13 +112,35 @@ public class FieldReference extends Reference implements InvocationSite {
                FlowInfo flowInfo,
                boolean valueRequired) {
 
-               receiver.analyseCode(currentScope, flowContext, flowInfo, !binding.isStatic());
+               boolean nonStatic = !binding.isStatic();
+               receiver.analyseCode(currentScope, flowContext, flowInfo, nonStatic);
+               if (nonStatic) receiver.checkNullStatus(currentScope, flowContext, flowInfo, FlowInfo.NON_NULL);
+               
                if (valueRequired) {
-                       manageSyntheticReadAccessIfNecessary(currentScope, flowInfo);
+                       manageSyntheticAccessIfNecessary(currentScope, flowInfo, true /*read-access*/);
                }
                return flowInfo;
        }
 
+       /**
+        * @see org.eclipse.jdt.internal.compiler.ast.Expression#computeConversion(org.eclipse.jdt.internal.compiler.lookup.Scope, org.eclipse.jdt.internal.compiler.lookup.TypeBinding, org.eclipse.jdt.internal.compiler.lookup.TypeBinding)
+        */
+       public void computeConversion(Scope scope, TypeBinding runtimeTimeType, TypeBinding compileTimeType) {
+               if (runtimeTimeType == null || compileTimeType == null)
+                       return;         
+               // set the generic cast after the fact, once the type expectation is fully known (no need for strict cast)
+               if (this.binding != null && this.binding.isValidBinding()) {
+                       FieldBinding originalBinding = this.binding.original();
+                       if (originalBinding != this.binding) {
+                           // extra cast needed if method return type has type variable
+                           if ((originalBinding.type.tagBits & TagBits.HasTypeVariable) != 0 && runtimeTimeType.id != T_JavaLangObject) {
+                               this.genericCast = originalBinding.type.genericCast(scope.boxing(runtimeTimeType)); // runtimeType could be base type in boxing case
+                           }
+                       }
+               }       
+               super.computeConversion(scope, runtimeTimeType, compileTimeType);
+       }
+
        public FieldBinding fieldBinding() {
 
                return binding;
@@ -133,11 +160,12 @@ public class FieldReference extends Reference implements InvocationSite {
                fieldStore(
                        codeStream,
                        this.codegenBinding,
-                       syntheticWriteAccessor,
+                       syntheticAccessors == null ? null : syntheticAccessors[WRITE],
                        valueRequired);
                if (valueRequired) {
                        codeStream.generateImplicitConversion(assignment.implicitConversion);
                }
+               // no need for generic cast as value got dupped
        }
 
        /**
@@ -161,27 +189,28 @@ public class FieldReference extends Reference implements InvocationSite {
                        boolean isStatic = this.codegenBinding.isStatic();
                        receiver.generateCode(currentScope, codeStream, !isStatic);
                        if (valueRequired) {
-                               if (this.codegenBinding.constant == NotAConstant) {
+                               if (!this.codegenBinding.isConstantValue()) {
                                        if (this.codegenBinding.declaringClass == null) { // array length
                                                codeStream.arraylength();
                                        } else {
-                                               if (syntheticReadAccessor == null) {
+                                               if (syntheticAccessors == null || syntheticAccessors[READ] == null) {
                                                        if (isStatic) {
                                                                codeStream.getstatic(this.codegenBinding);
                                                        } else {
                                                                codeStream.getfield(this.codegenBinding);
                                                        }
                                                } else {
-                                                       codeStream.invokestatic(syntheticReadAccessor);
+                                                       codeStream.invokestatic(syntheticAccessors[READ]);
                                                }
                                        }
+                                       if (this.genericCast != null) codeStream.checkcast(this.genericCast);                   
                                        codeStream.generateImplicitConversion(implicitConversion);
                                } else {
                                        if (!isStatic) {
                                                codeStream.invokeObjectGetClass(); // perform null check
                                                codeStream.pop();
                                        }
-                                       codeStream.generateConstant(this.codegenBinding.constant, implicitConversion);
+                                       codeStream.generateConstant(this.codegenBinding.constant(), implicitConversion);
                                }
                        } else {
                                if (!isStatic){
@@ -207,41 +236,46 @@ public class FieldReference extends Reference implements InvocationSite {
                        codeStream,
                        !(isStatic = this.codegenBinding.isStatic()));
                if (isStatic) {
-                       if (syntheticReadAccessor == null) {
+                       if (syntheticAccessors == null || syntheticAccessors[READ] == null) {
                                codeStream.getstatic(this.codegenBinding);
                        } else {
-                               codeStream.invokestatic(syntheticReadAccessor);
+                               codeStream.invokestatic(syntheticAccessors[READ]);
                        }
                } else {
                        codeStream.dup();
-                       if (syntheticReadAccessor == null) {
+                       if (syntheticAccessors == null || syntheticAccessors[READ] == null) {
                                codeStream.getfield(this.codegenBinding);
                        } else {
-                               codeStream.invokestatic(syntheticReadAccessor);
+                               codeStream.invokestatic(syntheticAccessors[READ]);
                        }
                }
                int operationTypeID;
-               if ((operationTypeID = implicitConversion >> 4) == T_String) {
-                       codeStream.generateStringAppend(currentScope, null, expression);
-               } else {
-                       // promote the array reference to the suitable operation type
-                       codeStream.generateImplicitConversion(implicitConversion);
-                       // generate the increment value (will by itself  be promoted to the operation value)
-                       if (expression == IntLiteral.One) { // prefix operation
-                               codeStream.generateConstant(expression.constant, implicitConversion);
-                       } else {
-                               expression.generateCode(currentScope, codeStream, true);
-                       }
-                       // perform the operation
-                       codeStream.sendOperator(operator, operationTypeID);
-                       // cast the value back to the array reference type
-                       codeStream.generateImplicitConversion(assignmentImplicitConversion);
+               switch(operationTypeID = (implicitConversion & IMPLICIT_CONVERSION_MASK) >> 4) {
+                       case T_JavaLangString :
+                       case T_JavaLangObject :
+                       case T_undefined :
+                               codeStream.generateStringConcatenationAppend(currentScope, null, expression);
+                               break;
+                       default :
+                               // promote the array reference to the suitable operation type
+                               codeStream.generateImplicitConversion(implicitConversion);
+                               // generate the increment value (will by itself  be promoted to the operation value)
+                               if (expression == IntLiteral.One) { // prefix operation
+                                       codeStream.generateConstant(expression.constant, implicitConversion);
+                               } else {
+                                       expression.generateCode(currentScope, codeStream, true);
+                               }
+                               // perform the operation
+                               codeStream.sendOperator(operator, operationTypeID);
+                               // cast the value back to the array reference type
+                               codeStream.generateImplicitConversion(assignmentImplicitConversion);
                }
                fieldStore(
                        codeStream,
                        this.codegenBinding,
-                       syntheticWriteAccessor,
+                       syntheticAccessors == null ? null : syntheticAccessors[WRITE],
                        valueRequired);
+               // no need for generic cast as value got dupped
        }
 
        public void generatePostIncrement(
@@ -256,17 +290,17 @@ public class FieldReference extends Reference implements InvocationSite {
                        codeStream,
                        !(isStatic = this.codegenBinding.isStatic()));
                if (isStatic) {
-                       if (syntheticReadAccessor == null) {
+                       if (syntheticAccessors == null || syntheticAccessors[READ] == null) {
                                codeStream.getstatic(this.codegenBinding);
                        } else {
-                               codeStream.invokestatic(syntheticReadAccessor);
+                               codeStream.invokestatic(syntheticAccessors[READ]);
                        }
                } else {
                        codeStream.dup();
-                       if (syntheticReadAccessor == null) {
+                       if (syntheticAccessors == null || syntheticAccessors[READ] == null) {
                                codeStream.getfield(this.codegenBinding);
                        } else {
-                               codeStream.invokestatic(syntheticReadAccessor);
+                               codeStream.invokestatic(syntheticAccessors[READ]);
                        }
                }
                if (valueRequired) {
@@ -286,15 +320,21 @@ public class FieldReference extends Reference implements InvocationSite {
                                }
                        }
                }
+               codeStream.generateImplicitConversion(implicitConversion);              
                codeStream.generateConstant(
                        postIncrement.expression.constant,
                        implicitConversion);
-               codeStream.sendOperator(postIncrement.operator, this.codegenBinding.type.id);
+               codeStream.sendOperator(postIncrement.operator, this.implicitConversion & COMPILE_TYPE_MASK);
                codeStream.generateImplicitConversion(
                        postIncrement.assignmentImplicitConversion);
-               fieldStore(codeStream, this.codegenBinding, syntheticWriteAccessor, false);
+               fieldStore(codeStream, this.codegenBinding, syntheticAccessors == null ? null : syntheticAccessors[WRITE], false);
+       }
+       /**
+        * @see org.eclipse.jdt.internal.compiler.lookup.InvocationSite#genericTypeArguments()
+        */
+       public TypeBinding[] genericTypeArguments() {
+               return null;
        }
-
        public static final Constant getConstantFor(
                FieldBinding binding,
                Reference reference,
@@ -318,12 +358,14 @@ public class FieldReference extends Reference implements InvocationSite {
                        return NotAConstant;
                }
                if (!binding.isFinal()) {
-                       return binding.constant = NotAConstant;
+                       binding.setConstant(NotAConstant);
+                       return NotAConstant;
                }
-               if (binding.constant != null) {
+               Constant fieldConstant = binding.constant();
+               if (fieldConstant != null) {
                        if (isImplicit || (reference instanceof QualifiedNameReference
                                        && binding == ((QualifiedNameReference)reference).binding)) {
-                               return binding.constant;
+                               return fieldConstant;
                        }
                        return NotAConstant;
                }
@@ -333,17 +375,18 @@ public class FieldReference extends Reference implements InvocationSite {
                //has already been compiled. It can only be from a class within
                //compilation units to process. Thus the field is NOT from a BinaryTypeBinbing
 
-               SourceTypeBinding typeBinding = (SourceTypeBinding) binding.declaringClass;
-               TypeDeclaration typeDecl = typeBinding.scope.referenceContext;
-               FieldDeclaration fieldDecl = typeDecl.declarationOf(binding);
+               FieldBinding originalField = binding.original();
+               SourceTypeBinding sourceType = (SourceTypeBinding) originalField.declaringClass;
+               TypeDeclaration typeDecl = sourceType.scope.referenceContext;
+               FieldDeclaration fieldDecl = typeDecl.declarationOf(originalField);
 
-               fieldDecl.resolve(binding.isStatic() //side effect on binding 
+               fieldDecl.resolve(originalField.isStatic() //side effect on binding 
                                ? typeDecl.staticInitializerScope
                                : typeDecl.initializerScope); 
 
                if (isImplicit || (reference instanceof QualifiedNameReference
                                && binding == ((QualifiedNameReference)reference).binding)) {
-                       return binding.constant;
+                       return binding.constant();
                }
                return NotAConstant;
        }
@@ -361,15 +404,19 @@ public class FieldReference extends Reference implements InvocationSite {
        /*
         * No need to emulate access to protected fields since not implicitly accessed
         */
-       public void manageSyntheticReadAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
+       public void manageSyntheticAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo, boolean isReadAccess) {
 
                if (!flowInfo.isReachable()) return;
+               // if field from parameterized type got found, use the original field at codegen time
+               this.codegenBinding = this.binding.original();
+               
                if (binding.isPrivate()) {
-                       if ((currentScope.enclosingSourceType() != binding.declaringClass)
-                               && (binding.constant == NotAConstant)) {
-                               syntheticReadAccessor =
-                                       ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, true);
-                               currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this);
+                       if ((currentScope.enclosingSourceType() != this.codegenBinding.declaringClass) && !binding.isConstantValue()) {
+                               if (syntheticAccessors == null)
+                                       syntheticAccessors = new MethodBinding[2];
+                               syntheticAccessors[isReadAccess ? READ : WRITE] = 
+                                       ((SourceTypeBinding) this.codegenBinding.declaringClass).addSyntheticMethod(this.codegenBinding, isReadAccess);
+                               currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess);
                                return;
                        }
 
@@ -379,8 +426,10 @@ public class FieldReference extends Reference implements InvocationSite {
                        SourceTypeBinding destinationType =
                                (SourceTypeBinding) (((QualifiedSuperReference) receiver)
                                        .currentCompatibleType);
-                       syntheticReadAccessor = destinationType.addSyntheticMethod(binding, true);
-                       currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this);
+                       if (syntheticAccessors == null)
+                               syntheticAccessors = new MethodBinding[2];
+                       syntheticAccessors[isReadAccess ? READ : WRITE] = destinationType.addSyntheticMethod(this.codegenBinding, isReadAccess);
+                       currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess);
                        return;
 
                } else if (binding.isProtected()) {
@@ -393,86 +442,31 @@ public class FieldReference extends Reference implements InvocationSite {
                                SourceTypeBinding currentCompatibleType =
                                        (SourceTypeBinding) enclosingSourceType.enclosingTypeAt(
                                                (bits & DepthMASK) >> DepthSHIFT);
-                               syntheticReadAccessor = currentCompatibleType.addSyntheticMethod(binding, true);
-                               currentScope.problemReporter().needToEmulateFieldReadAccess(binding, this);
+                               if (syntheticAccessors == null)
+                                       syntheticAccessors = new MethodBinding[2];
+                               syntheticAccessors[isReadAccess ? READ : WRITE] = currentCompatibleType.addSyntheticMethod(this.codegenBinding, isReadAccess);
+                               currentScope.problemReporter().needToEmulateFieldAccess(this.codegenBinding, this, isReadAccess);
                                return;
                        }
                }
                // if the binding declaring class is not visible, need special action
                // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
                // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
-               if (binding.declaringClass != this.receiverType
+               if (this.binding.declaringClass != this.receiverType
                        && !this.receiverType.isArrayType()
-                       && binding.declaringClass != null // array.length
-                       && binding.constant == NotAConstant
+                       && this.binding.declaringClass != null // array.length
+                       && !this.binding.isConstantValue()
                        && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2
-                               && binding.declaringClass.id != T_Object)
+                               && this.binding.declaringClass.id != T_JavaLangObject)
                        //no change for Object fields (in case there was)
-                               || !binding.declaringClass.canBeSeenBy(currentScope))) {
+                               || !this.codegenBinding.declaringClass.canBeSeenBy(currentScope))) {
                        this.codegenBinding =
                                currentScope.enclosingSourceType().getUpdatedFieldBinding(
-                                       binding,
-                                       (ReferenceBinding) this.receiverType);
+                                       this.codegenBinding,
+                                       (ReferenceBinding) this.receiverType.erasure());
                }
        }
 
-       /*
-        * No need to emulate access to protected fields since not implicitly accessed
-        */
-       public void manageSyntheticWriteAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
-
-               if (!flowInfo.isReachable()) return;
-               if (binding.isPrivate()) {
-                       if (currentScope.enclosingSourceType() != binding.declaringClass) {
-                               syntheticWriteAccessor =
-                                       ((SourceTypeBinding) binding.declaringClass).addSyntheticMethod(binding, false);
-                               currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this);
-                               return;
-                       }
-
-               } else if (receiver instanceof QualifiedSuperReference) { // qualified super
-
-                       // qualified super need emulation always
-                       SourceTypeBinding destinationType =
-                               (SourceTypeBinding) (((QualifiedSuperReference) receiver)
-                                       .currentCompatibleType);
-                       syntheticWriteAccessor = destinationType.addSyntheticMethod(binding, false);
-                       currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this);
-                       return;
-
-               } else if (binding.isProtected()) {
-
-                       SourceTypeBinding enclosingSourceType;
-                       if (((bits & DepthMASK) != 0)
-                               && binding.declaringClass.getPackage()
-                                       != (enclosingSourceType = currentScope.enclosingSourceType()).getPackage()) {
-
-                               SourceTypeBinding currentCompatibleType =
-                                       (SourceTypeBinding) enclosingSourceType.enclosingTypeAt(
-                                               (bits & DepthMASK) >> DepthSHIFT);
-                               syntheticWriteAccessor =
-                                       currentCompatibleType.addSyntheticMethod(binding, false);
-                               currentScope.problemReporter().needToEmulateFieldWriteAccess(binding, this);
-                               return;
-                       }
-               }
-               // if the binding declaring class is not visible, need special action
-               // for runtime compatibility on 1.2 VMs : change the declaring class of the binding
-               // NOTE: from target 1.2 on, field's declaring class is touched if any different from receiver type
-               if (binding.declaringClass != this.receiverType
-                       && !this.receiverType.isArrayType()
-                       && binding.declaringClass != null // array.length
-                       && binding.constant == NotAConstant
-                       && ((currentScope.environment().options.targetJDK >= ClassFileConstants.JDK1_2
-                               && binding.declaringClass.id != T_Object)
-                       //no change for Object fields (in case there was)
-                               || !binding.declaringClass.canBeSeenBy(currentScope))) {
-                       this.codegenBinding =
-                               currentScope.enclosingSourceType().getUpdatedFieldBinding(
-                                       binding,
-                                       (ReferenceBinding) this.receiverType);
-               }
-       }
 
        public StringBuffer printExpression(int indent, StringBuffer output) {
 
@@ -509,7 +503,7 @@ public class FieldReference extends Reference implements InvocationSite {
                        scope.problemReporter().invalidField(this, this.receiverType);
                        return null;
                }
-
+               this.receiver.computeConversion(scope, this.receiverType, this.receiverType);
                if (isFieldUseDeprecated(binding, scope, (this.bits & IsStrictlyAssignedMASK) !=0)) {
                        scope.problemReporter().deprecatedField(binding, this);
                }
@@ -521,9 +515,8 @@ public class FieldReference extends Reference implements InvocationSite {
                if (binding.isStatic()) {
                        // static field accessed through receiver? legal but unoptimal (optional warning)
                        if (!(isImplicitThisRcv
-                                       || receiver.isSuper()
                                        || (receiver instanceof NameReference 
-                                               && (((NameReference) receiver).bits & BindingIds.TYPE) != 0))) {
+                                               && (((NameReference) receiver).bits & Binding.TYPE) != 0))) {
                                scope.problemReporter().nonStaticAccessToStaticField(this, binding);
                        }
                        if (!isImplicitThisRcv && binding.declaringClass != receiverType) {