import eclipse 3.1 M4 compiler
[org.ibex.tool.git] / src / org / eclipse / jdt / internal / compiler / ast / QualifiedAllocationExpression.java
index af7dd02..289eca2 100644 (file)
@@ -16,7 +16,10 @@ import org.eclipse.jdt.internal.compiler.flow.*;
 import org.eclipse.jdt.internal.compiler.lookup.*;
 
 /**
- * Variation on allocation, where can be specified an enclosing instance and an anonymous type
+ * Variation on allocation, where can optionally be specified any of:
+ * - leading enclosing instance
+ * - trailing anonymous type
+ * - generic type arguments for generic constructor invocation
  */
 public class QualifiedAllocationExpression extends AllocationExpression {
        
@@ -31,6 +34,7 @@ public class QualifiedAllocationExpression extends AllocationExpression {
 
        public QualifiedAllocationExpression(TypeDeclaration anonymousType) {
                this.anonymousType = anonymousType;
+               anonymousType.allocation = this;
        }
 
        public FlowInfo analyseCode(
@@ -44,8 +48,9 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                }
                
                // check captured variables are initialized in current context (26134)
+               ReferenceBinding allocatedType = this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding;
                checkCapturedLocalInitializationIfNecessary(
-                       this.superTypeBinding == null ? this.binding.declaringClass : this.superTypeBinding, 
+                       (ReferenceBinding) allocatedType.erasure(),
                        currentScope, 
                        flowInfo);
                
@@ -87,14 +92,19 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                boolean valueRequired) {
 
                int pc = codeStream.position;
-               ReferenceBinding allocatedType = binding.declaringClass;
+               ReferenceBinding allocatedType = this.codegenBinding.declaringClass;
                codeStream.new_(allocatedType);
                if (valueRequired) {
                        codeStream.dup();
                }
                // better highlight for allocation: display the type individually
-               codeStream.recordPositionsFrom(pc, type.sourceStart);
-
+               if (this.type != null) { // null for enum constant body
+                       codeStream.recordPositionsFrom(pc, this.type.sourceStart);
+               } else {
+                       // push enum constant name and ordinal
+                       codeStream.ldc(String.valueOf(enumConstant.name));
+                       codeStream.generateInlinedValue(enumConstant.binding.id);
+               }
                // handling innerclass instance allocation - enclosing instance arguments
                if (allocatedType.isNestedType()) {
                        codeStream.generateSyntheticEnclosingInstanceValues(
@@ -104,11 +114,7 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                                this);
                }
                // generate the arguments for constructor
-               if (arguments != null) {
-                       for (int i = 0, count = arguments.length; i < count; i++) {
-                               arguments[i].generateCode(currentScope, codeStream, true);
-                       }
-               }
+               generateArguments(binding, arguments, currentScope, codeStream);
                // handling innerclass instance allocation - outer local arguments
                if (allocatedType.isNestedType()) {
                        codeStream.generateSyntheticOuterArgumentValues(
@@ -119,17 +125,18 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                
                // invoke constructor
                if (syntheticAccessor == null) {
-                       codeStream.invokespecial(binding);
+                       codeStream.invokespecial(this.codegenBinding);
                } else {
                        // synthetic accessor got some extra arguments appended to its signature, which need values
                        for (int i = 0,
-                               max = syntheticAccessor.parameters.length - binding.parameters.length;
+                               max = syntheticAccessor.parameters.length - this.codegenBinding.parameters.length;
                                i < max;
                                i++) {
                                codeStream.aconst_null();
                        }
                        codeStream.invokespecial(syntheticAccessor);
                }
+               codeStream.generateImplicitConversion(this.implicitConversion);
                codeStream.recordPositionsFrom(pc, this.sourceStart);
 
                if (anonymousType != null) {
@@ -153,17 +160,17 @@ public class QualifiedAllocationExpression extends AllocationExpression {
        public void manageEnclosingInstanceAccessIfNecessary(BlockScope currentScope, FlowInfo flowInfo) {
 
                if (!flowInfo.isReachable()) return;
-               ReferenceBinding allocatedType;
+               ReferenceBinding allocatedTypeErasure = (ReferenceBinding) binding.declaringClass.erasure();
 
                // perform some emulation work in case there is some and we are inside a local type only
-               if ((allocatedType = binding.declaringClass).isNestedType()
+               if (allocatedTypeErasure.isNestedType()
                        && currentScope.enclosingSourceType().isLocalType()) {
 
-                       if (allocatedType.isLocalType()) {
-                               ((LocalTypeBinding) allocatedType).addInnerEmulationDependent(currentScope, enclosingInstance != null);
+                       if (allocatedTypeErasure.isLocalType()) {
+                               ((LocalTypeBinding) allocatedTypeErasure).addInnerEmulationDependent(currentScope, enclosingInstance != null);
                        } else {
                                // locally propagate, since we already now the desired shape for sure
-                               currentScope.propagateInnerEmulation(allocatedType, enclosingInstance != null);
+                               currentScope.propagateInnerEmulation(allocatedTypeErasure, enclosingInstance != null);
                        }
                }
        }
@@ -182,17 +189,14 @@ public class QualifiedAllocationExpression extends AllocationExpression {
        public TypeBinding resolveType(BlockScope scope) {
 
                // added for code assist...cannot occur with 'normal' code
-               if (anonymousType == null && enclosingInstance == null) {
+               if (this.anonymousType == null && this.enclosingInstance == null) {
                        return super.resolveType(scope);
                }
 
                // Propagate the type checking to the arguments, and checks if the constructor is defined.
                // ClassInstanceCreationExpression ::= Primary '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
                // ClassInstanceCreationExpression ::= Name '.' 'new' SimpleName '(' ArgumentListopt ')' ClassBodyopt
-               // ==> by construction, when there is an enclosing instance the typename may NOT be qualified
-               // ==> therefore by construction the type is always a SingleTypeReferenceType instead of being either 
-               // sometime a SingleTypeReference and sometime a QualifedTypeReference
-
+               
                constant = NotAConstant;
                TypeBinding enclosingInstanceType = null;
                TypeBinding receiverType = null;
@@ -212,22 +216,42 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                                        enclosingInstanceType,
                                        enclosingInstance);
                                hasError = true;
+                       } else if (type instanceof QualifiedTypeReference) {
+                               scope.problemReporter().illegalUsageOfQualifiedTypeReference((QualifiedTypeReference)type);
+                               hasError = true;
                        } else {
                                receiverType = ((SingleTypeReference) type).resolveTypeEnclosing(scope, (ReferenceBinding) enclosingInstanceType);
                                if (receiverType != null && enclosingInstanceContainsCast) {
-                                               CastExpression.checkNeedForEnclosingInstanceCast(scope, enclosingInstance, enclosingInstanceType, receiverType);
+                                       CastExpression.checkNeedForEnclosingInstanceCast(scope, enclosingInstance, enclosingInstanceType, receiverType);
                                }
                        }
                } else {
-                       receiverType = type.resolveType(scope);
+                       if (this.type == null) {
+                               // initialization of an enum constant
+                               receiverType = scope.enclosingSourceType();
+                       } else {
+                               receiverType = this.type.resolveType(scope, true /* check bounds*/);
+                       }                       
                }
                if (receiverType == null) {
                        hasError = true;
                } else if (((ReferenceBinding) receiverType).isFinal() && this.anonymousType != null) {
-                       scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
+                       if (!receiverType.isEnum()) {
+                               scope.problemReporter().anonymousClassCannotExtendFinalClass(type, receiverType);
+                       }
                        hasError = true;
                }
-
+               // resolve type arguments (for generic constructor call)
+               if (this.typeArguments != null) {
+                       int length = this.typeArguments.length;
+                       this.genericTypeArguments = new TypeBinding[length];
+                       for (int i = 0; i < length; i++) {
+                               TypeBinding argType = this.typeArguments[i].resolveType(scope, true /* check bounds*/);
+                               if (argType == null) return null; // error already reported
+                               this.genericTypeArguments[i] = argType;
+                       }
+               }
+               
                // will check for null after args are resolved
                TypeBinding[] argumentTypes = NoParameters;
                if (arguments != null) {
@@ -246,7 +270,6 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                }
                // limit of fault-tolerance
                if (hasError) return this.resolvedType = receiverType;
-               
                if (this.anonymousType == null) {
                        // qualified allocation with no anonymous type
                        ReferenceBinding allocationType = (ReferenceBinding) receiverType;
@@ -258,14 +281,8 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                                if (isMethodUseDeprecated(binding, scope)) {
                                        scope.problemReporter().deprecatedMethod(this.binding, this);
                                }
-                               if (arguments != null) {
-                                       for (int i = 0; i < arguments.length; i++) {
-                                               arguments[i].implicitWidening(this.binding.parameters[i], argumentTypes[i]);
-                                       }
-                                       if (argsContainCast) {
-                                               CastExpression.checkNeedForArgumentCasts(scope, null, allocationType, binding, this.arguments, argumentTypes, this);
-                                       }
-                               }
+                               if (this.arguments != null)
+                                       checkInvocationArguments(scope, null, allocationType, binding, this.arguments, argumentTypes, argsContainCast, this);
                        } else {
                                if (this.binding.declaringClass == null) {
                                        this.binding.declaringClass = allocationType;
@@ -276,16 +293,21 @@ public class QualifiedAllocationExpression extends AllocationExpression {
 
                        // The enclosing instance must be compatible with the innermost enclosing type
                        ReferenceBinding expectedType = this.binding.declaringClass.enclosingType();
-                       if (enclosingInstanceType.isCompatibleWith(expectedType)) {
+                       if (expectedType != enclosingInstanceType) // must call before computeConversion() and typeMismatchError()
+                               scope.compilationUnitScope().recordTypeConversion(expectedType, enclosingInstanceType);
+                       if (enclosingInstanceType.isCompatibleWith(expectedType) || scope.isBoxingCompatibleWith(enclosingInstanceType, expectedType)) {
+                               enclosingInstance.computeConversion(scope, expectedType, enclosingInstanceType);
                                return receiverType;
                        }
-                       scope.problemReporter().typeMismatchErrorActualTypeExpectedType(
-                               this.enclosingInstance,
-                               enclosingInstanceType,
-                               expectedType);
+                       scope.problemReporter().typeMismatchError(enclosingInstanceType, expectedType, this.enclosingInstance);
                        return this.resolvedType = receiverType;
                }
 
+               if (receiverType.isTypeVariable()) {
+                       receiverType = new ProblemReferenceBinding(receiverType.sourceName(), (ReferenceBinding)receiverType, ProblemReasons.IllegalSuperTypeVariable);
+                       scope.problemReporter().invalidType(this, receiverType);
+                       return null;
+               }
                // anonymous type scenario
                // an anonymous class inherits from java.lang.Object when declared "after" an interface
                this.superTypeBinding = receiverType.isInterface() ? scope.getJavaLangObject() : (ReferenceBinding) receiverType;
@@ -293,6 +315,9 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                scope.addAnonymousType(this.anonymousType, (ReferenceBinding) receiverType);
                this.anonymousType.resolve(scope);              
                
+               if ((receiverType.tagBits & TagBits.HasDirectWildcard) != 0) {
+                       scope.problemReporter().superTypeCannotUseWildcard(anonymousType.binding, this.type, receiverType);
+               }               
                // find anonymous super constructor
                MethodBinding inheritedBinding = scope.getConstructor(this.superTypeBinding, argumentTypes, this);
                if (!inheritedBinding.isValidBinding()) {
@@ -307,24 +332,17 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                        if (targetEnclosing == null) {
                                scope.problemReporter().unnecessaryEnclosingInstanceSpecification(enclosingInstance, (ReferenceBinding)receiverType);
                                return this.resolvedType = anonymousType.binding;
-                       } else  if (!enclosingInstanceType.isCompatibleWith(targetEnclosing)) {
-                               scope.problemReporter().typeMismatchErrorActualTypeExpectedType(enclosingInstance, enclosingInstanceType, targetEnclosing);
+                       } else if (!enclosingInstanceType.isCompatibleWith(targetEnclosing) && !scope.isBoxingCompatibleWith(enclosingInstanceType, targetEnclosing)) {
+                               scope.problemReporter().typeMismatchError(enclosingInstanceType, targetEnclosing, enclosingInstance);
                                return this.resolvedType = anonymousType.binding;
                        }
+                       enclosingInstance.computeConversion(scope, targetEnclosing, enclosingInstanceType);
                }
+               if (this.arguments != null)
+                       checkInvocationArguments(scope, null, this.superTypeBinding, inheritedBinding, this.arguments, argumentTypes, argsContainCast, this);
 
-               // this promotion has to be done somewhere: here or inside the constructor of the
-               // anonymous class. We do it here while the constructor of the inner is then easier.
-               if (arguments != null) {
-                       for (int i = 0; i < arguments.length; i++) {
-                               arguments[i].implicitWidening(inheritedBinding.parameters[i], argumentTypes[i]);
-                       }
-                       if (argsContainCast) {
-                               CastExpression.checkNeedForArgumentCasts(scope, null, this.superTypeBinding, inheritedBinding, this.arguments, argumentTypes, this);
-                       }
-               }
                // Update the anonymous inner class : superclass, interface  
-               binding = anonymousType.createsInternalConstructorWithBinding(inheritedBinding);
+               binding = anonymousType.createDefaultConstructorWithBinding(inheritedBinding);
                return this.resolvedType = anonymousType.binding; // 1.2 change
        }
        
@@ -333,7 +351,13 @@ public class QualifiedAllocationExpression extends AllocationExpression {
                if (visitor.visit(this, scope)) {
                        if (enclosingInstance != null)
                                enclosingInstance.traverse(visitor, scope);
-                       type.traverse(visitor, scope);
+                       if (this.typeArguments != null) {
+                               for (int i = 0, typeArgumentsLength = this.typeArguments.length; i < typeArgumentsLength; i++) {
+                                       this.typeArguments[i].traverse(visitor, scope);
+                               }                                       
+                       }
+                       if (this.type != null) // case of enum constant
+                               this.type.traverse(visitor, scope);
                        if (arguments != null) {
                                int argumentsLength = arguments.length;
                                for (int i = 0; i < argumentsLength; i++)