From 4cc6ff1e88b9db432aa1c06b1b0f056f254fddb8 Mon Sep 17 00:00:00 2001 From: Werner Dietl Date: Fri, 17 Jul 2026 15:17:07 -0400 Subject: [PATCH] Test capture glb with a non-top type-parameter bound framework/tests/h1h2checker/WildcardBounds.java notes it only exercises wildcard capture against a top type-parameter bound ("We could add an OuterS1 to also test with a non-top upper bound."), for which the glb of the wildcard's extends bound and the parameter bound trivially equals the wildcard's bound. Add a nontopdefault test capturing Foo where Foo and the wildcard's extends bound (the @NTDMiddle type-use default, or an explicit qualifier) is strictly more precise than the @NTDTop parameter bound. This confirms the captured type variable's upper bound is the greatest lower bound (@NTDMiddle), not the parameter bound wholesale, and that the result varies with the wildcard's extends bound (an explicit @NTDTop bound is not assignable to @NTDMiddle). This is the CF-level reduction for cf-tasks/task-3; see cf-tasks/task-3-findings.md. Capture conversion computes the glb correctly in stock CF, so no framework change is warranted. Co-Authored-By: Claude Fable 5 --- .../CaptureGlbWildcardBound.java | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 framework/tests/nontopdefault/CaptureGlbWildcardBound.java diff --git a/framework/tests/nontopdefault/CaptureGlbWildcardBound.java b/framework/tests/nontopdefault/CaptureGlbWildcardBound.java new file mode 100644 index 000000000000..b6b8af95ef84 --- /dev/null +++ b/framework/tests/nontopdefault/CaptureGlbWildcardBound.java @@ -0,0 +1,41 @@ +import org.checkerframework.framework.testchecker.nontopdefault.qual.NTDMiddle; +import org.checkerframework.framework.testchecker.nontopdefault.qual.NTDTop; + +// Capture conversion of Foo where Foo must give the +// captured type variable an upper bound equal to the glb of the wildcard's extends bound and the +// type parameter's bound -- not the type parameter's bound wholesale. Here the wildcard's extends +// bound (the type-use default @NTDMiddle, or an explicit qualifier) is more precise than the +// @NTDTop parameter bound, so the glb is the wildcard's qualifier. +// +// This fills the coverage gap noted in framework/tests/h1h2checker/WildcardBounds.java ("We could +// add an OuterS1 to also test with a non-top upper bound."): the existing wildcard-capture tests +// use a top parameter bound, for which the glb trivially equals the wildcard's bound. See also +// cf-tasks/task-3-findings.md. +@SuppressWarnings("inconsistent.constructor.type") // not the point of this test +class CaptureGlbWildcardBound { + interface Bar {} + + interface Foo { + T get(); + } + + // Implicit wildcard extends bound: Bar defaults to the type-use default @NTDMiddle, which is + // below the @NTDTop parameter bound. glb(@NTDMiddle Bar, @NTDTop Object) == @NTDMiddle Bar, so + // x.get() is @NTDMiddle. + void implicitBound(Foo x) { + @NTDMiddle Object m = x.get(); + } + + // Explicit @NTDMiddle wildcard extends bound: same glb, @NTDMiddle. + void explicitMiddleBound(Foo x) { + @NTDMiddle Object m = x.get(); + } + + // Discriminating control: an explicit @NTDTop wildcard extends bound equals the parameter + // bound, so the glb is @NTDTop, which is not assignable to @NTDMiddle. This confirms the glb + // machinery actually varies with the wildcard's extends bound. + void explicitTopBound(Foo x) { + // :: error: (assignment.type.incompatible) + @NTDMiddle Object m = x.get(); + } +}