[code-reflection] RFR: Drop Quotable type [v3]

Paul Sandoz psandoz at openjdk.org
Wed Nov 19 18:26:16 UTC 2025


On Wed, 19 Nov 2025 14:26:05 GMT, Maurizio Cimadamore <mcimadamore at openjdk.org> wrote:

>> The `Quotable` type is a marker interface that is used to mark lambda expressions and method reference for which javac should produce a code model (we call them quotable lambdas), as in:
>> 
>> 
>> Runnable r = (Runnable & Quotable)() ->  {}
>> 
>> 
>> Since the lambda metafactory, nor `Op::opQuotable` only rely on this type in a superficial way, this PR simplifies the programming model by removing `Quotable` and use the `@CodeReflection` annotation (now turned into a type annotation) to mark quotable lambdas, as in:
>> 
>> 
>> Runnable r = (@CodeReflection Runnable)() ->  {}
>> 
>> 
>> Supporting this is relatively straightforward. The most complex part is, perhaps, to make sure that (a) the type annotation we care about is visible in the AST (javac is very lazy when it comes to fill in information on type annotations) and (b) make sure we don't end up using type annotations that appear in positions other than a cast. The latter point is important; if we have this:
>> 
>> 
>> void m(@CodeReflection Runnable r)  { ... }
>> m(() -> { .. });
>> 
>> 
>> we don't want the lambda to magically become quotable simply because the target method parameter has been annotated.
>> 
>> There's also other cases like:
>> 
>> 
>> @CodeReflection
>> Runnable m()  {
>>    return () -> { .. };
>> }
>> 
>> 
>> If `@CodeReflection` is a type annotation, the above lambda has a target `@CodeReflection Runnable` and is also treated as a quotable lambda. What we want here instead is for `@CodeReflection` to just act as a regular declaration annotation on the method.
>> 
>> To address these issues, I've augmented both `ReflectMethods` and its associated `BodyScanner` to keep track of the prviously visited node. This is done by having both classes extend a new simple scanner `TreeScannerPrev`, which "remembers" the node visited before the current one.
>> 
>> Thanks to this, when we see a lambda we can see if the previous node was a cast, and if such a cast contained any type-annotated type. If so, we will treat the lambda as a quotable lambda.
>> 
>> This implementation tactic guarantees that type annotations will only be consulted when needed.
>
> Maurizio Cimadamore has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Remove more dead code
>   Fix all samples
>   Fix HAT code

I am balking on following up and requiring use-site and declaration-site alignment:


@FunctionalInterface
@Reflect
ReflectableRunnable extends Runnable {}

void m(ReflectableRunnable r) {
}

// Fail, use site and declaration site are not aligned
m(() -> {}) 

// Pass
m((@Reflect ReflectableRunnable) () -> {}) 


I worry the current verbosity is so unpalatable it will reduce folks willingness to experiment. We will somehow need to get there eventually with some new concise language feature(s).

-------------

PR Comment: https://git.openjdk.org/babylon/pull/685#issuecomment-3554077866


More information about the babylon-dev mailing list