diff --git a/checker/tests/mustcall/FunctionalInterfaces.java b/checker/tests/mustcall/FunctionalInterfaces.java new file mode 100644 index 00000000000..b556623ffa5 --- /dev/null +++ b/checker/tests/mustcall/FunctionalInterfaces.java @@ -0,0 +1,52 @@ +// Test that the correct type is assigned to instantiations of functional +// interfaces. +// https://github.com/typetools/checker-framework/issues/6823 + +import java.io.Closeable; +import org.checkerframework.checker.mustcall.qual.*; + +public abstract class FunctionalInterfaces { + + @FunctionalInterface + public interface Actor extends Closeable { + void act(); + + @Override + default void close() {} + } + + public static class ActorImpl implements Actor { + @Override + public void act() {} + } + + public abstract void run(@MustCall({}) Actor a); + + public static void method() {} + + public void normalConstruction() { + + // :: error: (assignment) + @MustCall({}) Actor a = new ActorImpl(); + } + + public void inlineClass() { + + class ActorImplInline implements Actor { + @Override + public void act() {} + } + + // :: error: (assignment) + @MustCall({}) Actor a = new ActorImplInline(); + } + + public void anonymousClass() { + + @MustCall({}) Actor a = + // :: error: (assignment) + new Actor() { + public void act() {} + }; + } +} 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 d0b39de5baf..f61a85ddd26 100644 --- a/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java +++ b/framework/src/main/java/org/checkerframework/framework/type/AnnotatedTypeFactory.java @@ -2826,7 +2826,13 @@ protected ParameterizedExecutableType constructorFromUse( p.addAll(1, superCon.getParameterTypes()); con.setParameterTypes(p); } - con.getReturnType().replaceAnnotations(superCon.getReturnType().getPrimaryAnnotations()); + Set lub = + qualHierarchy.leastUpperBoundsShallow( + type.getPrimaryAnnotations(), + type.getUnderlyingType(), + superCon.getReturnType().getPrimaryAnnotations(), + superCon.getReturnType().getUnderlyingType()); + con.getReturnType().replaceAnnotations(lub); } else { con = AnnotatedTypes.asMemberOf(types, this, type, ctor, con); } diff --git a/framework/tests/h1h2checker/AnonymousClasses.java b/framework/tests/h1h2checker/AnonymousClasses.java index 3caa087de6a..b373de987cb 100644 --- a/framework/tests/h1h2checker/AnonymousClasses.java +++ b/framework/tests/h1h2checker/AnonymousClasses.java @@ -4,7 +4,7 @@ public class AnonymousClasses { private <@H1S1 T extends @H1S1 Comparator> void testGenericAnonymous() { - // :: error: (type.argument) :: error: (constructor.invocation) + // :: error: (type.argument) :: warning: (cast.unsafe.constructor.invocation) new @H1S1 Gen() {}; // :: error: (type.argument) :: warning: (cast.unsafe.constructor.invocation) new @H1S1 GenInter() {};