From 2970db3d95af844b69701ba0664718bee17f8e1c Mon Sep 17 00:00:00 2001 From: Suzanne Millstein Date: Wed, 12 Jan 2022 13:02:14 -0800 Subject: [PATCH 1/7] Use the upper bound of super bounded wildcards. --- .../tests/nullness/generics/Issue5006.java | 34 +++++++++++++++++++ .../nullness/generics/WildcardOverride.java | 1 + .../framework/type/AnnotatedTypeFactory.java | 1 + 3 files changed, 36 insertions(+) create mode 100644 checker/tests/nullness/generics/Issue5006.java diff --git a/checker/tests/nullness/generics/Issue5006.java b/checker/tests/nullness/generics/Issue5006.java new file mode 100644 index 00000000000..cf2e1f2b5db --- /dev/null +++ b/checker/tests/nullness/generics/Issue5006.java @@ -0,0 +1,34 @@ +import org.checkerframework.checker.nullness.qual.NonNull; + +public class Issue5006 { + + static class C { + T get() { + throw new RuntimeException(""); + } + } + + interface X { + C get(); + } + + interface Y extends X { + @Override + // :: error: (override.return) + C get(); + } + + interface Z extends Y { + @Override + C get(); + } + + interface Q { + C get(); + } + + interface R extends Q { + @Override + C<@NonNull Object> get(); + } +} diff --git a/checker/tests/nullness/generics/WildcardOverride.java b/checker/tests/nullness/generics/WildcardOverride.java index 243ecc4dcbf..08ba4e1659b 100644 --- a/checker/tests/nullness/generics/WildcardOverride.java +++ b/checker/tests/nullness/generics/WildcardOverride.java @@ -11,6 +11,7 @@ interface ToOverride { public class WildcardOverride implements ToOverride { @Override + // :: error: (override.param) public int transform(List function) { return 0; } diff --git a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java index 88ae30eb6c9..0ae3bb128dd 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -4826,6 +4826,7 @@ public AnnotatedTypeMirror applyCaptureConversion( // that case. replaceAnnotations( ((AnnotatedWildcardType) uncapturedTypeArg).getSuperBound(), capturedTypeArg); + capturedTypeArg.replaceAnnotations(uncapturedTypeArg.getEffectiveAnnotations()); } } else { // The type argument is not a wildcard. From 40fee5d5ba0a2f9243c76f45a6608ea9af7a950f Mon Sep 17 00:00:00 2001 From: Suzanne Millstein Date: Thu, 13 Jan 2022 09:56:49 -0800 Subject: [PATCH 2/7] Add error. --- .../tests/nullness/generics/Issue5006.java | 18 +----- .../nullness/generics/WildcardAnnos.java | 17 ++++-- .../nullness/generics/WildcardOverride.java | 1 - checker/tests/tainting/SameTypeBounds.java | 5 +- .../common/basetype/BaseTypeValidator.java | 58 ++++++++++++------- .../common/basetype/messages.properties | 1 + .../framework/type/AnnotatedTypeFactory.java | 4 +- 7 files changed, 56 insertions(+), 48 deletions(-) diff --git a/checker/tests/nullness/generics/Issue5006.java b/checker/tests/nullness/generics/Issue5006.java index cf2e1f2b5db..3a6b5f1c154 100644 --- a/checker/tests/nullness/generics/Issue5006.java +++ b/checker/tests/nullness/generics/Issue5006.java @@ -1,5 +1,3 @@ -import org.checkerframework.checker.nullness.qual.NonNull; - public class Issue5006 { static class C { @@ -14,21 +12,7 @@ interface X { interface Y extends X { @Override - // :: error: (override.return) - C get(); - } - - interface Z extends Y { - @Override - C get(); - } - - interface Q { + // :: error: (super.wildcard) C get(); } - - interface R extends Q { - @Override - C<@NonNull Object> get(); - } } diff --git a/checker/tests/nullness/generics/WildcardAnnos.java b/checker/tests/nullness/generics/WildcardAnnos.java index 7f35f298a3d..c6f9ac9be22 100644 --- a/checker/tests/nullness/generics/WildcardAnnos.java +++ b/checker/tests/nullness/generics/WildcardAnnos.java @@ -8,13 +8,18 @@ public class WildcardAnnos { // The implicit upper bound is Nullable, because the annotation // on the wildcard is propagated. Therefore this type is: - // @Nullable List l3 = null; - @Nullable List<@Nullable ? super @NonNull Object> l3 = null; + // @Nullable List l3 = null; + @Nullable List<@Nullable ? super @NonNull String> l3 = null; + + // The bounds need to have the same annotations because capture conversion, + // converts the type argument to just Object. + // :: error: (super.wildcard) + @Nullable List<@Nullable ? super @NonNull Object> l3b = null; // :: error: (bound) - @Nullable List<@NonNull ? super @Nullable Object> l4 = null; + @Nullable List<@NonNull ? super @Nullable String> l4 = null; - @Nullable List l5 = null; + @Nullable List l5 = null; @Nullable List inReturn() { return null; @@ -25,9 +30,9 @@ void asParam(List p) {} // :: error: (conflicting.annos) @Nullable List<@Nullable @NonNull ? extends @Nullable Object> l6 = null; // :: error: (conflicting.annos) - @Nullable List<@Nullable @NonNull ? super @NonNull Object> l7 = null; + @Nullable List<@Nullable @NonNull ? super @NonNull String> l7 = null; // :: error: (conflicting.annos) @Nullable List l8 = null; // :: error: (conflicting.annos) - @Nullable List l9 = null; + @Nullable List l9 = null; } diff --git a/checker/tests/nullness/generics/WildcardOverride.java b/checker/tests/nullness/generics/WildcardOverride.java index 08ba4e1659b..243ecc4dcbf 100644 --- a/checker/tests/nullness/generics/WildcardOverride.java +++ b/checker/tests/nullness/generics/WildcardOverride.java @@ -11,7 +11,6 @@ interface ToOverride { public class WildcardOverride implements ToOverride { @Override - // :: error: (override.param) public int transform(List function) { return 0; } diff --git a/checker/tests/tainting/SameTypeBounds.java b/checker/tests/tainting/SameTypeBounds.java index 40adb2a69b6..d98a1f18e8a 100644 --- a/checker/tests/tainting/SameTypeBounds.java +++ b/checker/tests/tainting/SameTypeBounds.java @@ -7,9 +7,9 @@ public class SameTypeBounds { static class MyGen {} void test1(MyGen p) { - // TODO: error: invalid type // The upper and lower bound must have the same annotation because the bounds are collasped // during capture conversion. + // :: error: (super.wildcard) MyGen o = p; // :: error: (assignment) p = o; @@ -35,8 +35,9 @@ static class MySubClass extends MyClass {} class Gen {} + // :: error: (super.wildcard) void test3(Gen p, Gen p2) { - // TODO: error: invalid type + // :: error: (super.wildcard) Gen o = p; o = p2; // :: error: (assignment) diff --git a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java index 1485a803afc..4555c6908fb 100644 --- a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java +++ b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java @@ -580,27 +580,45 @@ protected Void visitParameterizedType(AnnotatedDeclaredType type, ParameterizedT for (int i = 0; i < numTypeArgs; i++) { AnnotatedTypeMirror captureTypeArg = capturedType.getTypeArguments().get(i); - if (TypesUtils.isCapturedTypeVariable(captureTypeArg.getUnderlyingType()) - && type.getTypeArguments().get(i).getKind() == TypeKind.WILDCARD) { - AnnotatedTypeVariable capturedTypeVar = (AnnotatedTypeVariable) captureTypeArg; + if (type.getTypeArguments().get(i).getKind() == TypeKind.WILDCARD) { AnnotatedWildcardType wildcard = (AnnotatedWildcardType) type.getTypeArguments().get(i); - // Substitute the captured type variables with their wildcards. Without this, the - // isSubtype check crashes because wildcards aren't comparable with type variables. - AnnotatedTypeMirror catpureTypeVarUB = - atypeFactory - .getTypeVarSubstitutor() - .substituteWithoutCopyingTypeArguments( - typeVarToWildcard, capturedTypeVar.getUpperBound()); - if (!atypeFactory - .getTypeHierarchy() - .isSubtype(catpureTypeVarUB, wildcard.getExtendsBound())) { - checker.reportError( - tree.getTypeArguments().get(i), - "type.argument", - element.getTypeParameters().get(i), - element.getSimpleName(), - wildcard.getExtendsBound(), - capturedTypeVar.getUpperBound()); + if (TypesUtils.isCapturedTypeVariable(captureTypeArg.getUnderlyingType())) { + AnnotatedTypeVariable capturedTypeVar = (AnnotatedTypeVariable) captureTypeArg; + // Substitute the captured type variables with their wildcards. Without this, the + // isSubtype check crashes because wildcards aren't comparable with type variables. + AnnotatedTypeMirror catpureTypeVarUB = + atypeFactory + .getTypeVarSubstitutor() + .substituteWithoutCopyingTypeArguments( + typeVarToWildcard, capturedTypeVar.getUpperBound()); + if (!atypeFactory + .getTypeHierarchy() + .isSubtype(catpureTypeVarUB, wildcard.getExtendsBound())) { + checker.reportError( + tree.getTypeArguments().get(i), + "type.argument", + element.getTypeParameters().get(i), + element.getSimpleName(), + wildcard.getExtendsBound(), + capturedTypeVar.getUpperBound()); + } + } else if (AnnotatedTypes.isExplicitlySuperBounded(wildcard)) { + if (!(atypeFactory + .getQualifierHierarchy() + .isSubtype( + wildcard.getSuperBound().getEffectiveAnnotations(), + wildcard.getExtendsBound().getAnnotations()) + && atypeFactory + .getQualifierHierarchy() + .isSubtype( + wildcard.getExtendsBound().getAnnotations(), + wildcard.getSuperBound().getEffectiveAnnotations()))) { + checker.reportError( + tree.getTypeArguments().get(i), + "super.wildcard", + wildcard.getExtendsBound(), + wildcard.getSuperBound()); + } } } } diff --git a/framework/src/main/java/org/checkerframework/common/basetype/messages.properties b/framework/src/main/java/org/checkerframework/common/basetype/messages.properties index 38611cce681..3bd259328bb 100644 --- a/framework/src/main/java/org/checkerframework/common/basetype/messages.properties +++ b/framework/src/main/java/org/checkerframework/common/basetype/messages.properties @@ -15,6 +15,7 @@ annotation=incompatible types in annotation.%nfound : %s%nrequired: %s conditional=incompatible types in conditional expression.%nfound : %s%nrequired: %s switch.expression=incompatible types in switch expression.%nfound : %s%nrequired: %s type.argument=incompatible type argument for type parameter %s of %s.%nfound : %s%nrequired: %s +super.wildcard=bounds must have the same annotations.%nsuper bound: %s%nextend bound: %s argument=incompatible argument for parameter %s of %s.%nfound : %s%nrequired: %s varargs=incompatible types in varargs.%nfound : %s%nrequired: %s type.incompatible=incompatible types.%nfound : %s%nrequired: %s diff --git a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java index 0ae3bb128dd..c6f364f08b8 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -4826,14 +4826,14 @@ public AnnotatedTypeMirror applyCaptureConversion( // that case. replaceAnnotations( ((AnnotatedWildcardType) uncapturedTypeArg).getSuperBound(), capturedTypeArg); - capturedTypeArg.replaceAnnotations(uncapturedTypeArg.getEffectiveAnnotations()); } } else { // The type argument is not a wildcard. // typeVarTypeMirror is the type parameter for which uncapturedTypeArg is a type argument. typeVarToAnnotatedTypeArg.put(typeVarTypeMirror, uncapturedTypeArg); if (uncapturedTypeArg.getKind() == TypeKind.TYPEVAR) { - // If the type arg is a type variable also add it to the typeVarToAnnotatedTypeArg map, so + // If the type arg is a type variable also add it to the typeVarToAnnotatedTypeArg map, + // sox // that references to the type variable are substituted. AnnotatedTypeVariable typeVar = (AnnotatedTypeVariable) uncapturedTypeArg; typeVarToAnnotatedTypeArg.put(typeVar.getUnderlyingType(), typeVar); From 436d995af6133239fdd0c81ff064a240a0a6742d Mon Sep 17 00:00:00 2001 From: Suzanne Millstein Date: Thu, 13 Jan 2022 15:55:04 -0800 Subject: [PATCH 3/7] Fix tests. --- checker/tests/lock/GuardSatisfiedTest.java | 2 +- checker/tests/lock/LockExpressionIsFinal.java | 4 ++-- .../framework/type/AnnotatedTypeFactory.java | 3 +-- .../lowerbound/LowerBoundDefaulting.java | 21 ++++++++++--------- .../upperbound/UpperBoundDefaulting.java | 11 +++++----- 5 files changed, 21 insertions(+), 20 deletions(-) diff --git a/checker/tests/lock/GuardSatisfiedTest.java b/checker/tests/lock/GuardSatisfiedTest.java index 6a61a6ceea4..be45483c6f8 100644 --- a/checker/tests/lock/GuardSatisfiedTest.java +++ b/checker/tests/lock/GuardSatisfiedTest.java @@ -247,7 +247,7 @@ void testGuardSatisfiedOnWildCardExtendsBound( void testGuardSatisfiedOnWildCardSuperBound( // :: error: (guardsatisfied.location.disallowed) - MyParameterizedClass1 l) {} + MyParameterizedClass1 l) {} @GuardSatisfied(1) Object testGuardSatisfiedOnParameters( @GuardSatisfied GuardSatisfiedTest this, diff --git a/checker/tests/lock/LockExpressionIsFinal.java b/checker/tests/lock/LockExpressionIsFinal.java index 2087af34bc1..521ad88a6df 100644 --- a/checker/tests/lock/LockExpressionIsFinal.java +++ b/checker/tests/lock/LockExpressionIsFinal.java @@ -281,9 +281,9 @@ void testGuardedByExpressionIsFinal() { class MyParameterizedClass1 {} - MyParameterizedClass1 m1; + MyParameterizedClass1 m1; // :: error: (lock.expression.not.final) - MyParameterizedClass1 m2; + MyParameterizedClass1 m2; MyParameterizedClass1 m3; // :: error: (lock.expression.not.final) diff --git a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java index c6f364f08b8..bb3af38f89c 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -4833,8 +4833,7 @@ public AnnotatedTypeMirror applyCaptureConversion( typeVarToAnnotatedTypeArg.put(typeVarTypeMirror, uncapturedTypeArg); if (uncapturedTypeArg.getKind() == TypeKind.TYPEVAR) { // If the type arg is a type variable also add it to the typeVarToAnnotatedTypeArg map, - // sox - // that references to the type variable are substituted. + // so that references to the type variable are substituted. AnnotatedTypeVariable typeVar = (AnnotatedTypeVariable) uncapturedTypeArg; typeVarToAnnotatedTypeArg.put(typeVar.getUnderlyingType(), typeVar); } diff --git a/framework/tests/defaulting/lowerbound/LowerBoundDefaulting.java b/framework/tests/defaulting/lowerbound/LowerBoundDefaulting.java index 7eee470a313..08cec52b2fd 100644 --- a/framework/tests/defaulting/lowerbound/LowerBoundDefaulting.java +++ b/framework/tests/defaulting/lowerbound/LowerBoundDefaulting.java @@ -5,9 +5,9 @@ import org.checkerframework.framework.testchecker.defaulting.LowerBoundQual.*; -class MyArrayList {} +class MyArrayList {} -class MyExplicitArray {} +class MyExplicitArray {} public class LowerBoundDefaulting { @@ -31,12 +31,13 @@ public void implicitsWildcard(MyArrayList myArrayList) { // should fail because @LbImplicit is below @LbTop // :: error: (assignment) - @LbTop MyArrayList<@LbTop ? extends @LbTop String> iwLowerBoundIncompatible = myArrayList; + @LbTop MyArrayList<@LbTop ? extends @LbTop CharSequence> iwLowerBoundIncompatible = myArrayList; // :: error: (assignment) - @LbTop MyArrayList<@LbExplicit ? extends @LbTop String> iwLowerBoundCompatible = myArrayList; + @LbTop MyArrayList<@LbExplicit ? extends @LbTop CharSequence> iwLowerBoundCompatible = myArrayList; - @LbTop MyArrayList<@LbImplicit ? extends @LbTop String> iwLowerBoundStillCompatible = myArrayList; + @LbTop MyArrayList<@LbImplicit ? extends @LbTop CharSequence> iwLowerBoundStillCompatible = + myArrayList; } public void implicitExtendBoundedWildcard(MyArrayList iebList) { @@ -51,16 +52,16 @@ public void implicitExtendBoundedWildcard(MyArrayList iebList) @LbTop MyArrayList<@LbImplicit ? extends @LbTop String> iebLowerBoundCompatible = iebList; } - // :: error: (type.argument) + // MyArrayList<@LbTop MAL extends @LbTop CharSequence> + // elbLsit is MyArrayList<@LbTop ? super @LbExplicit String> + // capture is MyArrayList + // The super bound is the LUB of @LbTop and @LbExplicit. public void explicitLowerBoundedWildcard(MyArrayList elbList) { - // should fail because @LbExplicit is below @LbTop // :: error: (assignment) - @LbTop MyArrayList<@LbTop ? super @LbTop String> iebLowerBoundIncompatible = elbList; + @LbTop MyArrayList<@LbBottom ? super @LbBottom String> iebLowerBoundIncompatible = elbList; - // :: error: (type.argument) @LbTop MyArrayList<@LbTop ? super @LbExplicit String> iebLowerBoundStillIncompatible = elbList; - // :: error: (assignment) @LbTop MyArrayList<@LbTop ? super @LbImplicit String> iebLowerBoundCompatible = elbList; } } diff --git a/framework/tests/defaulting/upperbound/UpperBoundDefaulting.java b/framework/tests/defaulting/upperbound/UpperBoundDefaulting.java index f2af9f39f11..b67ff75e00b 100644 --- a/framework/tests/defaulting/upperbound/UpperBoundDefaulting.java +++ b/framework/tests/defaulting/upperbound/UpperBoundDefaulting.java @@ -6,10 +6,10 @@ import org.checkerframework.framework.testchecker.defaulting.UpperBoundQual.*; // Upper bound: @UbExplicit, Lower bound: @UbBottom. -class MyArrayList {} +class MyArrayList {} // Upper bound: @UbExplicit, Lower bound: @UbBottom. -class MyExplicitArray {} +class MyExplicitArray {} public class UpperBoundDefaulting { @@ -28,11 +28,11 @@ public void explicitUpperBoundTypeVar() { public void implicitsWildcard(MyArrayList myArrayList) { - @UbTop MyArrayList<@UbBottom ? extends @UbTop String> iwLowerBoundIncompatible = myArrayList; + @UbTop MyArrayList<@UbBottom ? extends @UbTop CharSequence> iwLowerBoundIncompatible = myArrayList; - @UbTop MyArrayList<@UbBottom ? extends @UbExplicit String> iwLowerBoundCompatible = myArrayList; + @UbTop MyArrayList<@UbBottom ? extends @UbExplicit CharSequence> iwLowerBoundCompatible = myArrayList; - @UbTop MyArrayList<@UbBottom ? extends @UbImplicit String> iwLowerBoundStillCompatible = + @UbTop MyArrayList<@UbBottom ? extends @UbImplicit CharSequence> iwLowerBoundStillCompatible = // :: error: (assignment) myArrayList; } @@ -51,6 +51,7 @@ public void explicitLowerBoundedWildcard(MyArrayList elbList) { @UbTop MyArrayList<@UbTop ? super @UbBottom String> iebLowerBoundIncompatible = elbList; // Upper bound: GLB(@UbExplicit, @UbImplicit), Lower bound: @UbBottom. + // :: error: (assignment) @UbTop MyArrayList<@UbImplicit ? super @UbBottom String> iebLowerBoundStillIncompatible = elbList; @UbTop MyArrayList<@UbExplicit ? super @UbBottom String> iebLowerBoundCompatible = elbList; From bfc6efac578754d68961d27ebaea676866ad5eb4 Mon Sep 17 00:00:00 2001 From: Suzanne Millstein Date: Fri, 14 Jan 2022 08:34:37 -0800 Subject: [PATCH 4/7] Revert change. --- .../checkerframework/framework/type/AnnotatedTypeFactory.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java index bb3af38f89c..88ae30eb6c9 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -4832,8 +4832,8 @@ public AnnotatedTypeMirror applyCaptureConversion( // typeVarTypeMirror is the type parameter for which uncapturedTypeArg is a type argument. typeVarToAnnotatedTypeArg.put(typeVarTypeMirror, uncapturedTypeArg); if (uncapturedTypeArg.getKind() == TypeKind.TYPEVAR) { - // If the type arg is a type variable also add it to the typeVarToAnnotatedTypeArg map, - // so that references to the type variable are substituted. + // If the type arg is a type variable also add it to the typeVarToAnnotatedTypeArg map, so + // that references to the type variable are substituted. AnnotatedTypeVariable typeVar = (AnnotatedTypeVariable) uncapturedTypeArg; typeVarToAnnotatedTypeArg.put(typeVar.getUnderlyingType(), typeVar); } From 63f18162c0bfb126514ba97afc65a720f7d663af Mon Sep 17 00:00:00 2001 From: Michael Ernst Date: Fri, 14 Jan 2022 08:54:08 -0800 Subject: [PATCH 5/7] Tweak message --- .../org/checkerframework/common/basetype/messages.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/main/java/org/checkerframework/common/basetype/messages.properties b/framework/src/main/java/org/checkerframework/common/basetype/messages.properties index 3bd259328bb..1f64ef7ce3d 100644 --- a/framework/src/main/java/org/checkerframework/common/basetype/messages.properties +++ b/framework/src/main/java/org/checkerframework/common/basetype/messages.properties @@ -15,7 +15,7 @@ annotation=incompatible types in annotation.%nfound : %s%nrequired: %s conditional=incompatible types in conditional expression.%nfound : %s%nrequired: %s switch.expression=incompatible types in switch expression.%nfound : %s%nrequired: %s type.argument=incompatible type argument for type parameter %s of %s.%nfound : %s%nrequired: %s -super.wildcard=bounds must have the same annotations.%nsuper bound: %s%nextend bound: %s +super.wildcard=bounds must have the same annotations.%nsuper bound : %s%nextends bound: %s argument=incompatible argument for parameter %s of %s.%nfound : %s%nrequired: %s varargs=incompatible types in varargs.%nfound : %s%nrequired: %s type.incompatible=incompatible types.%nfound : %s%nrequired: %s From 6cd34fe96e30ae518abfbd4231ac5eee4402aa4b Mon Sep 17 00:00:00 2001 From: Suzanne Millstein Date: Fri, 14 Jan 2022 10:10:48 -0800 Subject: [PATCH 6/7] Add comment. --- .../checkerframework/common/basetype/BaseTypeValidator.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java index 4555c6908fb..f4158d5aeb3 100644 --- a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java +++ b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java @@ -603,6 +603,12 @@ protected Void visitParameterizedType(AnnotatedDeclaredType type, ParameterizedT capturedTypeVar.getUpperBound()); } } else if (AnnotatedTypes.isExplicitlySuperBounded(wildcard)) { + // If the super bound of the wildcard is the same as the upper bound of the type + // parameter, then javac uses the bound rather than creating a fresh type variable. + // In this case, the Checker Framework uses the annotations on the super bound of the + // wildcard and ignores the annotations on the extends bound. So, issue a warning if + // the annotations on the extends bound are not the same as the annotations on the super + // bound. if (!(atypeFactory .getQualifierHierarchy() .isSubtype( From fe7c6913567ad0ffd8cc0443acf404600417a9cb Mon Sep 17 00:00:00 2001 From: Suzanne Millstein Date: Fri, 14 Jan 2022 14:35:42 -0800 Subject: [PATCH 7/7] Reference javac bug. --- .../org/checkerframework/common/basetype/BaseTypeValidator.java | 1 + .../checkerframework/framework/type/AnnotatedTypeFactory.java | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java index f4158d5aeb3..a9f36976bde 100644 --- a/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java +++ b/framework/src/main/java/org/checkerframework/common/basetype/BaseTypeValidator.java @@ -605,6 +605,7 @@ protected Void visitParameterizedType(AnnotatedDeclaredType type, ParameterizedT } else if (AnnotatedTypes.isExplicitlySuperBounded(wildcard)) { // If the super bound of the wildcard is the same as the upper bound of the type // parameter, then javac uses the bound rather than creating a fresh type variable. + // (See https://bugs.openjdk.java.net/browse/JDK-8054309.) // In this case, the Checker Framework uses the annotations on the super bound of the // wildcard and ignores the annotations on the extends bound. So, issue a warning if // the annotations on the extends bound are not the same as the annotations on the super diff --git a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java index 88ae30eb6c9..995003fc895 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -4823,7 +4823,7 @@ public AnnotatedTypeMirror applyCaptureConversion( // Javac used a declared type instead of a captured type variable. This seems to happen // when the bounds of the captured type variable would have been identical. This seems to // be a violation of the JLS, but javac does this, so the Checker Framework must handle - // that case. + // that case. (See https://bugs.openjdk.java.net/browse/JDK-8054309.) replaceAnnotations( ((AnnotatedWildcardType) uncapturedTypeArg).getSuperBound(), capturedTypeArg); }