Java tutorial
/******************************************************************************* * Copyright (c) 2013, 2019 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Jesper S Moller - Contributions for * bug 382701 - [1.8][compiler] Implement semantic analysis of Lambda expressions & Reference expression * Bug 405066 - [1.8][compiler][codegen] Implement code generation infrastructure for JSR335 * Stephan Herrmann - Contribution for * Bug 400874 - [1.8][compiler] Inference infrastructure should evolve to meet JLS8 18.x (Part G of JSR335 spec) * Bug 423504 - [1.8] Implement "18.5.3 Functional Interface Parameterization Inference" * Bug 425142 - [1.8][compiler] NPE in ConstraintTypeFormula.reduceSubType * Bug 425153 - [1.8] Having wildcard allows incompatible types in a lambda expression * Bug 425156 - [1.8] Lambda as an argument is flagged with incompatible error * Bug 424403 - [1.8][compiler] Generic method call with method reference argument fails to resolve properly. * Bug 427438 - [1.8][compiler] NPE at org.eclipse.jdt.internal.compiler.ast.ConditionalExpression.generateCode(ConditionalExpression.java:280) * Bug 428352 - [1.8][compiler] Resolution errors don't always surface * Bug 446442 - [1.8] merge null annotations from super methods * Andy Clement (GoPivotal, Inc) aclement@gopivotal.com - Contributions for * Bug 405104 - [1.8][compiler][codegen] Implement support for serializeable lambdas *******************************************************************************/ package org.eclipse.jdt.internal.compiler.ast; import static org.eclipse.jdt.internal.compiler.ast.ExpressionContext.VANILLA_CONTEXT; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy; import org.eclipse.jdt.internal.compiler.flow.FlowInfo; import org.eclipse.jdt.internal.compiler.impl.Constant; import org.eclipse.jdt.internal.compiler.impl.ReferenceContext; import org.eclipse.jdt.internal.compiler.lookup.BlockScope; import org.eclipse.jdt.internal.compiler.lookup.CompilationUnitScope; import org.eclipse.jdt.internal.compiler.lookup.IntersectionTypeBinding18; import org.eclipse.jdt.internal.compiler.lookup.LookupEnvironment; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.compiler.lookup.MethodScope; import org.eclipse.jdt.internal.compiler.lookup.MethodVerifier; import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ProblemReasons; import org.eclipse.jdt.internal.compiler.lookup.RawTypeBinding; import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding; import org.eclipse.jdt.internal.compiler.lookup.Scope; import org.eclipse.jdt.internal.compiler.lookup.TypeBinding; import org.eclipse.jdt.internal.compiler.lookup.TypeBindingVisitor; import org.eclipse.jdt.internal.compiler.lookup.TypeIds; import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding; public abstract class FunctionalExpression extends Expression { protected TypeBinding expectedType; public MethodBinding descriptor; public MethodBinding binding; // Code generation binding. May include synthetics. See getMethodBinding() protected MethodBinding actualMethodBinding; // void of synthetics. boolean ignoreFurtherInvestigation; protected ExpressionContext expressionContext = VANILLA_CONTEXT; public CompilationResult compilationResult; public BlockScope enclosingScope; public int bootstrapMethodNumber = -1; public boolean shouldCaptureInstance = false; // Whether the expression needs access to instance data of enclosing type protected static IErrorHandlingPolicy silentErrorHandlingPolicy = DefaultErrorHandlingPolicies .ignoreAllProblems(); private boolean hasReportedSamProblem = false; public boolean hasDescripterProblem; public boolean isSerializable; public int ordinal; public FunctionalExpression(CompilationResult compilationResult) { this.compilationResult = compilationResult; } public FunctionalExpression() { super(); } @Override public boolean isBoxingCompatibleWith(TypeBinding targetType, Scope scope) { return false; } public void setCompilationResult(CompilationResult compilationResult) { this.compilationResult = compilationResult; } // Return the actual (non-code generation) method binding that is void of synthetics. public MethodBinding getMethodBinding() { return null; } @Override public void setExpectedType(TypeBinding expectedType) { this.expectedType = expectedType; } @Override public void setExpressionContext(ExpressionContext context) { this.expressionContext = context; } @Override public ExpressionContext getExpressionContext() { return this.expressionContext; } @Override public boolean isPolyExpression(MethodBinding candidate) { return true; } @Override public boolean isPolyExpression() { return true; // always as per introduction of part D, JSR 335 } @Override public boolean isFunctionalType() { return true; } @Override public boolean isPertinentToApplicability(TypeBinding targetType, MethodBinding method) { if (targetType instanceof TypeVariableBinding) { TypeVariableBinding typeVariable = (TypeVariableBinding) targetType; if (method != null) { // when called from type inference if (typeVariable.declaringElement == method) return false; if (method.isConstructor() && typeVariable.declaringElement == method.declaringClass) return false; } else { // for internal calls if (typeVariable.declaringElement instanceof MethodBinding) return false; } } return true; } @Override public TypeBinding invocationTargetType() { if (this.expectedType == null) return null; // when during inference this expression mimics as an invocationSite, // we simulate an *invocation* of this functional expression, // where the expected type of the expression is the return type of the sam: MethodBinding sam = this.expectedType.getSingleAbstractMethod(this.enclosingScope, true); if (sam != null && sam.problemId() != ProblemReasons.NoSuchSingleAbstractMethod) { if (sam.isConstructor()) return sam.declaringClass; else return sam.returnType; } return null; } @Override public TypeBinding expectedType() { return this.expectedType; } public boolean argumentsTypeElided() { return true; /* only exception: lambda with explicit argument types. */ } // Notify the compilation unit that it contains some functional types, taking care not to add any transient copies. this is assumed not to be a copy public int recordFunctionalType(Scope scope) { while (scope != null) { switch (scope.kind) { case Scope.METHOD_SCOPE: ReferenceContext context = ((MethodScope) scope).referenceContext; if (context instanceof LambdaExpression) { LambdaExpression expression = (LambdaExpression) context; if (expression != expression.original) // fake universe. return 0; } break; case Scope.COMPILATION_UNIT_SCOPE: CompilationUnitDeclaration unit = ((CompilationUnitScope) scope).referenceContext; return unit.record(this); } scope = scope.parent; } return 0; // not reached. } @Override public TypeBinding resolveType(BlockScope blockScope) { return resolveType(blockScope, false); } public TypeBinding resolveType(BlockScope blockScope, boolean skipKosherCheck) { this.constant = Constant.NotAConstant; this.enclosingScope = blockScope; MethodBinding sam = this.expectedType == null ? null : this.expectedType.getSingleAbstractMethod(blockScope, argumentsTypeElided()); if (sam == null) { blockScope.problemReporter().targetTypeIsNotAFunctionalInterface(this); return null; } if (!sam.isValidBinding() && sam.problemId() != ProblemReasons.ContradictoryNullAnnotations) { return reportSamProblem(blockScope, sam); } this.descriptor = sam; if (skipKosherCheck || kosherDescriptor(blockScope, sam, true)) { if (this.expectedType instanceof IntersectionTypeBinding18) { ReferenceBinding[] intersectingTypes = ((IntersectionTypeBinding18) this.expectedType).intersectingTypes; for (int t = 0, max = intersectingTypes.length; t < max; t++) { if (intersectingTypes[t].findSuperTypeOriginatingFrom(TypeIds.T_JavaIoSerializable, false /*Serializable is not a class*/) != null) { this.isSerializable = true; break; } } } else if (this.expectedType.findSuperTypeOriginatingFrom(TypeIds.T_JavaIoSerializable, false /*Serializable is not a class*/) != null) { this.isSerializable = true; } LookupEnvironment environment = blockScope.environment(); if (environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) { NullAnnotationMatching.checkForContradictions(sam, this, blockScope); } return this.resolvedType = this.expectedType; } return this.resolvedType = null; } protected TypeBinding reportSamProblem(BlockScope blockScope, MethodBinding sam) { if (this.hasReportedSamProblem) return null; switch (sam.problemId()) { case ProblemReasons.NoSuchSingleAbstractMethod: blockScope.problemReporter().targetTypeIsNotAFunctionalInterface(this); this.hasReportedSamProblem = true; break; case ProblemReasons.NotAWellFormedParameterizedType: blockScope.problemReporter().illFormedParameterizationOfFunctionalInterface(this); this.hasReportedSamProblem = true; break; } return null; } class VisibilityInspector extends TypeBindingVisitor { private Scope scope; private boolean shouldChatter; private boolean visible = true; private FunctionalExpression expression; public VisibilityInspector(FunctionalExpression expression, Scope scope, boolean shouldChatter) { this.scope = scope; this.shouldChatter = shouldChatter; this.expression = expression; } private void checkVisibility(ReferenceBinding referenceBinding) { if (!referenceBinding.canBeSeenBy(this.scope)) { this.visible = false; if (this.shouldChatter) this.scope.problemReporter().descriptorHasInvisibleType(this.expression, referenceBinding); } } @Override public boolean visit(ReferenceBinding referenceBinding) { checkVisibility(referenceBinding); return true; } @Override public boolean visit(ParameterizedTypeBinding parameterizedTypeBinding) { checkVisibility(parameterizedTypeBinding); return true; } @Override public boolean visit(RawTypeBinding rawTypeBinding) { checkVisibility(rawTypeBinding); return true; } public boolean visible(TypeBinding type) { TypeBindingVisitor.visit(this, type); return this.visible; } public boolean visible(TypeBinding[] types) { TypeBindingVisitor.visit(this, types); return this.visible; } } public boolean kosherDescriptor(Scope scope, MethodBinding sam, boolean shouldChatter) { VisibilityInspector inspector = new VisibilityInspector(this, scope, shouldChatter); boolean status = true; if (!inspector.visible(sam.returnType)) status = false; if (!inspector.visible(sam.parameters)) status = false; if (!inspector.visible(sam.thrownExceptions)) status = false; if (!inspector.visible(this.expectedType)) status = false; this.hasDescripterProblem |= !status; return status; } public int nullStatus(FlowInfo flowInfo) { return FlowInfo.NON_NULL; } public int diagnosticsSourceEnd() { return this.sourceEnd; } public MethodBinding[] getRequiredBridges() { class BridgeCollector { MethodBinding[] bridges; MethodBinding method; char[] selector; LookupEnvironment environment; Scope scope; BridgeCollector(ReferenceBinding functionalType, MethodBinding method) { this.method = method; this.selector = method.selector; this.environment = FunctionalExpression.this.enclosingScope.environment(); this.scope = FunctionalExpression.this.enclosingScope; collectBridges(new ReferenceBinding[] { functionalType }); } void collectBridges(ReferenceBinding[] interfaces) { int length = interfaces == null ? 0 : interfaces.length; for (int i = 0; i < length; i++) { ReferenceBinding superInterface = interfaces[i]; if (superInterface == null) continue; MethodBinding[] methods = superInterface.getMethods(this.selector); for (int j = 0, count = methods == null ? 0 : methods.length; j < count; j++) { MethodBinding inheritedMethod = methods[j]; if (inheritedMethod == null || this.method == inheritedMethod) // descriptor declaring class may not be same functional interface target type. continue; if (inheritedMethod.isStatic() || inheritedMethod.redeclaresPublicObjectMethod(this.scope)) continue; inheritedMethod = MethodVerifier.computeSubstituteMethod(inheritedMethod, this.method, this.environment); if (inheritedMethod == null || !MethodVerifier.isSubstituteParameterSubsignature(this.method, inheritedMethod, this.environment) || !MethodVerifier.areReturnTypesCompatible(this.method, inheritedMethod, this.environment)) continue; final MethodBinding originalInherited = inheritedMethod.original(); final MethodBinding originalOverride = this.method.original(); if (!originalOverride.areParameterErasuresEqual(originalInherited) || TypeBinding.notEquals( originalOverride.returnType.erasure(), originalInherited.returnType.erasure())) add(originalInherited); } collectBridges(superInterface.superInterfaces()); } } void add(MethodBinding inheritedMethod) { if (this.bridges == null) { this.bridges = new MethodBinding[] { inheritedMethod }; return; } int length = this.bridges.length; for (int i = 0; i < length; i++) { if (this.bridges[i].areParameterErasuresEqual(inheritedMethod) && TypeBinding.equalsEquals( this.bridges[i].returnType.erasure(), inheritedMethod.returnType.erasure())) return; } System.arraycopy(this.bridges, 0, this.bridges = new MethodBinding[length + 1], 0, length); this.bridges[length] = inheritedMethod; } MethodBinding[] getBridges() { return this.bridges; } } ReferenceBinding functionalType; if (this.expectedType instanceof IntersectionTypeBinding18) { functionalType = (ReferenceBinding) ((IntersectionTypeBinding18) this.expectedType) .getSAMType(this.enclosingScope); } else { functionalType = (ReferenceBinding) this.expectedType; } return new BridgeCollector(functionalType, this.descriptor).getBridges(); } boolean requiresBridges() { return getRequiredBridges() != null; } public void cleanUp() { // to be overridden by sub-classes } }