public void resolve(BlockScope upperScope) { // special scope for secret locals optimization. this.scope = new BlockScope(upperScope); BlockScope tryScope = new BlockScope(scope); BlockScope finallyScope = null; if (finallyBlock != null) { if (finallyBlock.isEmptyBlock()) { if ((finallyBlock.bits & UndocumentedEmptyBlockMASK) != 0) { scope .problemReporter() .undocumentedEmptyBlock(finallyBlock.sourceStart, finallyBlock.sourceEnd); } } else { finallyScope = new BlockScope(scope, false); // don't add it yet to parent scope // provision for returning and forcing the finally block to run MethodScope methodScope = scope.methodScope(); // the type does not matter as long as it is not a base type if (!upperScope.compilerOptions().inlineJsrBytecode) { this.returnAddressVariable = new LocalVariableBinding( SecretReturnName, upperScope.getJavaLangObject(), AccDefault, false); finallyScope.addLocalVariable(returnAddressVariable); this.returnAddressVariable.setConstant(NotAConstant); // not inlinable } this.subRoutineStartLabel = new Label(); this.anyExceptionVariable = new LocalVariableBinding( SecretAnyHandlerName, scope.getJavaLangThrowable(), AccDefault, false); finallyScope.addLocalVariable(this.anyExceptionVariable); this.anyExceptionVariable.setConstant(NotAConstant); // not inlinable if (!methodScope.isInsideInitializer()) { MethodBinding methodBinding = ((AbstractMethodDeclaration) methodScope.referenceContext).binding; if (methodBinding != null) { TypeBinding methodReturnType = methodBinding.returnType; if (methodReturnType.id != T_void) { this.secretReturnValue = new LocalVariableBinding( SecretLocalDeclarationName, methodReturnType, AccDefault, false); finallyScope.addLocalVariable(this.secretReturnValue); this.secretReturnValue.setConstant(NotAConstant); // not inlinable } } } finallyBlock.resolveUsing(finallyScope); // force the finally scope to have variable positions shifted after its try scope and catch // ones finallyScope.shiftScopes = new BlockScope[catchArguments == null ? 1 : catchArguments.length + 1]; finallyScope.shiftScopes[0] = tryScope; } } this.tryBlock.resolveUsing(tryScope); // arguments type are checked against JavaLangThrowable in resolveForCatch(..) if (this.catchBlocks != null) { int length = this.catchArguments.length; TypeBinding[] argumentTypes = new TypeBinding[length]; boolean catchHasError = false; for (int i = 0; i < length; i++) { BlockScope catchScope = new BlockScope(scope); if (finallyScope != null) { finallyScope.shiftScopes[i + 1] = catchScope; } // side effect on catchScope in resolveForCatch(..) if ((argumentTypes[i] = catchArguments[i].resolveForCatch(catchScope)) == null) { catchHasError = true; } catchBlocks[i].resolveUsing(catchScope); } if (catchHasError) { return; } // Verify that the catch clause are ordered in the right way: // more specialized first. this.caughtExceptionTypes = new ReferenceBinding[length]; for (int i = 0; i < length; i++) { caughtExceptionTypes[i] = (ReferenceBinding) argumentTypes[i]; for (int j = 0; j < i; j++) { if (caughtExceptionTypes[i].isCompatibleWith(argumentTypes[j])) { scope .problemReporter() .wrongSequenceOfExceptionTypesError( this, caughtExceptionTypes[i], i, argumentTypes[j]); } } } } else { caughtExceptionTypes = new ReferenceBinding[0]; } if (finallyScope != null) { // add finallyScope as last subscope, so it can be shifted behind try/catch subscopes. // the shifting is necessary to achieve no overlay in between the finally scope and its // sibling in term of local variable positions. this.scope.addSubscope(finallyScope); } }
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; }