1 11 package org.eclipse.jdt.internal.compiler.lookup; 12 13 import org.eclipse.jdt.internal.compiler.ast.MessageSend; 14 15 21 public class ParameterizedGenericMethodBinding extends ParameterizedMethodBinding implements Substitution { 22 23 public TypeBinding[] typeArguments; 24 private LookupEnvironment environment; 25 public boolean inferredReturnType; 26 public boolean wasInferred; public boolean isRaw; private MethodBinding tiebreakMethod; 29 public boolean isUnchecked; 31 34 public static MethodBinding computeCompatibleMethod(MethodBinding originalMethod, TypeBinding[] arguments, Scope scope, InvocationSite invocationSite) { 35 36 ParameterizedGenericMethodBinding methodSubstitute; 37 TypeVariableBinding[] typeVariables = originalMethod.typeVariables; 38 TypeBinding[] substitutes = invocationSite.genericTypeArguments(); 39 40 computeSubstitutes: { 41 if (substitutes != null) { 42 if (substitutes.length != typeVariables.length) { 44 return new ProblemMethodBinding(originalMethod, originalMethod.selector, substitutes, ProblemReasons.TypeParameterArityMismatch); 46 } 47 methodSubstitute = scope.environment().createParameterizedGenericMethod(originalMethod, substitutes); 48 break computeSubstitutes; 49 } 50 51 53 TypeBinding[] parameters = originalMethod.parameters; 55 InferenceContext inferenceContext = new InferenceContext(originalMethod); 56 methodSubstitute = inferFromArgumentTypes(scope, originalMethod, arguments, parameters, inferenceContext); 57 if (methodSubstitute == null) 58 return null; 59 61 if (inferenceContext.hasUnresolvedTypeArgument()) { 63 if (methodSubstitute.returnType != TypeBinding.VOID) { 64 TypeBinding expectedType = null; 65 if (invocationSite instanceof MessageSend) { 67 MessageSend message = (MessageSend) invocationSite; 68 expectedType = message.expectedType; 69 } 70 if (expectedType != null) { 71 inferenceContext.hasExplicitExpectedType = true; 73 } else { 74 expectedType = scope.getJavaLangObject(); } 76 inferenceContext.expectedType = expectedType; 77 } 78 methodSubstitute = methodSubstitute.inferFromExpectedType(scope, inferenceContext); 79 if (methodSubstitute == null) 80 return null; 81 } 82 } 83 84 if (!methodSubstitute.isRaw) { 86 for (int i = 0, length = typeVariables.length; i < length; i++) { 87 TypeVariableBinding typeVariable = typeVariables[i]; 88 TypeBinding substitute = methodSubstitute.typeArguments[i]; 89 switch (typeVariable.boundCheck(methodSubstitute, substitute)) { 90 case TypeConstants.MISMATCH : 91 int argLength = arguments.length; 93 TypeBinding[] augmentedArguments = new TypeBinding[argLength + 2]; System.arraycopy(arguments, 0, augmentedArguments, 0, argLength); 95 augmentedArguments[argLength] = substitute; 96 augmentedArguments[argLength+1] = typeVariable; 97 return new ProblemMethodBinding(methodSubstitute, originalMethod.selector, augmentedArguments, ProblemReasons.ParameterBoundMismatch); 98 case TypeConstants.UNCHECKED : 99 methodSubstitute.isUnchecked = true; 101 break; 102 } 103 } 104 } 105 return methodSubstitute; 106 } 107 108 111 private static ParameterizedGenericMethodBinding inferFromArgumentTypes(Scope scope, MethodBinding originalMethod, TypeBinding[] arguments, TypeBinding[] parameters, InferenceContext inferenceContext) { 112 113 if (originalMethod.isVarargs()) { 114 int paramLength = parameters.length; 115 int minArgLength = paramLength - 1; 116 int argLength = arguments.length; 117 for (int i = 0; i < minArgLength; i++) { 119 parameters[i].collectSubstitutes(scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); 120 if (inferenceContext.status == InferenceContext.FAILED) return null; } 122 if (minArgLength < argLength) { 124 TypeBinding varargType = parameters[minArgLength]; TypeBinding lastArgument = arguments[minArgLength]; 126 checkVarargDimension: { 127 if (paramLength == argLength) { 128 if (lastArgument == TypeBinding.NULL) break checkVarargDimension; 129 switch (lastArgument.dimensions()) { 130 case 0 : 131 break; case 1 : 133 if (!lastArgument.leafComponentType().isBaseType()) break checkVarargDimension; 134 break; default : 136 break checkVarargDimension; 137 } 138 } 139 varargType = ((ArrayBinding)varargType).elementsType(); 141 } 142 for (int i = minArgLength; i < argLength; i++) { 143 varargType.collectSubstitutes(scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); 144 if (inferenceContext.status == InferenceContext.FAILED) return null; } 146 } 147 } else { 148 int paramLength = parameters.length; 149 for (int i = 0; i < paramLength; i++) { 150 parameters[i].collectSubstitutes(scope, arguments[i], inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); 151 if (inferenceContext.status == InferenceContext.FAILED) return null; } 153 } 154 if (inferenceContext.status == InferenceContext.RAW_SUBSTITUTION) { 155 return scope.environment().createParameterizedGenericMethod(originalMethod, (RawTypeBinding)null); 157 } 158 TypeVariableBinding[] originalVariables = originalMethod.typeVariables; 159 if (!resolveSubstituteConstraints(scope, originalVariables , inferenceContext, false)) 160 return null; 162 TypeBinding[] inferredSustitutes = inferenceContext.substitutes; 164 TypeBinding[] actualSubstitutes = inferredSustitutes; 165 for (int i = 0, varLength = originalVariables.length; i < varLength; i++) { 166 if (inferredSustitutes[i] == null) { 167 if (actualSubstitutes == inferredSustitutes) { 168 System.arraycopy(inferredSustitutes, 0, actualSubstitutes = new TypeBinding[varLength], 0, i); } 170 actualSubstitutes[i] = originalVariables[i]; 171 } else if (actualSubstitutes != inferredSustitutes) { 172 actualSubstitutes[i] = inferredSustitutes[i]; 173 } 174 } 175 ParameterizedGenericMethodBinding paramMethod = scope.environment().createParameterizedGenericMethod(originalMethod, actualSubstitutes); 176 return paramMethod; 177 } 178 179 private static boolean resolveSubstituteConstraints(Scope scope, TypeVariableBinding[] typeVariables, InferenceContext inferenceContext, boolean considerEXTENDSConstraints) { 180 TypeBinding[] substitutes = inferenceContext.substitutes; 181 int varLength = typeVariables.length; 182 nextTypeParameter: 184 for (int i = 0; i < varLength; i++) { 185 TypeVariableBinding current = typeVariables[i]; 186 TypeBinding substitute = substitutes[i]; 187 if (substitute != null) continue nextTypeParameter; TypeBinding [] equalSubstitutes = inferenceContext.getSubstitutes(current, TypeConstants.CONSTRAINT_EQUAL); 189 if (equalSubstitutes != null) { 190 nextConstraint: 191 for (int j = 0, equalLength = equalSubstitutes.length; j < equalLength; j++) { 192 TypeBinding equalSubstitute = equalSubstitutes[j]; 193 if (equalSubstitute == null) continue nextConstraint; 194 if (equalSubstitute == current) { 195 for (int k = j+1; k < equalLength; k++) { 197 equalSubstitute = equalSubstitutes[k]; 198 if (equalSubstitute != current && equalSubstitute != null) { 199 substitutes[i] = equalSubstitute; 200 continue nextTypeParameter; 201 } 202 } 203 substitutes[i] = current; 204 continue nextTypeParameter; 205 } 206 substitutes[i] = equalSubstitute; 215 continue nextTypeParameter; } 217 } 218 } 219 if (inferenceContext.hasUnresolvedTypeArgument()) { 220 nextTypeParameter: 222 for (int i = 0; i < varLength; i++) { 223 TypeVariableBinding current = typeVariables[i]; 224 TypeBinding substitute = substitutes[i]; 225 if (substitute != null) continue nextTypeParameter; TypeBinding [] bounds = inferenceContext.getSubstitutes(current, TypeConstants.CONSTRAINT_SUPER); 227 if (bounds == null) continue nextTypeParameter; 228 TypeBinding mostSpecificSubstitute = scope.lowerUpperBound(bounds); 229 if (mostSpecificSubstitute == null) { 230 return false; } 232 if (mostSpecificSubstitute != TypeBinding.VOID) { 233 substitutes[i] = mostSpecificSubstitute; 234 } 235 } 236 } 237 if (considerEXTENDSConstraints && inferenceContext.hasUnresolvedTypeArgument()) { 238 nextTypeParameter: 240 for (int i = 0; i < varLength; i++) { 241 TypeVariableBinding current = typeVariables[i]; 242 TypeBinding substitute = substitutes[i]; 243 if (substitute != null) continue nextTypeParameter; TypeBinding [] bounds = inferenceContext.getSubstitutes(current, TypeConstants.CONSTRAINT_EXTENDS); 245 if (bounds == null) continue nextTypeParameter; 246 TypeBinding[] glb = Scope.greaterLowerBound(bounds); 247 TypeBinding mostSpecificSubstitute = null; 248 if (glb != null) mostSpecificSubstitute = glb[0]; if (mostSpecificSubstitute != null) { 251 substitutes[i] = mostSpecificSubstitute; 252 } 253 } 254 } 255 return true; 256 } 257 258 262 public ParameterizedGenericMethodBinding(MethodBinding originalMethod, RawTypeBinding rawType, LookupEnvironment environment) { 263 264 TypeVariableBinding[] originalVariables = originalMethod.typeVariables; 265 int length = originalVariables.length; 266 TypeBinding[] rawArguments = new TypeBinding[length]; 267 for (int i = 0; i < length; i++) { 268 rawArguments[i] = environment.convertToRawType(originalVariables[i].erasure()); 269 } 270 this.isRaw = true; 271 this.tagBits = originalMethod.tagBits; 272 this.environment = environment; 273 this.modifiers = originalMethod.modifiers; 274 this.selector = originalMethod.selector; 275 this.declaringClass = rawType == null ? originalMethod.declaringClass : rawType; 276 this.typeVariables = Binding.NO_TYPE_VARIABLES; 277 this.typeArguments = rawArguments; 278 this.originalMethod = originalMethod; 279 boolean ignoreRawTypeSubstitution = rawType == null || originalMethod.isStatic(); 280 this.parameters = Scope.substitute(this, ignoreRawTypeSubstitution 281 ? originalMethod.parameters : Scope.substitute(rawType, originalMethod.parameters)); 283 this.thrownExceptions = Scope.substitute(this, ignoreRawTypeSubstitution 284 ? originalMethod.thrownExceptions : Scope.substitute(rawType, originalMethod.thrownExceptions)); 286 this.returnType = Scope.substitute(this, ignoreRawTypeSubstitution 287 ? originalMethod.returnType : Scope.substitute(rawType, originalMethod.returnType)); 289 this.wasInferred = false; } 291 292 295 public ParameterizedGenericMethodBinding(MethodBinding originalMethod, TypeBinding[] typeArguments, LookupEnvironment environment) { 296 297 this.environment = environment; 298 this.modifiers = originalMethod.modifiers; 299 this.selector = originalMethod.selector; 300 this.declaringClass = originalMethod.declaringClass; 301 this.typeVariables = Binding.NO_TYPE_VARIABLES; 302 this.typeArguments = typeArguments; 303 this.isRaw = false; 304 this.tagBits = originalMethod.tagBits; 305 this.originalMethod = originalMethod; 306 this.parameters = Scope.substitute(this, originalMethod.parameters); 307 this.thrownExceptions = Scope.substitute(this, originalMethod.thrownExceptions); 308 this.returnType = Scope.substitute(this, originalMethod.returnType); 309 this.wasInferred = true; } 311 312 316 public char[] computeUniqueKey(boolean isLeaf) { 317 StringBuffer buffer = new StringBuffer (); 318 buffer.append(this.originalMethod.computeUniqueKey(false)); 319 buffer.append('%'); 320 buffer.append('<'); 321 if (!this.isRaw) { 322 int length = this.typeArguments.length; 323 for (int i = 0; i < length; i++) { 324 TypeBinding typeArgument = this.typeArguments[i]; 325 buffer.append(typeArgument.computeUniqueKey(false)); 326 } 327 } 328 buffer.append('>'); 329 int resultLength = buffer.length(); 330 char[] result = new char[resultLength]; 331 buffer.getChars(0, resultLength, result, 0); 332 return result; 333 334 } 335 336 339 public LookupEnvironment environment() { 340 return this.environment; 341 } 342 346 public boolean hasSubstitutedParameters() { 347 if (this.wasInferred) 349 return this.originalMethod.hasSubstitutedParameters(); 350 return super.hasSubstitutedParameters(); 351 } 352 356 public boolean hasSubstitutedReturnType() { 357 if (this.inferredReturnType) 358 return this.originalMethod.hasSubstitutedReturnType(); 359 return super.hasSubstitutedReturnType(); 360 } 361 365 private ParameterizedGenericMethodBinding inferFromExpectedType(Scope scope, InferenceContext inferenceContext) { 366 TypeVariableBinding[] originalVariables = this.originalMethod.typeVariables; int varLength = originalVariables.length; 368 369 computeSubstitutes: { 370 if (inferenceContext.expectedType != null) { 372 this.returnType.collectSubstitutes(scope, inferenceContext.expectedType, inferenceContext, TypeConstants.CONSTRAINT_SUPER); 373 if (inferenceContext.status == InferenceContext.FAILED) return null; } 375 for (int i = 0; i < varLength; i++) { 377 TypeVariableBinding originalVariable = originalVariables[i]; 378 TypeBinding argument = this.typeArguments[i]; 379 boolean argAlreadyInferred = argument != originalVariable; 380 if (originalVariable.firstBound == originalVariable.superclass) { 381 TypeBinding substitutedBound = Scope.substitute(this, originalVariable.superclass); 382 argument.collectSubstitutes(scope, substitutedBound, inferenceContext, TypeConstants.CONSTRAINT_SUPER); 383 if (inferenceContext.status == InferenceContext.FAILED) return null; if (argAlreadyInferred) { 388 substitutedBound.collectSubstitutes(scope, argument, inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); 389 if (inferenceContext.status == InferenceContext.FAILED) return null; } 391 } 392 for (int j = 0, max = originalVariable.superInterfaces.length; j < max; j++) { 393 TypeBinding substitutedBound = Scope.substitute(this, originalVariable.superInterfaces[j]); 394 argument.collectSubstitutes(scope, substitutedBound, inferenceContext, TypeConstants.CONSTRAINT_SUPER); 395 if (inferenceContext.status == InferenceContext.FAILED) return null; if (argAlreadyInferred) { 398 substitutedBound.collectSubstitutes(scope, argument, inferenceContext, TypeConstants.CONSTRAINT_EXTENDS); 399 if (inferenceContext.status == InferenceContext.FAILED) return null; } 401 } 402 } 403 if (inferenceContext.status == InferenceContext.RAW_SUBSTITUTION) { 404 this.isRaw = true; 406 this.isUnchecked = false; 407 for (int i = 0; i < varLength; i++) { 408 this.typeArguments[i] = originalVariables[i].upperBound(); 409 } 410 break computeSubstitutes; 411 } 412 if (!resolveSubstituteConstraints(scope, originalVariables, inferenceContext, true)) 413 return null; for (int i = 0; i < varLength; i++) { 416 TypeBinding substitute = inferenceContext.substitutes[i]; 417 if (substitute != null) { 418 this.typeArguments[i] = inferenceContext.substitutes[i]; 419 } else { 420 this.typeArguments[i] = originalVariables[i].upperBound(); 422 } 423 } 424 } 425 this.typeArguments = Scope.substitute(this, this.typeArguments); 428 TypeBinding oldReturnType = this.returnType; 430 this.returnType = Scope.substitute(this, this.returnType); 431 this.inferredReturnType = inferenceContext.hasExplicitExpectedType && this.returnType != oldReturnType; 432 this.parameters = Scope.substitute(this, this.parameters); 433 this.thrownExceptions = Scope.substitute(this, this.thrownExceptions); 434 return this; 435 } 436 437 440 public boolean isRawSubstitution() { 441 return this.isRaw; 442 } 443 444 447 public TypeBinding substitute(TypeVariableBinding originalVariable) { 448 TypeVariableBinding[] variables = this.originalMethod.typeVariables; 449 int length = variables.length; 450 if (originalVariable.rank < length && variables[originalVariable.rank] == originalVariable) { 452 return this.typeArguments[originalVariable.rank]; 453 } 454 if (!this.isStatic() && this.declaringClass instanceof Substitution) { 455 return ((Substitution)this.declaringClass).substitute(originalVariable); 456 } 457 return originalVariable; 458 } 459 462 public MethodBinding tiebreakMethod() { 463 if (this.tiebreakMethod == null) { 464 TypeVariableBinding[] originalVariables = originalMethod.typeVariables; 465 int length = originalVariables.length; 466 TypeBinding[] newArguments = new TypeBinding[length]; 467 for (int i = 0; i < length; i++) 468 newArguments[i] = environment.convertToRawType(originalVariables[i].upperBound()); 469 this.tiebreakMethod = this.environment.createParameterizedGenericMethod(this.originalMethod, newArguments); 470 } 471 return this.tiebreakMethod; 472 } 473 } 474 | Popular Tags |