public TypeBinding resolveType(BlockScope scope) { this.constant = Constant.NotAConstant; TypeBinding expressionType = this.expression.resolveType(scope); TypeBinding checkedType = this.type.resolveType(scope, true /* check bounds*/); if (expressionType == null || checkedType == null) return null; if (!checkedType.isReifiable()) { scope.problemReporter().illegalInstanceOfGenericType(checkedType, this); } else if ((expressionType != TypeBinding.NULL && expressionType.isBaseType()) // disallow autoboxing || !checkCastTypesCompatibility(scope, checkedType, expressionType, null)) { scope.problemReporter().notCompatibleTypesError(this, expressionType, checkedType); } return this.resolvedType = TypeBinding.BOOLEAN; }
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 resolveType(BlockScope scope) { // Build an array type reference using the current dimensions // The parser does not check for the fact that dimension may be null // only at the -end- like new int [4][][]. The parser allows new int[][4][] // so this must be checked here......(this comes from a reduction to LL1 grammar) TypeBinding referenceType = type.resolveType(scope, true /* check bounds*/); // will check for null after dimensions are checked constant = Constant.NotAConstant; if (referenceType == VoidBinding) { scope.problemReporter().cannotAllocateVoidArray(this); referenceType = null; } // check the validity of the dimension syntax (and test for all null dimensions) int explicitDimIndex = -1; loop: for (int i = dimensions.length; --i >= 0; ) { if (dimensions[i] != null) { if (explicitDimIndex < 0) explicitDimIndex = i; } else if (explicitDimIndex > 0) { // should not have an empty dimension before an non-empty one scope.problemReporter().incorrectLocationForNonEmptyDimension(this, explicitDimIndex); break loop; } } // explicitDimIndex < 0 says if all dimensions are nulled // when an initializer is given, no dimension must be specified if (initializer == null) { if (explicitDimIndex < 0) { scope.problemReporter().mustDefineDimensionsOrInitializer(this); } // allow new List<?>[5] - only check for generic array when no initializer, since also checked // inside initializer resolution if (referenceType != null && !referenceType.isReifiable()) { scope.problemReporter().illegalGenericArray(referenceType, this); } } else if (explicitDimIndex >= 0) { scope.problemReporter().cannotDefineDimensionsAndInitializer(this); } // dimensions resolution for (int i = 0; i <= explicitDimIndex; i++) { if (dimensions[i] != null) { TypeBinding dimensionType = dimensions[i].resolveTypeExpecting(scope, IntBinding); if (dimensionType != null) { dimensions[i].computeConversion(scope, IntBinding, dimensionType); } } } // building the array binding if (referenceType != null) { if (dimensions.length > 255) { scope.problemReporter().tooManyDimensions(this); } this.resolvedType = scope.createArrayType(referenceType, dimensions.length); // check the initializer if (initializer != null) { if ((initializer.resolveTypeExpecting(scope, this.resolvedType)) != null) initializer.binding = (ArrayBinding) this.resolvedType; } } return this.resolvedType; }
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; }