On Thu, 28 Mar 2024 14:08:44 GMT, Jan Lahoda <jlah...@openjdk.org> wrote:

>> This is a patch for javac, that adds the Derived Record Creation 
>> expressions. The current draft specification for the feature is:
>> https://cr.openjdk.org/~gbierman/jep468/jep468-20240326/specs/derived-record-creation-jls.html
>> 
>> The current CSR is here:
>> https://bugs.openjdk.org/browse/JDK-8328637
>> 
>> The patch is mostly straightforward, with two notable changes:
>>  - there is a new `ElementKind.COMPONENT_LOCAL_VARIABLE`, as the 
>> specification introduces this term, and it seems consistent with 
>> `ElementKind.BINDING_VARIABLE` that was introduced some time ago.
>>  - there are a bit broader changes in `Flow`, to facilitate the introduction 
>> of variables without an explicit declaration for definite assignment and 
>> effectively final computation.
>
> Jan Lahoda has updated the pull request incrementally with one additional 
> commit since the last revision:
> 
>   Fixing tests.

src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java line 
1415:

> 1413:                                                      
> canonicalConstructorTypes,
> 1414:                                                      List.nil());
> 1415:         createNew.constructor = init;

Maybe instead of hardcoding the constructor that is canonical at compile time 
(in case new components get added), it might be better to go through some sort 
of `indy` callsite like (at least when not in the same compilation unit):

DynamicCallSiteDesc[java.lang.runtime.RecordSupport::derivedConstructor(modified
 component names...):(T extends Record, Class<?>... /* modified component types 
*/)T]


with the `derivedConstructor` bootstrap method:

public static MethodHandle derivedConstructor(MethodHandles.Lookup lookup, 
String unused, MethodType type, String... modifiedComponents) throws 
ReflectiveOperationException {
        requireNonNull(lookup);
        requireNonNull(type);
        // implicit null-check:
        List<String> modifiedComponentNames = List.of(modifiedComponents);

        Class<?> rtype = type.returnType();
        if (
                !rtype.isRecord()
                || type.parameterCount() != modifiedComponents.length + 1
                || type.parameterType(0) != rtype
        ) {
                throw new IllegalArgumentException("...");
        }

        Set<String> remainingComponentNames = new 
HashSet(modifiedComponentNames);
        if (remainingComponentNames.size() != modifiedComponentNames.size()) {
                throw new IllegalArgumentException("Duplicate component names 
in modifiedComponents");
        }

        RecordComponent[] recordComponents = rtype.getRecordComponents();

        var componentTypes = new Class<?>[recordComponents.length];
        var filters = new MethodHandle[recordComponents.length];
        var reorder = new int[recordComponents.length];

        for (int i = 0, j = 1; i < recordComponents.length; i++) {
                var component = recordComponents[i];
                componentTypes[i] = component.getType();

                var getter = lookup.findVirtual(rtype, component.getName(), 
MethodType.methodType(component.getType()));
                if (modifiedComponentNames.contains(component.getName())) {
                        remainingComponentNames.remove(component.getName());
                        filters[i] = null;
                        reorder[i] = j++;
                } else {
                        filters[i] = getter;
                        reorder[i] = 0;
                }
        }

        if (!remainingComponentNames.isEmpty()) {
                throw new IllegalArgumentException("Components " + 
remainingComponentNames + " are not present in the record " + rtype);
        }

        var canonicalConstructor = lookup.findConstructor(rtype, 
MethodType.methodType(rtype, componentTypes);
        var filteredConstructor = 
MethodHandles.filterArguments(canonicalConstructor, 0, filters);
        // implicitly verifies that type's parameter types match the actual 
component types
        var permutedConstructor = 
MethodHandles.permuteArguments(filterArguments, type, reorder);

        return permutedConstructor;
}

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

PR Review Comment: https://git.openjdk.org/jdk/pull/18509#discussion_r1547819538

Reply via email to