package org.eclipse.jdt.internal.compiler.lookup;
import org.eclipse.jdt.internal.compiler.ast.ASTNode;
import org.eclipse.jdt.internal.compiler.ast.Expression;
import org.eclipse.jdt.internal.compiler.ast.Invocation;
import org.eclipse.jdt.internal.compiler.ast.NullAnnotationMatching;
import org.eclipse.jdt.internal.compiler.ast.ReferenceExpression;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
public class ParameterizedGenericMethodBinding extends ParameterizedMethodBinding implements Substitution {
public TypeBinding[] typeArguments;
protected LookupEnvironment environment;
public boolean inferredReturnType;
public boolean wasInferred;
public boolean isRaw;
private MethodBinding tiebreakMethod;
public boolean inferredWithUncheckedConversion;
public TypeBinding targetType;
public static MethodBinding computeCompatibleMethod(MethodBinding originalMethod, TypeBinding[] arguments, Scope scope, InvocationSite invocationSite)
{
LookupEnvironment environment = scope.environment();
if(environment.globalOptions.isAnnotationBasedNullAnalysisEnabled) {
ImplicitNullAnnotationVerifier.ensureNullnessIsKnown(originalMethod, scope);
}
ParameterizedGenericMethodBinding methodSubstitute;
TypeVariableBinding[] typeVariables = originalMethod.typeVariables;
TypeBinding[] substitutes = invocationSite.genericTypeArguments();
InferenceContext inferenceContext = null;
TypeBinding[] uncheckedArguments = null;
computeSubstitutes: {
if (substitutes != null) {
if (substitutes.length != typeVariables.length) {
return new ProblemMethodBinding(originalMethod, originalMethod.selector, substitutes, ProblemReasons.TypeParameterArityMismatch);
}
methodSubstitute = environment.createParameterizedGenericMethod(originalMethod, substitutes);
break computeSubstitutes;
}
TypeBinding[] parameters = originalMethod.parameters;
CompilerOptions compilerOptions = scope.compilerOptions();
if (compilerOptions.sourceLevel >= ClassFileConstants.JDK1_8)
return computeCompatibleMethod18(originalMethod, arguments, scope, invocationSite);
inferenceContext = new InferenceContext(originalMethod);
methodSubstitute = inferFromArgumentTypes(scope, originalMethod, arguments, parameters, inferenceContext);
if (methodSubstitute == null)
return null;
if (inferenceContext.hasUnresolvedTypeArgument()) {
if (inferenceContext.isUnchecked) {
int length = inferenceContext.substitutes.length;
System.arraycopy(inferenceContext.substitutes, 0, uncheckedArguments = new TypeBinding[length], 0, length);
}
if (methodSubstitute.returnType != TypeBinding.VOID) {
TypeBinding expectedType = invocationSite.invocationTargetType();
if (expectedType != null) {
inferenceContext.hasExplicitExpectedType = true;
} else {
expectedType = scope.getJavaLangObject();
}
inferenceContext.expectedType = expectedType;
}
methodSubstitute = methodSubstitute.inferFromExpectedType(scope, inferenceContext);
if (methodSubstitute == null)
return null;
} else if (compilerOptions.sourceLevel == ClassFileConstants.JDK1_7) {
if (methodSubstitute.returnType != TypeBinding.VOID) {
TypeBinding expectedType = invocationSite.invocationTargetType();
if (expectedType != null && !originalMethod.returnType.mentionsAny(originalMethod.parameters, -1)) {
TypeBinding uncaptured = methodSubstitute.returnType.uncapture(scope);
if (!methodSubstitute.returnType.isCompatibleWith(expectedType) &&
expectedType.isCompatibleWith(uncaptured)) {
InferenceContext oldContext = inferenceContext;
inferenceContext = new InferenceContext(originalMethod);
originalMethod.returnType.collectSubstitutes(scope, expectedType, inferenceContext, TypeConstants.CONSTRAINT_EXTENDS);
ParameterizedGenericMethodBinding substitute = inferFromArgumentTypes(scope, originalMethod, arguments, parameters, inferenceContext);
if (substitute != null && substitute.returnType.isCompatibleWith(expectedType)) {
if ((scope.parameterCompatibilityLevel(substitute, arguments, false)) > Scope.NOT_COMPATIBLE) {
methodSubstitute = substitute;
} else {
inferenceContext = oldContext;
}
} else {
inferenceContext = oldContext;
}
}
}
}
}
}
Substitution substitution = null;
if (inferenceContext != null) {
substitution = new LingeringTypeVariableEliminator(typeVariables, inferenceContext.substitutes, scope);
} else {
substitution = methodSubstitute;
}
for (int i = 0, length = typeVariables.length; i < length; i++) {
TypeVariableBinding typeVariable = typeVariables[i];
TypeBinding substitute = methodSubstitute.typeArguments[i];
TypeBinding substituteForChecks;
if (substitute instanceof TypeVariableBinding) {
substituteForChecks = substitute;
} else {
substituteForChecks = Scope.substitute(new LingeringTypeVariableEliminator(typeVariables, null, scope), substitute);
}
if (uncheckedArguments != null && uncheckedArguments[i] == null) continue;
switch (typeVariable.boundCheck(substitution, substituteForChecks, scope, null)) {
case MISMATCH :
int argLength = arguments.length;
TypeBinding[] augmentedArguments = new TypeBinding[argLength + 2];
System.arraycopy(arguments, 0, augmentedArguments, 0, argLength);
augmentedArguments[argLength] = substitute;
augmentedArguments[argLength+1] = typeVariable;
return new ProblemMethodBinding(methodSubstitute, originalMethod.selector, augmentedArguments, ProblemReasons.ParameterBoundMismatch);
case UNCHECKED :
methodSubstitute.tagBits |= TagBits.HasUncheckedTypeArgumentForBoundCheck;
break;
default:
break;
}
}
return methodSubstitute;
}
public static MethodBinding computeCompatibleMethod18(MethodBinding originalMethod, TypeBinding[] arguments, final Scope scope, InvocationSite invocationSite) {
TypeVariableBinding[] typeVariables = originalMethod.typeVariables;
if (invocationSite.checkingPotentialCompatibility()) {
return scope.environment().createParameterizedGenericMethod(originalMethod, typeVariables);
}
ParameterizedGenericMethodBinding methodSubstitute = null;
InferenceContext18 infCtx18 = invocationSite.freshInferenceContext(scope);
if (infCtx18 == null)
return originalMethod;
TypeBinding[] parameters = originalMethod.parameters;
CompilerOptions compilerOptions = scope.compilerOptions();
boolean invocationTypeInferred = false;
boolean requireBoxing = false;
boolean allArgumentsAreProper = true;
TypeBinding [] argumentsCopy = new TypeBinding[arguments.length];
for (int i = 0, length = arguments.length, parametersLength = parameters.length ; i < length; i++) {
TypeBinding parameter = i < parametersLength ? parameters[i] : parameters[parametersLength - 1];
final TypeBinding argument = arguments[i];
allArgumentsAreProper &= argument.isProperType(true);
if (argument.isPrimitiveType() != parameter.isPrimitiveType()) {
argumentsCopy[i] = scope.environment().computeBoxingType(argument);
requireBoxing = true;
} else {
argumentsCopy[i] = argument;
}
}
arguments = argumentsCopy;
LookupEnvironment environment = scope.environment();
InferenceContext18 previousContext = environment.currentInferenceContext;
if (previousContext == null)
environment.currentInferenceContext = infCtx18;
try {
BoundSet provisionalResult = null;
BoundSet result = null;
final boolean isPolyExpression = invocationSite instanceof Expression && ((Expression) invocationSite).isTrulyExpression() &&
((Expression)invocationSite).isPolyExpression(originalMethod);
boolean isDiamond = isPolyExpression && originalMethod.isConstructor();
if (arguments.length == parameters.length) {
infCtx18.inferenceKind = requireBoxing ? InferenceContext18.CHECK_LOOSE : InferenceContext18.CHECK_STRICT;
infCtx18.inferInvocationApplicability(originalMethod, arguments, isDiamond);
result = infCtx18.solve(true);
}
if (result == null && originalMethod.isVarargs()) {
infCtx18 = invocationSite.freshInferenceContext(scope);
infCtx18.inferenceKind = InferenceContext18.CHECK_VARARG;
infCtx18.inferInvocationApplicability(originalMethod, arguments, isDiamond);
result = infCtx18.solve(true);
}
if (result == null)
return null;
if (infCtx18.isResolved(result)) {
infCtx18.stepCompleted = InferenceContext18.APPLICABILITY_INFERRED;
} else {
return null;
}
TypeBinding expectedType = invocationSite.invocationTargetType();
boolean hasReturnProblem = false;
if (expectedType != null || !invocationSite.getExpressionContext().definesTargetType() || !isPolyExpression) {
provisionalResult = result;
result = infCtx18.inferInvocationType(expectedType, invocationSite, originalMethod);
invocationTypeInferred = infCtx18.stepCompleted == InferenceContext18.TYPE_INFERRED_FINAL;
hasReturnProblem |= result == null;
if (hasReturnProblem)
result = provisionalResult;
}
if (result != null) {
TypeBinding[] solutions = infCtx18.getSolutions(typeVariables, invocationSite, result);
if (solutions != null) {
methodSubstitute = scope.environment().createParameterizedGenericMethod(originalMethod, solutions, infCtx18.usesUncheckedConversion, hasReturnProblem, expectedType);
if (invocationSite instanceof Invocation && allArgumentsAreProper && (expectedType == null || expectedType.isProperType(true)))
infCtx18.forwardResults(result, (Invocation) invocationSite, methodSubstitute, expectedType);
try {
if (hasReturnProblem) {
MethodBinding problemMethod = infCtx18.getReturnProblemMethodIfNeeded(expectedType, methodSubstitute);
if (problemMethod instanceof ProblemMethodBinding) {
return problemMethod;
}
}
if (invocationTypeInferred) {
if (compilerOptions.isAnnotationBasedNullAnalysisEnabled)
NullAnnotationMatching.checkForContradictions(methodSubstitute, invocationSite, scope);
MethodBinding problemMethod = methodSubstitute.boundCheck18(scope, arguments, invocationSite);
if (problemMethod != null) {
return problemMethod;
}
} else {
methodSubstitute = new PolyParameterizedGenericMethodBinding(methodSubstitute);
}
} finally {
if (allArgumentsAreProper) {
if (invocationSite instanceof Invocation)
((Invocation) invocationSite).registerInferenceContext(methodSubstitute, infCtx18);
else if (invocationSite instanceof ReferenceExpression)
((ReferenceExpression) invocationSite).registerInferenceContext(methodSubstitute, infCtx18);
}
}
return methodSubstitute;
}
}
return null;
} catch (InferenceFailureException e) {
scope.problemReporter().genericInferenceError(e.getMessage(), invocationSite);
return null;
} finally {
environment.currentInferenceContext = previousContext;
}
}
MethodBinding boundCheck18(Scope scope, TypeBinding[] arguments, InvocationSite site) {
Substitution substitution = this;
ParameterizedGenericMethodBinding methodSubstitute = this;
TypeVariableBinding[] originalTypeVariables = this.originalMethod.typeVariables;
for (int i = 0, length = originalTypeVariables.length; i < length; i++) {
TypeVariableBinding typeVariable = originalTypeVariables[i];
TypeBinding substitute = methodSubstitute.typeArguments[i];
ASTNode location = site instanceof ASTNode ? (ASTNode) site : null;
switch (typeVariable.boundCheck(substitution, substitute, scope, location)) {
case MISMATCH :
int argLength = arguments.length;
TypeBinding[] augmentedArguments = new TypeBinding[argLength + 2];
System.arraycopy(arguments, 0, augmentedArguments, 0, argLength);
augmentedArguments[argLength] = substitute;
augmentedArguments[argLength+1] = typeVariable;
return new ProblemMethodBinding(methodSubstitute, this.originalMethod.selector, augmentedArguments, ProblemReasons.ParameterBoundMismatch);
case UNCHECKED :
methodSubstitute.tagBits |= TagBits.HasUncheckedTypeArgumentForBoundCheck;
break;
default:
break;
}
}
return null;
}
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;
for (int i = 0; i < minArgLength; i++) {
parameters[i].collectSubstitutes(scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS);
if (inferenceContext.status == InferenceContext.FAILED) return null;
}
if (minArgLength < argLength) {
TypeBinding varargType = parameters[minArgLength];
TypeBinding lastArgument = arguments[minArgLength];
checkVarargDimension: {
if (paramLength == argLength) {
if (lastArgument == TypeBinding.NULL) break checkVarargDimension;
switch (lastArgument.dimensions()) {
case 0 :
break;
case 1 :
if (!lastArgument.leafComponentType().isBaseType()) break checkVarargDimension;
break;
default :
break checkVarargDimension;
}
}
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;
}
}
} 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;
}
}
TypeVariableBinding[] originalVariables = originalMethod.typeVariables;
if (!resolveSubstituteConstraints(scope, originalVariables , inferenceContext, false))
return null;
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);
}
actualSubstitutes[i] = originalVariables[i];
} else if (actualSubstitutes != inferredSustitutes) {
actualSubstitutes[i] = inferredSustitutes[i];
}
}
ParameterizedGenericMethodBinding paramMethod = scope.environment().createParameterizedGenericMethod(originalMethod, actualSubstitutes);
return paramMethod;
}
private static boolean resolveSubstituteConstraints(Scope scope, TypeVariableBinding[] typeVariables, InferenceContext inferenceContext, boolean considerEXTENDSConstraints) {
TypeBinding[] substitutes = inferenceContext.substitutes;
int varLength = typeVariables.length;
nextTypeParameter:
for (int i = 0; i < varLength; i++) {
TypeVariableBinding current = typeVariables[i];
TypeBinding substitute = substitutes[i];
if (substitute != null) continue nextTypeParameter;
TypeBinding [] equalSubstitutes = inferenceContext.getSubstitutes(current, TypeConstants.CONSTRAINT_EQUAL);
if (equalSubstitutes != null) {
nextConstraint:
for (int j = 0, equalLength = equalSubstitutes.length; j < equalLength; j++) {
TypeBinding equalSubstitute = equalSubstitutes[j];
if (equalSubstitute == null) continue nextConstraint;
if (TypeBinding.equalsEquals(equalSubstitute, current)) {
for (int k = j+1; k < equalLength; k++) {
equalSubstitute = equalSubstitutes[k];
if (TypeBinding.notEquals(equalSubstitute, current) && equalSubstitute != null) {
substitutes[i] = equalSubstitute;
continue nextTypeParameter;
}
}
substitutes[i] = current;
continue nextTypeParameter;
}
substitutes[i] = equalSubstitute;
continue nextTypeParameter;
}
}
}
if (inferenceContext.hasUnresolvedTypeArgument()) {
nextTypeParameter:
for (int i = 0; i < varLength; i++) {
TypeVariableBinding current = typeVariables[i];
TypeBinding substitute = substitutes[i];
if (substitute != null) continue nextTypeParameter;
TypeBinding [] bounds = inferenceContext.getSubstitutes(current, TypeConstants.CONSTRAINT_SUPER);
if (bounds == null) continue nextTypeParameter;
TypeBinding mostSpecificSubstitute = scope.lowerUpperBound(bounds);
if (mostSpecificSubstitute == null) {
return false;
}
if (mostSpecificSubstitute != TypeBinding.VOID) {
substitutes[i] = mostSpecificSubstitute;
}
}
}
if (considerEXTENDSConstraints && inferenceContext.hasUnresolvedTypeArgument()) {
nextTypeParameter:
for (int i = 0; i < varLength; i++) {
TypeVariableBinding current = typeVariables[i];
TypeBinding substitute = substitutes[i];
if (substitute != null) continue nextTypeParameter;
TypeBinding [] bounds = inferenceContext.getSubstitutes(current, TypeConstants.CONSTRAINT_EXTENDS);
if (bounds == null) continue nextTypeParameter;
TypeBinding[] glb = Scope.greaterLowerBound(bounds, scope, scope.environment());
TypeBinding mostSpecificSubstitute = null;
if (glb != null) {
if (glb.length == 1) {
mostSpecificSubstitute = glb[0];
} else {
TypeBinding [] otherBounds = new TypeBinding[glb.length - 1];
System.arraycopy(glb, 1, otherBounds, 0, glb.length - 1);
mostSpecificSubstitute = scope.environment().createWildcard(null, 0, glb[0], otherBounds, Wildcard.EXTENDS);
}
}
if (mostSpecificSubstitute != null) {
substitutes[i] = mostSpecificSubstitute;
}
}
}
return true;
}
public ParameterizedGenericMethodBinding(MethodBinding originalMethod, RawTypeBinding rawType, LookupEnvironment environment) {
TypeVariableBinding[] originalVariables = originalMethod.typeVariables;
int length = originalVariables.length;
TypeBinding[] rawArguments = new TypeBinding[length];
for (int i = 0; i < length; i++) {
rawArguments[i] = environment.convertToRawType(originalVariables[i].erasure(), false );
}
this.isRaw = true;
this.tagBits = originalMethod.tagBits;
this.environment = environment;
this.modifiers = originalMethod.modifiers;
this.selector = originalMethod.selector;
this.declaringClass = rawType == null ? originalMethod.declaringClass : rawType;
this.typeVariables = Binding.NO_TYPE_VARIABLES;
this.typeArguments = rawArguments;
this.originalMethod = originalMethod;
boolean ignoreRawTypeSubstitution = rawType == null || originalMethod.isStatic();
this.parameters = Scope.substitute(this, ignoreRawTypeSubstitution
? originalMethod.parameters
: Scope.substitute(rawType, originalMethod.parameters));
this.thrownExceptions = Scope.substitute(this, ignoreRawTypeSubstitution
? originalMethod.thrownExceptions
: Scope.substitute(rawType, originalMethod.thrownExceptions));
if (this.thrownExceptions == null) this.thrownExceptions = Binding.NO_EXCEPTIONS;
this.returnType = Scope.substitute(this, ignoreRawTypeSubstitution
? originalMethod.returnType
: Scope.substitute(rawType, originalMethod.returnType));
this.wasInferred = false;
this.parameterNonNullness = originalMethod.parameterNonNullness;
this.defaultNullness = originalMethod.defaultNullness;
}
public ParameterizedGenericMethodBinding(MethodBinding originalMethod, TypeBinding[] typeArguments, LookupEnvironment environment, boolean inferredWithUncheckConversion, boolean hasReturnProblem, TypeBinding targetType) {
this.environment = environment;
this.inferredWithUncheckedConversion = inferredWithUncheckConversion;
this.targetType = targetType;
this.modifiers = originalMethod.modifiers;
this.selector = originalMethod.selector;
this.declaringClass = originalMethod.declaringClass;
if (inferredWithUncheckConversion && originalMethod.isConstructor() && this.declaringClass.isParameterizedType()) {
this.declaringClass = (ReferenceBinding) environment.convertToRawType(this.declaringClass.erasure(), false);
}
this.typeVariables = Binding.NO_TYPE_VARIABLES;
this.typeArguments = typeArguments;
this.isRaw = false;
this.tagBits = originalMethod.tagBits;
this.originalMethod = originalMethod;
this.parameters = Scope.substitute(this, originalMethod.parameters);
if (inferredWithUncheckConversion) {
this.returnType = getErasure18_5_2(originalMethod.returnType, environment, hasReturnProblem);
this.thrownExceptions = new ReferenceBinding[originalMethod.thrownExceptions.length];
for (int i = 0; i < originalMethod.thrownExceptions.length; i++) {
this.thrownExceptions[i] = (ReferenceBinding) getErasure18_5_2(originalMethod.thrownExceptions[i], environment, false);
}
} else {
this.returnType = Scope.substitute(this, originalMethod.returnType);
this.thrownExceptions = Scope.substitute(this, originalMethod.thrownExceptions);
}
if (this.thrownExceptions == null) this.thrownExceptions = Binding.NO_EXCEPTIONS;
checkMissingType: {
if ((this.tagBits & TagBits.HasMissingType) != 0)
break checkMissingType;
if ((this.returnType.tagBits & TagBits.HasMissingType) != 0) {
this.tagBits |= TagBits.HasMissingType;
break checkMissingType;
}
for (int i = 0, max = this.parameters.length; i < max; i++) {
if ((this.parameters[i].tagBits & TagBits.HasMissingType) != 0) {
this.tagBits |= TagBits.HasMissingType;
break checkMissingType;
}
}
for (int i = 0, max = this.thrownExceptions.length; i < max; i++) {
if ((this.thrownExceptions[i].tagBits & TagBits.HasMissingType) != 0) {
this.tagBits |= TagBits.HasMissingType;
break checkMissingType;
}
}
}
this.wasInferred = true;
this.parameterNonNullness = originalMethod.parameterNonNullness;
this.defaultNullness = originalMethod.defaultNullness;
int len = this.parameters.length;
for (int i = 0; i < len; i++) {
if (this.parameters[i] == TypeBinding.NULL) {
long nullBits = originalMethod.parameters[i].tagBits & TagBits.AnnotationNullMASK;
if (nullBits == TagBits.AnnotationNonNull) {
if (this.parameterNonNullness == null)
this.parameterNonNullness = new Boolean[len];
this.parameterNonNullness[i] = Boolean.TRUE;
}
}
}
}
TypeBinding getErasure18_5_2(TypeBinding type, LookupEnvironment env, boolean substitute) {
if (substitute)
type = Scope.substitute(this, type);
return env.convertToRawType(type.erasure(), true);
}
@Override
public char[] computeUniqueKey(boolean isLeaf) {
StringBuffer buffer = new StringBuffer();
buffer.append(this.originalMethod.computeUniqueKey(false));
buffer.append('%');
buffer.append('<');
if (!this.isRaw) {
int length = this.typeArguments.length;
for (int i = 0; i < length; i++) {
TypeBinding typeArgument = this.typeArguments[i];
buffer.append(typeArgument.computeUniqueKey(false));
}
}
buffer.append('>');
int resultLength = buffer.length();
char[] result = new char[resultLength];
buffer.getChars(0, resultLength, result, 0);
return result;
}
@Override
public LookupEnvironment environment() {
return this.environment;
}
@Override
public boolean hasSubstitutedParameters() {
if (this.wasInferred)
return this.originalMethod.hasSubstitutedParameters();
return super.hasSubstitutedParameters();
}
@Override
public boolean hasSubstitutedReturnType() {
if (this.inferredReturnType)
return this.originalMethod.hasSubstitutedReturnType();
return super.hasSubstitutedReturnType();
}
private ParameterizedGenericMethodBinding inferFromExpectedType(Scope scope, InferenceContext inferenceContext) {
TypeVariableBinding[] originalVariables = this.originalMethod.typeVariables;
int varLength = originalVariables.length;
if (inferenceContext.expectedType != null) {
this.returnType.collectSubstitutes(scope, inferenceContext.expectedType, inferenceContext, TypeConstants.CONSTRAINT_SUPER);
if (inferenceContext.status == InferenceContext.FAILED) return null;
}
for (int i = 0; i < varLength; i++) {
TypeVariableBinding originalVariable = originalVariables[i];
TypeBinding argument = this.typeArguments[i];
boolean argAlreadyInferred = TypeBinding.notEquals(argument, originalVariable);
if (TypeBinding.equalsEquals(originalVariable.firstBound, originalVariable.superclass)) {
TypeBinding substitutedBound = Scope.substitute(this, originalVariable.superclass);
argument.collectSubstitutes(scope, substitutedBound, inferenceContext, TypeConstants.CONSTRAINT_SUPER);
if (inferenceContext.status == InferenceContext.FAILED) return null;
if (argAlreadyInferred) {
substitutedBound.collectSubstitutes(scope, argument, inferenceContext, TypeConstants.CONSTRAINT_EXTENDS);
if (inferenceContext.status == InferenceContext.FAILED) return null;
}
}
for (int j = 0, max = originalVariable.superInterfaces.length; j < max; j++) {
TypeBinding substitutedBound = Scope.substitute(this, originalVariable.superInterfaces[j]);
argument.collectSubstitutes(scope, substitutedBound, inferenceContext, TypeConstants.CONSTRAINT_SUPER);
if (inferenceContext.status == InferenceContext.FAILED) return null;
if (argAlreadyInferred) {
substitutedBound.collectSubstitutes(scope, argument, inferenceContext, TypeConstants.CONSTRAINT_EXTENDS);
if (inferenceContext.status == InferenceContext.FAILED) return null;
}
}
}
if (!resolveSubstituteConstraints(scope, originalVariables, inferenceContext, true))
return null;
for (int i = 0; i < varLength; i++) {
TypeBinding substitute = inferenceContext.substitutes[i];
if (substitute != null) {
this.typeArguments[i] = substitute;
} else {
this.typeArguments[i] = inferenceContext.substitutes[i] = originalVariables[i].upperBound();
}
}
this.typeArguments = Scope.substitute(this, this.typeArguments);
TypeBinding oldReturnType = this.returnType;
this.returnType = Scope.substitute(this, this.returnType);
this.inferredReturnType = inferenceContext.hasExplicitExpectedType && TypeBinding.notEquals(this.returnType, oldReturnType);
this.parameters = Scope.substitute(this, this.parameters);
this.thrownExceptions = Scope.substitute(this, this.thrownExceptions);
if (this.thrownExceptions == null) this.thrownExceptions = Binding.NO_EXCEPTIONS;
checkMissingType: {
if ((this.tagBits & TagBits.HasMissingType) != 0)
break checkMissingType;
if ((this.returnType.tagBits & TagBits.HasMissingType) != 0) {
this.tagBits |= TagBits.HasMissingType;
break checkMissingType;
}
for (int i = 0, max = this.parameters.length; i < max; i++) {
if ((this.parameters[i].tagBits & TagBits.HasMissingType) != 0) {
this.tagBits |= TagBits.HasMissingType;
break checkMissingType;
}
}
for (int i = 0, max = this.thrownExceptions.length; i < max; i++) {
if ((this.thrownExceptions[i].tagBits & TagBits.HasMissingType) != 0) {
this.tagBits |= TagBits.HasMissingType;
break checkMissingType;
}
}
}
return this;
}
@Override
public boolean isParameterizedGeneric() {
return true;
}
private static class LingeringTypeVariableEliminator implements Substitution {
final private TypeVariableBinding [] variables;
final private TypeBinding [] substitutes;
final private Scope scope;
public LingeringTypeVariableEliminator(TypeVariableBinding [] variables, TypeBinding [] substitutes, Scope scope) {
this.variables = variables;
this.substitutes = substitutes;
this.scope = scope;
}
@Override
public TypeBinding substitute(TypeVariableBinding typeVariable) {
if (typeVariable.rank >= this.variables.length || TypeBinding.notEquals(this.variables[typeVariable.rank], typeVariable)) {
return typeVariable;
}
if (this.substitutes != null) {
return Scope.substitute(new LingeringTypeVariableEliminator(this.variables, null, this.scope), this.substitutes[typeVariable.rank]);
}
ReferenceBinding genericType = (ReferenceBinding) (typeVariable.declaringElement instanceof ReferenceBinding ? typeVariable.declaringElement : null);
return this.scope.environment().createWildcard(genericType, typeVariable.rank, null, null, Wildcard.UNBOUND, typeVariable.getTypeAnnotations());
}
@Override
public LookupEnvironment environment() {
return this.scope.environment();
}
@Override
public boolean isRawSubstitution() {
return false;
}
}
@Override
public boolean isRawSubstitution() {
return this.isRaw;
}
@Override
public TypeBinding substitute(TypeVariableBinding originalVariable) {
TypeVariableBinding[] variables = this.originalMethod.typeVariables;
int length = variables.length;
if (originalVariable.rank < length && TypeBinding.equalsEquals(variables[originalVariable.rank], originalVariable)) {
TypeBinding substitute = this.typeArguments[originalVariable.rank];
return originalVariable.combineTypeAnnotations(substitute);
}
return originalVariable;
}
@Override
public MethodBinding tiebreakMethod() {
if (this.tiebreakMethod == null)
this.tiebreakMethod = this.originalMethod.asRawMethod(this.environment);
return this.tiebreakMethod;
}
@Override
public MethodBinding genericMethod() {
if (this.isRaw)
return this;
return this.originalMethod;
}
}