/** * Collect the substitutes into a map for certain type variables inside the receiver type e.g. * Collection<T>.collectSubstitutes(Collection<List<X>>, Map), will populate Map with: T --> * List<X> Constraints: A << F corresponds to: F.collectSubstitutes(..., A, ..., * CONSTRAINT_EXTENDS (1)) A = F corresponds to: F.collectSubstitutes(..., A, ..., * CONSTRAINT_EQUAL (0)) A >> F corresponds to: F.collectSubstitutes(..., A, ..., CONSTRAINT_SUPER * (2)) */ public void collectSubstitutes( Scope scope, TypeBinding actualType, InferenceContext inferenceContext, int constraint) { if ((this.tagBits & TagBits.HasTypeVariable) == 0) return; if (actualType == TypeBinding.NULL) return; switch (actualType.kind()) { case Binding.ARRAY_TYPE: int actualDim = actualType.dimensions(); if (actualDim == this.dimensions) { this.leafComponentType.collectSubstitutes( scope, actualType.leafComponentType(), inferenceContext, constraint); } else if (actualDim > this.dimensions) { ArrayBinding actualReducedType = this.environment.createArrayType( actualType.leafComponentType(), actualDim - this.dimensions); this.leafComponentType.collectSubstitutes( scope, actualReducedType, inferenceContext, constraint); } break; case Binding.TYPE_PARAMETER: // TypeVariableBinding variable = (TypeVariableBinding) otherType; // TODO (philippe) should consider array bounds, and recurse break; } }
/* This method replaces the version that used to sit in LE. The parameter `annotations' is a flattened sequence of annotations, where each dimension's annotations end with a sentinel null. Leaf type can be an already annotated type. See ArrayBinding.swapUnresolved for further special case handling if incoming leafType is a URB that would resolve to a raw type later. */ public ArrayBinding getArrayType( TypeBinding leafType, int dimensions, AnnotationBinding[] annotations) { ArrayBinding nakedType = null; TypeBinding[] derivedTypes = getDerivedTypes(leafType); for (int i = 0, length = derivedTypes.length; i < length; i++) { TypeBinding derivedType = derivedTypes[i]; if (derivedType == null) break; if (!derivedType.isArrayType() || derivedType.dimensions() != dimensions || derivedType.leafComponentType() != leafType) // $IDENTITY-COMPARISON$ continue; if (Util.effectivelyEqual(derivedType.getTypeAnnotations(), annotations)) return (ArrayBinding) derivedType; if (!derivedType.hasTypeAnnotations()) nakedType = (ArrayBinding) derivedType; } if (nakedType == null) nakedType = super.getArrayType(leafType, dimensions); if (!haveTypeAnnotations(leafType, annotations)) return nakedType; ArrayBinding arrayType = new ArrayBinding(leafType, dimensions, this.environment); arrayType.id = nakedType.id; arrayType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled); return (ArrayBinding) cacheDerivedType(leafType, nakedType, arrayType); }
public TypeBinding checkResolvedType( TypeBinding type, Scope scope, int location, boolean hasError) { // SH} if (type.isArrayType() && ((ArrayBinding) type).leafComponentType == TypeBinding.VOID) { scope.problemReporter().cannotAllocateVoidArray(this); return null; } if (!(this instanceof QualifiedTypeReference) // QualifiedTypeReference#getTypeBinding called above will have // already checked deprecation && isTypeUseDeprecated(type, scope)) { reportDeprecatedType(type, scope); } type = scope .environment() .convertToRawType(type, false /*do not force conversion of enclosing types*/); if (type.leafComponentType().isRawType() && (this.bits & ASTNode.IgnoreRawTypeCheck) == 0 && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) { scope.problemReporter().rawTypeReference(this, type); } if (hasError) { resolveAnnotations(scope, 0); // don't apply null defaults to buggy type return type; } else { // store the computed type only if no error, otherwise keep the problem type instead this.resolvedType = type; resolveAnnotations(scope, location); return this .resolvedType; // pick up value that may have been changed in resolveAnnotations(..) } }
/* Answer true if the receiver type can be assigned to the argument type (right) */ public boolean isCompatibleWith(TypeBinding otherType) { if (this == otherType) return true; switch (otherType.kind()) { case Binding.ARRAY_TYPE: ArrayBinding otherArray = (ArrayBinding) otherType; if (otherArray.leafComponentType.isBaseType()) return false; // relying on the fact that all equal arrays are identical if (dimensions == otherArray.dimensions) return leafComponentType.isCompatibleWith(otherArray.leafComponentType); if (dimensions < otherArray.dimensions) return false; // cannot assign 'String[]' into 'Object[][]' but can assign 'byte[][]' into // 'Object[]' break; case Binding.BASE_TYPE: return false; case Binding.WILDCARD_TYPE: case Binding.INTERSECTION_TYPE: return ((WildcardBinding) otherType).boundCheck(this); case Binding.TYPE_PARAMETER: // check compatibility with capture of ? super X if (otherType.isCapture()) { CaptureBinding otherCapture = (CaptureBinding) otherType; TypeBinding otherLowerBound; if ((otherLowerBound = otherCapture.lowerBound) != null) { if (!otherLowerBound.isArrayType()) return false; return this.isCompatibleWith(otherLowerBound); } } return false; } // Check dimensions - Java does not support explicitly sized dimensions for types. // However, if it did, the type checking support would go here. switch (otherType.leafComponentType().id) { case TypeIds.T_JavaLangObject: case TypeIds.T_JavaLangCloneable: case TypeIds.T_JavaIoSerializable: return true; } return false; }
/** Collect argument type mapping, handling varargs */ private static ParameterizedGenericMethodBinding inferFromArgumentTypes( Scope scope, MethodBinding originalMethod, TypeBinding[] arguments, TypeBinding[] parameters, InferenceContext inferenceContext) { if (originalMethod.isVarargs()) { int paramLength = parameters.length; int minArgLength = paramLength - 1; int argLength = arguments.length; // process mandatory arguments for (int i = 0; i < minArgLength; i++) { parameters[i].collectSubstitutes( scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); if (inferenceContext.status == InferenceContext.FAILED) return null; // impossible substitution } // process optional arguments if (minArgLength < argLength) { TypeBinding varargType = parameters[minArgLength]; // last arg type - as is ? TypeBinding lastArgument = arguments[minArgLength]; checkVarargDimension: { if (paramLength == argLength) { if (lastArgument == TypeBinding.NULL) break checkVarargDimension; switch (lastArgument.dimensions()) { case 0: break; // will remove one dim case 1: if (!lastArgument.leafComponentType().isBaseType()) break checkVarargDimension; break; // will remove one dim default: break checkVarargDimension; } } // eliminate one array dimension varargType = ((ArrayBinding) varargType).elementsType(); } for (int i = minArgLength; i < argLength; i++) { varargType.collectSubstitutes( scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); if (inferenceContext.status == InferenceContext.FAILED) return null; // impossible substitution } } } else { int paramLength = parameters.length; for (int i = 0; i < paramLength; i++) { parameters[i].collectSubstitutes( scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); if (inferenceContext.status == InferenceContext.FAILED) return null; // impossible substitution } } TypeVariableBinding[] originalVariables = originalMethod.typeVariables; if (!resolveSubstituteConstraints( scope, originalVariables, inferenceContext, false /*ignore Ti<:Uk*/)) return null; // impossible substitution // apply inferred variable substitutions - replacing unresolved variable with original ones in // param method TypeBinding[] inferredSustitutes = inferenceContext.substitutes; TypeBinding[] actualSubstitutes = inferredSustitutes; for (int i = 0, varLength = originalVariables.length; i < varLength; i++) { if (inferredSustitutes[i] == null) { if (actualSubstitutes == inferredSustitutes) { System.arraycopy( inferredSustitutes, 0, actualSubstitutes = new TypeBinding[varLength], 0, i); // clone to replace null with original variable in param method } actualSubstitutes[i] = originalVariables[i]; } else if (actualSubstitutes != inferredSustitutes) { actualSubstitutes[i] = inferredSustitutes[i]; } } ParameterizedGenericMethodBinding paramMethod = scope.environment().createParameterizedGenericMethod(originalMethod, actualSubstitutes); return paramMethod; }
// return: ReductionResult or ConstraintFormula[] public Object reduce(InferenceContext18 inferenceContext) { switch (this.relation) { case COMPATIBLE: // 18.2.2: if (this.left.isProperType(true) && this.right.isProperType(true)) { return this.left.isCompatibleWith(this.right, inferenceContext.scope) || this.left.isBoxingCompatibleWith(this.right, inferenceContext.scope) ? TRUE : FALSE; } if (this.left.isPrimitiveType()) { TypeBinding sPrime = inferenceContext.environment.computeBoxingType(this.left); return ConstraintTypeFormula.create(sPrime, this.right, COMPATIBLE, this.isSoft); } if (this.right.isPrimitiveType()) { TypeBinding tPrime = inferenceContext.environment.computeBoxingType(this.right); return ConstraintTypeFormula.create(this.left, tPrime, SAME, this.isSoft); } switch (this.right.kind()) { case Binding.ARRAY_TYPE: if (this.right.leafComponentType().kind() != Binding.PARAMETERIZED_TYPE) break; // $FALL-THROUGH$ array of parameterized is handled below: case Binding.PARAMETERIZED_TYPE: { // this.right = G<T1,T2,...> or G<T1,T2,...>[]k TypeBinding gs = this.left.findSuperTypeOriginatingFrom( this.right); // G<S1,S2,...> or G<S1,S2,...>[]k if (gs != null && gs.leafComponentType().isRawType()) { inferenceContext.recordUncheckedConversion(this); return TRUE; } break; } } return ConstraintTypeFormula.create(this.left, this.right, SUBTYPE, this.isSoft); case SUBTYPE: // 18.2.3: return reduceSubType(inferenceContext.scope, this.left, this.right); case SUPERTYPE: // 18.2.3: return reduceSubType(inferenceContext.scope, this.right, this.left); case SAME: if (inferenceContext.environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) if (!checkIVFreeTVmatch(this.left, this.right)) checkIVFreeTVmatch(this.right, this.left); // 18.2.4: return reduceTypeEquality(inferenceContext.object); case TYPE_ARGUMENT_CONTAINED: // 18.2.3: if (this.right.kind() != Binding.WILDCARD_TYPE) { // "If T is a type" ... all alternatives require "wildcard" if (this.left.kind() != Binding.WILDCARD_TYPE) { return ConstraintTypeFormula.create(this.left, this.right, SAME, this.isSoft); } else { return FALSE; } } else { WildcardBinding t = (WildcardBinding) this.right; if (t.boundKind == Wildcard.UNBOUND) return TRUE; if (t.boundKind == Wildcard.EXTENDS) { if (this.left.kind() != Binding.WILDCARD_TYPE) { return ConstraintTypeFormula.create(this.left, t.bound, SUBTYPE, this.isSoft); } else { WildcardBinding s = (WildcardBinding) this.left; switch (s.boundKind) { case Wildcard.UNBOUND: return ConstraintTypeFormula.create( inferenceContext.object, t.bound, SUBTYPE, this.isSoft); case Wildcard.EXTENDS: return ConstraintTypeFormula.create(s.bound, t.bound, SUBTYPE, this.isSoft); case Wildcard.SUPER: return ConstraintTypeFormula.create( inferenceContext.object, t.bound, SAME, this.isSoft); default: throw new IllegalArgumentException( "Unexpected boundKind " + s.boundKind); // $NON-NLS-1$ } } } else { // SUPER if (this.left.kind() != Binding.WILDCARD_TYPE) { return ConstraintTypeFormula.create(t.bound, this.left, SUBTYPE, this.isSoft); } else { WildcardBinding s = (WildcardBinding) this.left; if (s.boundKind == Wildcard.SUPER) { return ConstraintTypeFormula.create(t.bound, s.bound, SUBTYPE, this.isSoft); } else { return FALSE; } } } } default: throw new IllegalStateException("Unexpected relation kind " + this.relation); // $NON-NLS-1$ } }
/* Private subroutine for public APIs. Create an annotated version of the type. To materialize the annotated version, we can't use new since this is a general purpose method designed to deal type bindings of all types. "Clone" the incoming type, specializing for any enclosing type that may itself be possibly be annotated. This is so the binding for @Outer Outer.Inner != Outer.@Inner Inner != @Outer Outer.@Inner Inner. Likewise so the bindings for @Readonly List<@NonNull String> != @Readonly List<@Nullable String> != @Readonly List<@Interned String> */ private TypeBinding getAnnotatedType( TypeBinding type, TypeBinding enclosingType, AnnotationBinding[] annotations) { if (type.kind() == Binding.PARAMETERIZED_TYPE) { return getParameterizedType( type.actualType(), type.typeArguments(), (ReferenceBinding) enclosingType, annotations); } TypeBinding nakedType = null; TypeBinding[] derivedTypes = getDerivedTypes(type); for (int i = 0, length = derivedTypes.length; i < length; i++) { TypeBinding derivedType = derivedTypes[i]; if (derivedType == null) break; if (derivedType.enclosingType() != enclosingType || !Util.effectivelyEqual( derivedType.typeArguments(), type.typeArguments())) // $IDENTITY-COMPARISON$ continue; switch (type.kind()) { case Binding.ARRAY_TYPE: if (!derivedType.isArrayType() || derivedType.dimensions() != type.dimensions() || derivedType.leafComponentType() != type.leafComponentType()) // $IDENTITY-COMPARISON$ continue; break; case Binding.RAW_TYPE: if (!derivedType.isRawType() || derivedType.actualType() != type.actualType()) // $IDENTITY-COMPARISON$ continue; break; case Binding.WILDCARD_TYPE: if (!derivedType.isWildcard() || derivedType.actualType() != type.actualType() || derivedType.rank() != type.rank() || derivedType.boundKind() != type.boundKind()) // $IDENTITY-COMPARISON$ continue; if (derivedType.bound() != type.bound() || !Util.effectivelyEqual( derivedType.additionalBounds(), type.additionalBounds())) // $IDENTITY-COMPARISON$ continue; break; default: switch (derivedType.kind()) { case Binding.ARRAY_TYPE: case Binding.RAW_TYPE: case Binding.WILDCARD_TYPE: case Binding.INTERSECTION_CAST_TYPE: case Binding.INTERSECTION_TYPE: continue; } break; } if (Util.effectivelyEqual(derivedType.getTypeAnnotations(), annotations)) { return derivedType; } if (!derivedType.hasTypeAnnotations()) nakedType = derivedType; } if (nakedType == null) nakedType = getUnannotatedType(type); if (!haveTypeAnnotations(type, enclosingType, null, annotations)) return nakedType; TypeBinding annotatedType = type.clone(enclosingType); annotatedType.id = nakedType.id; annotatedType.setTypeAnnotations(annotations, this.isAnnotationBasedNullAnalysisEnabled); TypeBinding keyType; switch (type.kind()) { case Binding.ARRAY_TYPE: keyType = type.leafComponentType(); break; case Binding.RAW_TYPE: case Binding.WILDCARD_TYPE: keyType = type.actualType(); break; default: keyType = nakedType; break; } return cacheDerivedType(keyType, nakedType, annotatedType); }
protected TypeBinding internalResolveType(Scope scope, int location) { // handle the error here this.constant = Constant.NotAConstant; if (this.resolvedType != null) { // is a shared type reference which was already resolved if (this.resolvedType.isValidBinding()) { return this.resolvedType; } else { switch (this.resolvedType.problemId()) { case ProblemReasons.NotFound: case ProblemReasons.NotVisible: case ProblemReasons.InheritedNameHidesEnclosingName: TypeBinding type = this.resolvedType.closestMatch(); if (type == null) return null; return scope .environment() .convertToRawType(type, false /*do not force conversion of enclosing types*/); default: return null; } } } boolean hasError; // {ObjectTeams: don't let SelectionNodeFound(null) prevent alternate searching strategies: SelectionNodeFound caughtException = null; TypeBinding type = null; try { // base import scope first: CompilationResult compilationResult = scope.referenceCompilationUnit().compilationResult(); CompilationResult.CheckPoint cp = compilationResult.getCheckPoint(scope.referenceContext()); try { type = checkResolveUsingBaseImportScope( scope, location, false); // apply TOLERATE strategy only as a last resort below // copied from below: if (type != null && type.isValidBinding()) { type = scope .environment() .convertToRawType(type, false /*do not force conversion of enclosing types*/); if (type.leafComponentType().isRawType() && (this.bits & ASTNode.IgnoreRawTypeCheck) == 0 && scope.compilerOptions().getSeverity(CompilerOptions.RawTypeReference) != ProblemSeverities.Ignore) { scope.problemReporter().rawTypeReference(this, type); } return type; } } catch (SelectionNodeFound snf) { if (snf.binding != null) throw snf; // found a valid node. caughtException = snf; } finally { if (caughtException != null || (type == null) || !type.isValidBinding()) compilationResult.rollBack(cp); } // ~orig~: type = this.resolvedType = getTypeBinding(scope); if (type == null) { return null; // detected cycle while resolving hierarchy } // :~giro~ } catch (SelectionNodeFound snf) { if (snf.binding != null) throw snf; // found a valid node. caughtException = snf; } // a third chance trying an anchored type: try { if ((caughtException != null) || (this.resolvedType.problemId() == ProblemReasons.NotFound)) { // anchored type TypeBinding result = resolveAnchoredType(scope); if (result != null) // did we do any better than before? type = this.resolvedType = result; // if non-null but ProblemBinding report below. } } catch (SelectionNodeFound snf2) { caughtException = snf2; // throw the newer exception instead. } // a forth chance trying a TOLERATED base imported type: try { if ((caughtException != null) || (this.resolvedType.problemId() == ProblemReasons.NotFound)) { if (this.baseclassDecapsulation == DecapsulationState.TOLERATED) { TypeBinding result = checkResolveUsingBaseImportScope(scope, -1, true); if (result != null) // did we do any better than before? type = this.resolvedType = result; // if non-null but ProblemBinding report below. } } } catch (SelectionNodeFound snf2) { caughtException = snf2; // throw the newer exception instead. } finally { // the attempt to prevent an exception failed: if (caughtException != null) throw caughtException; } // SH} if ((hasError = !type.isValidBinding()) == true) { reportInvalidType(scope); switch (type.problemId()) { case ProblemReasons.NotFound: case ProblemReasons.NotVisible: case ProblemReasons.InheritedNameHidesEnclosingName: type = type.closestMatch(); if (type == null) return null; break; default: return null; } } // {ObjectTeams: Split method to make tail accessible: return checkResolvedType(type, scope, location, hasError); }
public static boolean checkInvocationArguments( BlockScope scope, Expression receiver, TypeBinding receiverType, MethodBinding method, Expression[] arguments, TypeBinding[] argumentTypes, boolean argsContainCast, InvocationSite invocationSite) { TypeBinding[] params = method.parameters; int paramLength = params.length; boolean isRawMemberInvocation = !method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && method.hasSubstitutedParameters(); boolean uncheckedBoundCheck = (method.tagBits & TagBits.HasUncheckedTypeArgumentForBoundCheck) != 0; MethodBinding rawOriginalGenericMethod = null; if (!isRawMemberInvocation) { if (method instanceof ParameterizedGenericMethodBinding) { ParameterizedGenericMethodBinding paramMethod = (ParameterizedGenericMethodBinding) method; if (paramMethod.isRaw && method.hasSubstitutedParameters()) { rawOriginalGenericMethod = method.original(); } } } int invocationStatus = INVOCATION_ARGUMENT_OK; if (arguments == null) { if (method.isVarargs()) { TypeBinding parameterType = ((ArrayBinding) params[paramLength - 1]) .elementsType(); // no element was supplied for vararg parameter if (!parameterType.isReifiable()) { scope .problemReporter() .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite); } } } else { if (method.isVarargs()) { // 4 possibilities exist for a call to the vararg method foo(int i, long ... value) : // foo(1), foo(1, 2), foo(1, 2, 3, 4) & foo(1, new long[] {1, 2}) int lastIndex = paramLength - 1; for (int i = 0; i < lastIndex; i++) { TypeBinding originalRawParam = rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i]; invocationStatus |= checkInvocationArgument( scope, arguments[i], params[i], argumentTypes[i], originalRawParam); } int argLength = arguments.length; if (lastIndex < argLength) { // vararg argument was provided TypeBinding parameterType = params[lastIndex]; TypeBinding originalRawParam = null; if (paramLength != argLength || parameterType.dimensions() != argumentTypes[lastIndex].dimensions()) { parameterType = ((ArrayBinding) parameterType) .elementsType(); // single element was provided for vararg parameter if (!parameterType.isReifiable()) { scope .problemReporter() .unsafeGenericArrayForVarargs(parameterType, (ASTNode) invocationSite); } originalRawParam = rawOriginalGenericMethod == null ? null : ((ArrayBinding) rawOriginalGenericMethod.parameters[lastIndex]) .elementsType(); } for (int i = lastIndex; i < argLength; i++) { invocationStatus |= checkInvocationArgument( scope, arguments[i], parameterType, argumentTypes[i], originalRawParam); } } if (paramLength == argLength) { // 70056 int varargsIndex = paramLength - 1; ArrayBinding varargsType = (ArrayBinding) params[varargsIndex]; TypeBinding lastArgType = argumentTypes[varargsIndex]; int dimensions; if (lastArgType == TypeBinding.NULL) { if (!(varargsType.leafComponentType().isBaseType() && varargsType.dimensions() == 1)) scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } else if (varargsType.dimensions <= (dimensions = lastArgType.dimensions())) { if (lastArgType.leafComponentType().isBaseType()) { dimensions--; } if (varargsType.dimensions < dimensions) { scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } else if (varargsType.dimensions == dimensions && lastArgType != varargsType && lastArgType.leafComponentType().erasure() != varargsType.leafComponentType.erasure() && lastArgType.isCompatibleWith(varargsType.elementsType()) && lastArgType.isCompatibleWith(varargsType)) { scope.problemReporter().varargsArgumentNeedCast(method, lastArgType, invocationSite); } } } } else { for (int i = 0; i < paramLength; i++) { TypeBinding originalRawParam = rawOriginalGenericMethod == null ? null : rawOriginalGenericMethod.parameters[i]; invocationStatus |= checkInvocationArgument( scope, arguments[i], params[i], argumentTypes[i], originalRawParam); } } if (argsContainCast) { CastExpression.checkNeedForArgumentCasts( scope, receiver, receiverType, method, arguments, argumentTypes, invocationSite); } } if ((invocationStatus & INVOCATION_ARGUMENT_WILDCARD) != 0) { scope .problemReporter() .wildcardInvocation((ASTNode) invocationSite, receiverType, method, argumentTypes); } else if (!method.isStatic() && !receiverType.isUnboundWildcard() && method.declaringClass.isRawType() && method.hasSubstitutedParameters()) { scope.problemReporter().unsafeRawInvocation((ASTNode) invocationSite, method); } else if (rawOriginalGenericMethod != null || uncheckedBoundCheck || ((invocationStatus & INVOCATION_ARGUMENT_UNCHECKED) != 0 && method instanceof ParameterizedGenericMethodBinding /*&& method.returnType != scope.environment().convertToRawType(method.returnType.erasure(), true)*/ )) { scope .problemReporter() .unsafeRawGenericMethodInvocation((ASTNode) invocationSite, method, argumentTypes); return true; } return false; }
public TypeBinding resolveTypeExpecting(BlockScope scope, TypeBinding expectedType) { // Array initializers can only occur on the right hand side of an assignment // expression, therefore the expected type contains the valid information // concerning the type that must be enforced by the elements of the array initializer. // this method is recursive... (the test on isArrayType is the stop case) this.constant = Constant.NotAConstant; if (expectedType instanceof ArrayBinding) { // allow new List<?>[5] if ((this.bits & IsAnnotationDefaultValue) == 0) { // annotation default value need only to be commensurate JLS9.7 // allow new List<?>[5] - only check for generic array when no initializer, since also // checked inside initializer resolution TypeBinding leafComponentType = expectedType.leafComponentType(); if (!leafComponentType.isReifiable()) { scope.problemReporter().illegalGenericArray(leafComponentType, this); } } this.resolvedType = this.binding = (ArrayBinding) expectedType; if (this.expressions == null) return this.binding; TypeBinding elementType = this.binding.elementsType(); for (int i = 0, length = this.expressions.length; i < length; i++) { Expression expression = this.expressions[i]; expression.setExpectedType(elementType); TypeBinding expressionType = expression instanceof ArrayInitializer ? expression.resolveTypeExpecting(scope, elementType) : expression.resolveType(scope); if (expressionType == null) continue; // Compile-time conversion required? if (elementType != expressionType) // must call before computeConversion() and typeMismatchError() scope.compilationUnitScope().recordTypeConversion(elementType, expressionType); if (expression.isConstantValueOfTypeAssignableToType(expressionType, elementType) || expressionType.isCompatibleWith(elementType)) { expression.computeConversion(scope, elementType, expressionType); } else if (scope.isBoxingCompatibleWith(expressionType, elementType) || (expressionType.isBaseType() // narrowing then boxing ? && scope.compilerOptions().sourceLevel >= ClassFileConstants.JDK1_5 // autoboxing && !elementType.isBaseType() && expression.isConstantValueOfTypeAssignableToType( expressionType, scope.environment().computeBoxingType(elementType)))) { expression.computeConversion(scope, elementType, expressionType); } else { scope.problemReporter().typeMismatchError(expressionType, elementType, expression, null); } } return this.binding; } // infer initializer type for error reporting based on first element TypeBinding leafElementType = null; int dim = 1; if (this.expressions == null) { leafElementType = scope.getJavaLangObject(); } else { Expression expression = this.expressions[0]; while (expression != null && expression instanceof ArrayInitializer) { dim++; Expression[] subExprs = ((ArrayInitializer) expression).expressions; if (subExprs == null) { leafElementType = scope.getJavaLangObject(); expression = null; break; } expression = ((ArrayInitializer) expression).expressions[0]; } if (expression != null) { leafElementType = expression.resolveType(scope); } // fault-tolerance - resolve other expressions as well for (int i = 1, length = this.expressions.length; i < length; i++) { expression = this.expressions[i]; if (expression != null) { expression.resolveType(scope); } } } if (leafElementType != null) { this.resolvedType = scope.createArrayType(leafElementType, dim); if (expectedType != null) scope.problemReporter().typeMismatchError(this.resolvedType, expectedType, this, null); } return null; }