Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Polymorphic qualifier substitution in member references #2931

Open
wmdietl opened this issue Nov 23, 2019 · 2 comments
Open

Polymorphic qualifier substitution in member references #2931

wmdietl opened this issue Nov 23, 2019 · 2 comments
Milestone

Comments

@wmdietl
Copy link
Member

wmdietl commented Nov 23, 2019

While working on #2876 I've noticed that polymorphic qualifier substitution does not seem to work for member references.

Take:

import java.util.function.Supplier;
import testlib.util.Encrypted;
import testlib.util.PolyEncrypted;

class PolyMemberRef {
  @SuppressWarnings("return.type.incompatible") // impl
  @PolyEncrypted String id(@PolyEncrypted PolyMemberRef this) { return this.toString(); }

  void giveUnq(Supplier<String> s) {}
  void giveEnc(Supplier<@Encrypted String> s) {}

  void foo(PolyMemberRef u, @Encrypted PolyMemberRef e) {
    giveUnq(u::id);
    giveEnc(e::id);
  }
}

Run something like: ./checker/bin-devel/javac -cp framework/build/classes/java/test -processor org.checkerframework.common.subtyping.SubtypingChecker -Aquals=testlib.util.Encrypted,testlib.util.PolyEncrypted,org.checkerframework.common.subtyping.qual.Unqualified PolyMemberRef.java

And you'll get an error:

PolyMemberRef.java:14: error: [methodref.return.invalid] Incompatible return type
    giveEnc(e::id);
            ^
  Method
    String id(PolyMemberRef this) in PolyMemberRef
  is not a valid method reference for
    @Encrypted String get(Supplier<@Encrypted String> this) in java.util.function.Supplier
  found   : String
  required: @Encrypted String
1 error

The receiver used in the member reference should be used to resolve the polymorphic qualifier.

@wmdietl wmdietl added this to the Medium milestone Nov 25, 2019
@smillst
Copy link
Member

smillst commented Apr 27, 2020

Here's another example:

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

public class PolyReceiver {

    @PolyTainted PolyReceiver polyReceiverReturn(@PolyTainted PolyReceiver this, Object o) {
        return this;
    }

    PolyReceiver noPoly(PolyReceiver this, Object o) {
        return this;
    }

   @PolyTainted Object polyParameterReturn(PolyReceiver this, @PolyTainted Object o) {
        return o;
    }

    interface SetterPolyReceiver {
        @PolyTainted Object consume(@PolyTainted SetterPolyReceiver this, Object p);
    }

    interface SetterTaintedReceiver {
        @PolyTainted Object consume(SetterTaintedReceiver this, @PolyTainted Object p);
    }


    void use(@Tainted PolyReceiver this) {
        // What should theses errors be?
        // :: error: (?)
        SetterPolyReceiver s1 = this::noPoly;
        // :: error: (?)
        SetterPolyReceiver s2 = this::polyReceiverReturn;
        // :: error: (?)
        SetterPolyReceiver s3 = this::polyParameterReturn;

        // The next three assignments issues the correct errors or no error.
        // :: error: (methodref.return.invalid)
        SetterTaintedReceiver s4 = this::noPoly;
        // :: error: (methodref.return.invalid)
        SetterTaintedReceiver s5 = this::polyReceiverReturn;
        // no error
        SetterTaintedReceiver s6 = this::polyParameterReturn;
    }

}

@lnsun
Copy link
Contributor

lnsun commented Apr 29, 2020

Here's another example:

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

public class PolyReceiver {

    @PolyTainted PolyReceiver polyReceiverReturn(@PolyTainted PolyReceiver this, Object o) {
        return this;
    }

    PolyReceiver noPoly(PolyReceiver this, Object o) {
        return this;
    }

   @PolyTainted Object polyParameterReturn(PolyReceiver this, @PolyTainted Object o) {
        return o;
    }

    interface SetterPolyReceiver {
        @PolyTainted Object consume(@PolyTainted SetterPolyReceiver this, Object p);
    }

    interface SetterTaintedReceiver {
        @PolyTainted Object consume(SetterTaintedReceiver this, @PolyTainted Object p);
    }


    void use(@Tainted PolyReceiver this) {
        // What should theses errors be?
        // :: error: (?)
        SetterPolyReceiver s1 = this::noPoly;
        // :: error: (?)
        SetterPolyReceiver s2 = this::polyReceiverReturn;
        // :: error: (?)
        SetterPolyReceiver s3 = this::polyParameterReturn;

        // The next three assignments issues the correct errors or no error.
        // :: error: (methodref.return.invalid)
        SetterTaintedReceiver s4 = this::noPoly;
        // :: error: (methodref.return.invalid)
        SetterTaintedReceiver s5 = this::polyReceiverReturn;
        // no error
        SetterTaintedReceiver s6 = this::polyParameterReturn;
    }

}

@smillst I think s2 and s5 have a little problem: if the assignment l-value (SetterPolyReceiver and SetterTaintedReceiver) method return type have any poly annotation, r-value (this::polyReceiverReturn) will not be poly resolved*, so the poly annotation on receiver remains. And this causes this::polyReceiverReturn to have a methodref.receiver.bound.invalid error bacause acutal receiver is @Tainted PolyReceiver, not compatible with the declared receiver @PolyTainted PolyReceiver this in polyReceiverReturn.

(I didn't found java.util.function.Supplier in stub files, so I assume the function in the interface only have default annotation)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants