View | Details | Raw Unified | Return to bug 264881 | Differences between
and this patch

Collapse All | Expand All

(-)compiler/org/eclipse/jdt/internal/compiler/lookup/MethodVerifier15.java (-40 / +45 lines)
Lines 124-141 Link Here
124
124
125
		// so the parameters are equal and the return type is compatible b/w the currentMethod & the substituted inheritedMethod
125
		// so the parameters are equal and the return type is compatible b/w the currentMethod & the substituted inheritedMethod
126
		MethodBinding originalInherited = abstractMethod.original();
126
		MethodBinding originalInherited = abstractMethod.original();
127
		if (originalInherited.returnType != concreteMethod.returnType) {
127
		if (originalInherited.returnType != concreteMethod.returnType)
128
			if (abstractMethod.returnType.leafComponentType().isParameterizedTypeWithActualArguments()) {
128
			if (!isAcceptableReturnTypeOverride(concreteMethod, abstractMethod))
129
				if (concreteMethod.returnType.leafComponentType().isRawType())
129
				problemReporter().unsafeReturnTypeOverride(concreteMethod, originalInherited, this.type);
130
					problemReporter().unsafeReturnTypeOverride(concreteMethod, originalInherited, this.type);
130
131
			} else if (abstractMethod.hasSubstitutedReturnType() && originalInherited.returnType.leafComponentType().isTypeVariable()) {
132
				if (((TypeVariableBinding) originalInherited.returnType.leafComponentType()).declaringElement == originalInherited) { // see 81618 - type variable from inherited method
133
					TypeBinding currentReturnType = concreteMethod.returnType.leafComponentType();
134
					if (!currentReturnType.isTypeVariable() || ((TypeVariableBinding) currentReturnType).declaringElement != concreteMethod)
135
						problemReporter().unsafeReturnTypeOverride(concreteMethod, originalInherited, this.type);
136
				}
137
			}
138
		}
139
		// check whether bridge method is already defined above for interface methods
131
		// check whether bridge method is already defined above for interface methods
140
		if (originalInherited.declaringClass.isInterface()) {
132
		if (originalInherited.declaringClass.isInterface()) {
141
			if ((concreteMethod.declaringClass == this.type.superclass && this.type.superclass.isParameterizedType())
133
			if ((concreteMethod.declaringClass == this.type.superclass && this.type.superclass.isParameterizedType())
Lines 150-169 Link Here
150
142
151
	// so the parameters are equal and the return type is compatible b/w the currentMethod & the substituted inheritedMethod
143
	// so the parameters are equal and the return type is compatible b/w the currentMethod & the substituted inheritedMethod
152
	MethodBinding originalInherited = inheritedMethod.original();
144
	MethodBinding originalInherited = inheritedMethod.original();
153
	if (originalInherited.returnType != currentMethod.returnType) {
145
	if (originalInherited.returnType != currentMethod.returnType)
154
//		if (currentMethod.returnType.needsUncheckedConversion(inheritedMethod.returnType)) {
146
		if (!isAcceptableReturnTypeOverride(currentMethod, inheritedMethod))
155
//			problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
156
		if (inheritedMethod.returnType.leafComponentType().isParameterizedTypeWithActualArguments() 
157
				&& currentMethod.returnType.leafComponentType().isRawType()) {
158
			problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
147
			problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
159
		} else if (inheritedMethod.hasSubstitutedReturnType() && originalInherited.returnType.leafComponentType().isTypeVariable()) {
160
			if (((TypeVariableBinding) originalInherited.returnType.leafComponentType()).declaringElement == originalInherited) { // see 81618 - type variable from inherited method
161
				TypeBinding currentReturnType = currentMethod.returnType.leafComponentType();
162
				if (!currentReturnType.isTypeVariable() || ((TypeVariableBinding) currentReturnType).declaringElement != currentMethod)
163
					problemReporter(currentMethod).unsafeReturnTypeOverride(currentMethod, originalInherited, this.type);
164
			}
165
		}
166
	}
167
148
168
	if (this.type.addSyntheticBridgeMethod(originalInherited, currentMethod.original()) != null) {
149
	if (this.type.addSyntheticBridgeMethod(originalInherited, currentMethod.original()) != null) {
169
		for (int i = 0, l = allInheritedMethods == null ? 0 : allInheritedMethods.length; i < l; i++) {
150
		for (int i = 0, l = allInheritedMethods == null ? 0 : allInheritedMethods.length; i < l; i++) {
Lines 586-606 Link Here
586
public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) {
567
public boolean doesMethodOverride(MethodBinding method, MethodBinding inheritedMethod) {
587
	return couldMethodOverride(method, inheritedMethod) && areMethodsCompatible(method, inheritedMethod);
568
	return couldMethodOverride(method, inheritedMethod) && areMethodsCompatible(method, inheritedMethod);
588
}
569
}
589
boolean hasGenericParameter(MethodBinding method) {
590
	if (method.genericSignature() == null) return false;
591
592
	// may be only the return type that is generic, need to check parameters
593
	TypeBinding[] params = method.parameters;
594
	for (int i = 0, l = params.length; i < l; i++) {
595
		TypeBinding param = params[i].leafComponentType();
596
		if (param instanceof ReferenceBinding) {
597
			int modifiers = ((ReferenceBinding) param).modifiers;
598
			if ((modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)
599
				return true;
600
		}
601
	}
602
	return false;
603
}
604
boolean doTypeVariablesClash(MethodBinding one, MethodBinding substituteTwo) {
570
boolean doTypeVariablesClash(MethodBinding one, MethodBinding substituteTwo) {
605
	// one has type variables and substituteTwo did not pass bounds check in computeSubstituteMethod()
571
	// one has type variables and substituteTwo did not pass bounds check in computeSubstituteMethod()
606
	return one.typeVariables != Binding.NO_TYPE_VARIABLES && !(substituteTwo instanceof ParameterizedGenericMethodBinding);
572
	return one.typeVariables != Binding.NO_TYPE_VARIABLES && !(substituteTwo instanceof ParameterizedGenericMethodBinding);
Lines 674-679 Link Here
674
	}
640
	}
675
	return copy;
641
	return copy;
676
}
642
}
643
boolean hasGenericParameter(MethodBinding method) {
644
	if (method.genericSignature() == null) return false;
645
646
	// may be only the return type that is generic, need to check parameters
647
	TypeBinding[] params = method.parameters;
648
	for (int i = 0, l = params.length; i < l; i++) {
649
		TypeBinding param = params[i].leafComponentType();
650
		if (param instanceof ReferenceBinding) {
651
			int modifiers = ((ReferenceBinding) param).modifiers;
652
			if ((modifiers & ExtraCompilerModifiers.AccGenericSignature) != 0)
653
				return true;
654
		}
655
	}
656
	return false;
657
}
658
boolean isAcceptableReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod) {
659
	// called when currentMethod's return type is compatible with inheritedMethod's return type
660
661
	if (inheritedMethod.declaringClass.isRawType())
662
		return true; // since the inheritedMethod comes from a raw type, the return type is always acceptable
663
664
	TypeBinding currentReturnType = currentMethod.returnType.leafComponentType();
665
	switch (currentReturnType.kind()) {
666
	   	case Binding.RAW_TYPE :
667
			return !inheritedMethod.returnType.leafComponentType().isParameterizedTypeWithActualArguments();
668
	   	case Binding.TYPE_PARAMETER :
669
	   		if (currentReturnType == inheritedMethod.returnType.leafComponentType())
670
	   			return true;
671
	   		//$FALL-THROUGH$
672
		default :
673
			MethodBinding originalInherited = inheritedMethod.original();
674
			TypeBinding originalInheritedReturnType = originalInherited.returnType.leafComponentType();
675
			if (originalInheritedReturnType.isTypeVariable() && ((TypeVariableBinding) originalInheritedReturnType).declaringElement == originalInherited)
676
				return false;
677
			return true;
678
	}
679
}
677
// caveat: returns false if a method is implemented that needs a bridge method
680
// caveat: returns false if a method is implemented that needs a bridge method
678
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
681
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
679
	if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface())
682
	if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface())
Lines 731-736 Link Here
731
	return method.typeVariables == Binding.NO_TYPE_VARIABLES;
734
	return method.typeVariables == Binding.NO_TYPE_VARIABLES;
732
}
735
}
733
boolean isUnsafeReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod) {
736
boolean isUnsafeReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod) {
737
	// called when currentMethod's return type is NOT compatible with inheritedMethod's return type
738
734
	// JLS 3 §8.4.5: more are accepted, with an unchecked conversion
739
	// JLS 3 §8.4.5: more are accepted, with an unchecked conversion
735
	if (currentMethod.returnType == inheritedMethod.returnType.erasure()) {
740
	if (currentMethod.returnType == inheritedMethod.returnType.erasure()) {
736
		TypeBinding[] currentParams = currentMethod.parameters;
741
		TypeBinding[] currentParams = currentMethod.parameters;
(-)src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java (+60 lines)
Lines 9383-9386 Link Here
9383
		"----------\n"
9383
		"----------\n"
9384
	);
9384
	);
9385
}
9385
}
9386
//https://bugs.eclipse.org/bugs/show_bug.cgi?id=264881
9387
public void test184() {
9388
	this.runNegativeTest(
9389
		new String[] {
9390
			"X.java",
9391
			"class A<U extends Number> {\n" +
9392
			"	<T extends Number> U a() { return null; }\n" +
9393
			"	<T> T x() { return null; }\n" +
9394
			"	<T extends Number> T y() { return null; }\n" +
9395
			"	<T extends Integer> T z() { return null; }\n" +
9396
			"}\n" +
9397
			"class B extends A<Double> {\n" +
9398
			"	@Override Double a() { return 1.0; }\n" +
9399
			"	@Override Integer x() { return 1; }\n" +
9400
			"	@Override Integer y() { return 1; }\n" +
9401
			"	@Override Integer z() { return 1; }\n" +
9402
			"}\n" +
9403
			"class C extends A {\n" +
9404
			"	@Override Double a() { return 1.0; }\n" +
9405
			"	@Override Integer x() { return 1; }\n" +
9406
			"	@Override Integer y() { return 1; }\n" +
9407
			"	@Override Integer z() { return 1; }\n" +
9408
			"}\n" +
9409
			"class M {\n" +
9410
			"	<T extends M> Object m(Class<T> c) { return null; }\n" +
9411
			"	<T extends M> Object n(Class<T> c) { return null; }\n" +
9412
			"}\n" +
9413
			"class N<V> extends M {\n" +
9414
			"	@Override <T extends M> T m(Class<T> c) { return null; }\n" +
9415
			"	@Override <T extends M> V n(Class<T> c) { return null; }\n" +
9416
			"}"
9417
		},
9418
		"----------\n" + 
9419
		"1. WARNING in X.java (at line 5)\n" + 
9420
		"	<T extends Integer> T z() { return null; }\n" + 
9421
		"	           ^^^^^^^\n" + 
9422
		"The type parameter T should not be bounded by the final type Integer. Final types cannot be further extended\n" + 
9423
		"----------\n" + 
9424
		"2. WARNING in X.java (at line 9)\n" + 
9425
		"	@Override Integer x() { return 1; }\n" + 
9426
		"	          ^^^^^^^\n" + 
9427
		"Type safety: The return type Integer for x() from the type B needs unchecked conversion to conform to T from the type A<U>\n" + 
9428
		"----------\n" + 
9429
		"3. WARNING in X.java (at line 10)\n" + 
9430
		"	@Override Integer y() { return 1; }\n" + 
9431
		"	          ^^^^^^^\n" + 
9432
		"Type safety: The return type Integer for y() from the type B needs unchecked conversion to conform to T from the type A<U>\n" + 
9433
		"----------\n" + 
9434
		"4. WARNING in X.java (at line 11)\n" + 
9435
		"	@Override Integer z() { return 1; }\n" + 
9436
		"	          ^^^^^^^\n" + 
9437
		"Type safety: The return type Integer for z() from the type B needs unchecked conversion to conform to T from the type A<U>\n" + 
9438
		"----------\n" + 
9439
		"5. WARNING in X.java (at line 13)\n" + 
9440
		"	class C extends A {\n" + 
9441
		"	                ^\n" + 
9442
		"A is a raw type. References to generic type A<U> should be parameterized\n" + 
9443
		"----------\n"
9444
	);
9445
}
9386
}
9446
}

Return to bug 264881