Lines 344-399
Link Here
|
344 |
boolean checkInheritedReturnTypes(MethodBinding[] methods, int length) { |
344 |
boolean checkInheritedReturnTypes(MethodBinding[] methods, int length) { |
345 |
if (methods[0].declaringClass.isClass()) |
345 |
if (methods[0].declaringClass.isClass()) |
346 |
return super.checkInheritedReturnTypes(methods, length); |
346 |
return super.checkInheritedReturnTypes(methods, length); |
347 |
if (length <= 1) { |
|
|
348 |
return true; // no need to continue since only 1 inherited method is left |
349 |
} |
350 |
// get rid of overriden methods coming from interfaces - if any |
351 |
MethodBinding methodsToCheck[] = new MethodBinding[length]; // must not nullify methods slots in place |
352 |
int count = length; |
353 |
for (int i = 0; i < length; i++) { |
354 |
methodsToCheck[i] = methods[i]; |
355 |
} |
356 |
for (int i = 0; i < length; i++) { |
357 |
MethodBinding existingMethod; |
358 |
if ((existingMethod = methodsToCheck[i]) != null) { |
359 |
for (int j = 0; j < length; j++) { |
360 |
MethodBinding inheritedMethod; |
361 |
if (i != j && (inheritedMethod = methodsToCheck[j]) != null && |
362 |
existingMethod.declaringClass.implementsInterface(inheritedMethod.declaringClass, true)) { |
363 |
MethodBinding substitute = computeSubstituteMethod(inheritedMethod, existingMethod); |
364 |
if (substitute != null && |
365 |
doesSubstituteMethodOverride(existingMethod, substitute) && |
366 |
(existingMethod.returnType.isCompatibleWith(substitute.returnType) || |
367 |
isReturnTypeSubstituable(substitute, existingMethod))) { |
368 |
count--; |
369 |
methodsToCheck[j] = null; |
370 |
} |
371 |
} |
372 |
} |
373 |
} |
374 |
} |
375 |
if (count < length) { |
376 |
if (count == 1) { |
377 |
return true; // no need to continue since only 1 inherited method is left |
378 |
} |
379 |
for (int i = 0, j = 0; j < count; i++) { |
380 |
if (methodsToCheck[i] != null) { |
381 |
methodsToCheck[j++] = methodsToCheck[i]; |
382 |
} |
383 |
} |
384 |
methods = methodsToCheck; |
385 |
length = count; |
386 |
} // else keep methods unchanged for further checks |
387 |
|
347 |
|
388 |
// its possible in 1.5 that A is compatible with B & C, but B is not compatible with C |
348 |
// its possible in 1.5 that A is compatible with B & C, but B is not compatible with C |
389 |
for (int i = 0, l = length - 1; i < l;) { |
349 |
for (int i = 0, l = length - 1; i < l;) { |
390 |
MethodBinding method = methods[i++]; |
350 |
MethodBinding method = methods[i++]; |
391 |
for (int j = i; j <= l; j++) { |
351 |
nextMethod : for (int j = i; j <= l; j++) { |
392 |
if (!areReturnTypesCompatible(method, methods[j])) { |
352 |
if (!areReturnTypesCompatible(method, methods[j])) { |
393 |
if (this.type.isInterface()) |
353 |
if (this.type.isInterface()) |
394 |
for (int m = length; --m >= 0;) |
354 |
for (int m = length; --m >= 0;) |
395 |
if (methods[m].declaringClass.id == TypeIds.T_JavaLangObject) |
355 |
if (methods[m].declaringClass.id == TypeIds.T_JavaLangObject) |
396 |
return false; // do not complain since the super interface already got blamed |
356 |
continue nextMethod; // do not complain since the super interface already got blamed |
397 |
problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); |
357 |
problemReporter().inheritedMethodsHaveIncompatibleReturnTypes(this.type, methods, length); |
398 |
return false; |
358 |
return false; |
399 |
} |
359 |
} |
Lines 621-704
Link Here
|
621 |
// one has type variables and substituteTwo did not pass bounds check in computeSubstituteMethod() |
581 |
// one has type variables and substituteTwo did not pass bounds check in computeSubstituteMethod() |
622 |
return one.typeVariables != Binding.NO_TYPE_VARIABLES && !(substituteTwo instanceof ParameterizedGenericMethodBinding); |
582 |
return one.typeVariables != Binding.NO_TYPE_VARIABLES && !(substituteTwo instanceof ParameterizedGenericMethodBinding); |
623 |
} |
583 |
} |
624 |
// caveat: returns false if a method is implemented but needs that a bridge |
584 |
// caveat: returns false if a method is implemented that needs a bridge method |
625 |
// method be generated |
|
|
626 |
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) { |
585 |
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) { |
627 |
if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface()) |
586 |
if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface()) |
628 |
return false; // must hold onto ParameterizedMethod to see if a bridge method is necessary |
587 |
return false; // must hold onto ParameterizedMethod to see if a bridge method is necessary |
629 |
|
588 |
|
630 |
inheritedMethod = computeSubstituteMethod(inheritedMethod, existingMethod); |
589 |
inheritedMethod = computeSubstituteMethod(inheritedMethod, existingMethod); |
631 |
return inheritedMethod != null |
590 |
return inheritedMethod != null |
632 |
&& inheritedMethod.returnType == existingMethod.returnType |
591 |
&& inheritedMethod.returnType == existingMethod.returnType // keep around to produce bridge methods |
633 |
&& super.isInterfaceMethodImplemented(inheritedMethod, existingMethod, superType); |
592 |
&& super.isInterfaceMethodImplemented(inheritedMethod, existingMethod, superType); |
634 |
} |
593 |
} |
635 |
/** |
|
|
636 |
* Return true iff the return type of existingMethod is a valid replacement for |
637 |
* the one of substituteMethod in a method declaration, in the context specified |
638 |
* thereafter. It is expected that substituteMethod is the result of the |
639 |
* substitution of the type parameters of an inheritedMethod method according to |
640 |
* the type parameters of existingMethod and the inheritance relationship |
641 |
* between existingMethod's declaring type and inheritedMethod's declaring type, |
642 |
* where inheritedMethod is a method inherited by existingMethod's declaring |
643 |
* type which is override compatible with existingMethod, except maybe for |
644 |
* their respective return types. If those conditions are not met, the result is |
645 |
* unspecified. |
646 |
* @param substituteMethod a proper substitute of a method inherited by existingMethod |
647 |
* @param existingMethod the existing method under examination |
648 |
* @return true if the return type of existingMethod is a valid substitute for |
649 |
* the one of substituteMethod |
650 |
*/ |
651 |
boolean isReturnTypeSubstituable(MethodBinding substituteMethod, MethodBinding existingMethod) { |
652 |
class ReturnTypeSubstitution implements Substitution { |
653 |
TypeBinding replaced, replacer; |
654 |
ReturnTypeSubstitution(TypeBinding replaced, TypeBinding replacer) { |
655 |
this.replaced = replaced; |
656 |
this.replacer = replacer; |
657 |
} |
658 |
public LookupEnvironment environment() { |
659 |
return environment; |
660 |
} |
661 |
public boolean isRawSubstitution() { |
662 |
return false; |
663 |
} |
664 |
public TypeBinding substitute(TypeVariableBinding typeVariable) { |
665 |
return typeVariable == replaced ? replacer : typeVariable; |
666 |
} |
667 |
} |
668 |
if (substituteMethod.returnType instanceof TypeVariableBinding) { |
669 |
return ((TypeVariableBinding) substituteMethod.returnType). |
670 |
boundCheck( |
671 |
new ReturnTypeSubstitution(substituteMethod.returnType, existingMethod.returnType), |
672 |
existingMethod.returnType) == TypeConstants.OK; |
673 |
} else if (substituteMethod.returnType instanceof ParameterizedTypeBinding) { |
674 |
if (! (existingMethod.returnType instanceof ParameterizedTypeBinding)) { |
675 |
return false; |
676 |
} |
677 |
ParameterizedTypeBinding substituteReturnType = (ParameterizedTypeBinding) substituteMethod.returnType, |
678 |
existingReturnType = (ParameterizedTypeBinding) existingMethod.returnType; |
679 |
if (substituteReturnType.actualType() != existingReturnType.actualType()) |
680 |
return false; |
681 |
for (int i = 0; i < substituteReturnType.arguments.length; i++) { |
682 |
TypeBinding substituteArgumentType, existingArgumentType; |
683 |
if (! (existingArgumentType = existingReturnType.arguments[i]).isCompatibleWith( |
684 |
substituteArgumentType = substituteReturnType.arguments[i])) { |
685 |
if (substituteArgumentType instanceof TypeVariableBinding) { |
686 |
if (((TypeVariableBinding) substituteArgumentType). |
687 |
boundCheck( |
688 |
new ReturnTypeSubstitution(substituteArgumentType, existingArgumentType), |
689 |
// we do not address the most general pattern of multiple type variables, nor the recursive case either |
690 |
existingArgumentType) != TypeConstants.OK) { |
691 |
return false; |
692 |
} |
693 |
} else { |
694 |
return false; |
695 |
} |
696 |
} |
697 |
} |
698 |
return true; |
699 |
} |
700 |
return false; |
701 |
} |
702 |
SimpleSet findSuperinterfaceCollisions(ReferenceBinding superclass, ReferenceBinding[] superInterfaces) { |
594 |
SimpleSet findSuperinterfaceCollisions(ReferenceBinding superclass, ReferenceBinding[] superInterfaces) { |
703 |
ReferenceBinding[] interfacesToVisit = null; |
595 |
ReferenceBinding[] interfacesToVisit = null; |
704 |
int nextPosition = 0; |
596 |
int nextPosition = 0; |