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 / +47 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
	MethodBinding originalInherited = inheritedMethod.original();
665
	TypeBinding originalInheritedReturnType = originalInherited.returnType.leafComponentType();
666
	if (originalInheritedReturnType.isParameterizedTypeWithActualArguments())
667
		return !currentMethod.returnType.leafComponentType().isRawType(); // raw types issue a warning if inherited is parameterized
668
669
	TypeBinding currentReturnType = currentMethod.returnType.leafComponentType();
670
	switch (currentReturnType.kind()) {
671
	   	case Binding.TYPE_PARAMETER :
672
	   		if (currentReturnType == inheritedMethod.returnType.leafComponentType())
673
	   			return true;
674
	   		//$FALL-THROUGH$
675
		default :
676
			if (originalInheritedReturnType.isTypeVariable())
677
				if (((TypeVariableBinding) originalInheritedReturnType).declaringElement == originalInherited)
678
					return false;
679
			return true;
680
	}
681
}
677
// caveat: returns false if a method is implemented that needs a bridge method
682
// caveat: returns false if a method is implemented that needs a bridge method
678
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
683
boolean isInterfaceMethodImplemented(MethodBinding inheritedMethod, MethodBinding existingMethod, ReferenceBinding superType) {
679
	if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface())
684
	if (inheritedMethod.original() != inheritedMethod && existingMethod.declaringClass.isInterface())
Lines 731-736 Link Here
731
	return method.typeVariables == Binding.NO_TYPE_VARIABLES;
736
	return method.typeVariables == Binding.NO_TYPE_VARIABLES;
732
}
737
}
733
boolean isUnsafeReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod) {
738
boolean isUnsafeReturnTypeOverride(MethodBinding currentMethod, MethodBinding inheritedMethod) {
739
	// called when currentMethod's return type is NOT compatible with inheritedMethod's return type
740
734
	// JLS 3 §8.4.5: more are accepted, with an unchecked conversion
741
	// JLS 3 §8.4.5: more are accepted, with an unchecked conversion
735
	if (currentMethod.returnType == inheritedMethod.returnType.erasure()) {
742
	if (currentMethod.returnType == inheritedMethod.returnType.erasure()) {
736
		TypeBinding[] currentParams = currentMethod.parameters;
743
		TypeBinding[] currentParams = currentMethod.parameters;
(-)src/org/eclipse/jdt/core/tests/compiler/regression/MethodVerifyTest.java (+78 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 A<Number>> T a() { return null; }\n" +
9393
			"	<T extends Number> U num() { return null; }\n" +
9394
			"	<T> T x() { return null; }\n" +
9395
			"	<T extends Number> T y() { return null; }\n" +
9396
			"	<T extends Integer> T z() { return null; }\n" +
9397
			"}\n" +
9398
			"class B extends A<Double> {\n" +
9399
			"	@Override A a() { return null; }\n" +
9400
			"	@Override Double num() { return 1.0; }\n" +
9401
			"	@Override Integer x() { return 1; }\n" +
9402
			"	@Override Integer y() { return 1; }\n" +
9403
			"	@Override Integer z() { return 1; }\n" +
9404
			"}\n" +
9405
			"class C extends A {\n" +
9406
			"	@Override A a() { return null; }\n" +
9407
			"	@Override Double num() { return 1.0; }\n" +
9408
			"	@Override Integer x() { return 1; }\n" +
9409
			"	@Override Integer y() { return 1; }\n" +
9410
			"	@Override Integer z() { return 1; }\n" +
9411
			"}\n" +
9412
			"class M {\n" +
9413
			"	<T extends M> Object m(Class<T> c) { return null; }\n" +
9414
			"	<T extends M> Object n(Class<T> c) { return null; }\n" +
9415
			"}\n" +
9416
			"class N<V> extends M {\n" +
9417
			"	@Override <T extends M> T m(Class<T> c) { return null; }\n" +
9418
			"	@Override <T extends M> V n(Class<T> c) { return null; }\n" +
9419
			"}"
9420
		},
9421
		"----------\n" + 
9422
		"1. WARNING in X.java (at line 6)\n" + 
9423
		"	<T extends Integer> T z() { return null; }\n" + 
9424
		"	           ^^^^^^^\n" + 
9425
		"The type parameter T should not be bounded by the final type Integer. Final types cannot be further extended\n" + 
9426
		"----------\n" + 
9427
		"2. WARNING in X.java (at line 9)\n" + 
9428
		"	@Override A a() { return null; }\n" + 
9429
		"	          ^\n" + 
9430
		"A is a raw type. References to generic type A<U> should be parameterized\n" + 
9431
		"----------\n" + 
9432
		"3. WARNING in X.java (at line 9)\n" + 
9433
		"	@Override A a() { return null; }\n" + 
9434
		"	          ^\n" + 
9435
		"Type safety: The return type A for a() from the type B needs unchecked conversion to conform to T from the type A<U>\n" + 
9436
		"----------\n" + 
9437
		"4. WARNING in X.java (at line 11)\n" + 
9438
		"	@Override Integer x() { return 1; }\n" + 
9439
		"	          ^^^^^^^\n" + 
9440
		"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" + 
9441
		"----------\n" + 
9442
		"5. WARNING in X.java (at line 12)\n" + 
9443
		"	@Override Integer y() { return 1; }\n" + 
9444
		"	          ^^^^^^^\n" + 
9445
		"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" + 
9446
		"----------\n" + 
9447
		"6. WARNING in X.java (at line 13)\n" + 
9448
		"	@Override Integer z() { return 1; }\n" + 
9449
		"	          ^^^^^^^\n" + 
9450
		"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" + 
9451
		"----------\n" + 
9452
		"7. WARNING in X.java (at line 15)\n" + 
9453
		"	class C extends A {\n" + 
9454
		"	                ^\n" + 
9455
		"A is a raw type. References to generic type A<U> should be parameterized\n" + 
9456
		"----------\n" + 
9457
		"8. WARNING in X.java (at line 16)\n" + 
9458
		"	@Override A a() { return null; }\n" + 
9459
		"	          ^\n" + 
9460
		"A is a raw type. References to generic type A<U> should be parameterized\n" + 
9461
		"----------\n"
9462
	);
9463
}
9386
}
9464
}

Return to bug 264881