Skip to content

Intersection types: explicit annotations and defaults on/for bounds #1735

@aosen-xiong

Description

@aosen-xiong

This is the finding when I do #1434.

For explicitly annotated intersection types, CF choose the primary annotation for the intersection from the first bound in the qualifier hierarchy, rather than computing a semantically meaningful qualifier such as the GLB of the bound annotations.

This makes diagnostics order-sensitive. In the Tainting Checker, @Untainted <: @Tainted, so it is surprising that:

(@Tainted Object & @Untainted I)

is treated as:

@Tainted Object & @Tainted I

and the explicit @Untainted annotation is reported as ignored.

Minimal Test Case

import org.checkerframework.checker.tainting.qual.Tainted;
import org.checkerframework.checker.tainting.qual.Untainted;

class TaintedIntersectionOrder {
    interface I {}

    void firstBoundTainted() {
        @Untainted Object x = (@Tainted Object & @Untainted I) null;
    }

    void firstBoundUntainted() {
        @Untainted Object x = (@Untainted Object & @Tainted I) null;
    }
}

Command

./checker/bin/javac \
  -processor org.checkerframework.checker.tainting.TaintingChecker \
  TaintedIntersectionOrder.java

Actual Output

TaintedIntersectionOrder.java:9: error: [assignment.type.incompatible] incompatible types in assignment.
        @Untainted Object x = (@Tainted Object & @Untainted I) null;
                              ^
  found   : @Tainted Object & @Tainted I
  required: @Untainted Object
TaintedIntersectionOrder.java:9: warning: [explicit.annotation.ignored] The qualifier @Untainted is ignored in favor of @Tainted. Either delete @Untainted or change it to @Tainted.
        @Untainted Object x = (@Tainted Object & @Untainted I) null;
                                                 ^
TaintedIntersectionOrder.java:14: warning: [explicit.annotation.ignored] The qualifier @Tainted is ignored in favor of @Untainted. Either delete @Tainted or change it to @Untainted.
        @Untainted Object x = (@Untainted Object & @Tainted I) null;
                                                   ^
1 error
2 warnings

Expected / Question
Is this intended behavior? If the intersection combines annotations from multiple bounds in the same hierarchy, should the primary annotation be computed using the qualifier hierarchy instead of depending on the first bound?

For Tainting, it seems like @Untainted Object & @Tainted I and @Tainted Object & @Untainted I should not produce opposite “ignored annotation” choices solely due to bound order.

How should this behave for hierarchies like PICO or viewpoint test checker, for example, @Immutable Object & @Mutable SomeInterface? If the qualifiers' GLB is bottom, should the Checker Framework reject the intersection type as uninhabitable, or is there a use case where such an intersection should remain expressible with a warning?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions