On Wed, 3 Apr 2024 07:13:13 GMT, Jan Lahoda <jlah...@openjdk.org> wrote:
>> 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);... > > While this is very smart, I would prefer not to do that. JLS 13.4.27 talks > about binary compatibility for record, and warns that adding or removing > components may break record usages. So I don't think we need to provide too > much support for adding or removing record components. > > Overall, I believe the current code adheres to what the JLS draft says. If > the author of the record wants to add or remove components, they can make it > so that the existing compiled code still works (by adding constructor > overloads and keeping the accessors for removed component). It is better, > IMO, to keep the behavior predictable, and leave adjustments after record > component modifications up to the record author, than to introduce some magic. This was once again asked about on amber‑dev: - https://mail.openjdk.org/pipermail/amber-dev/2024-April/008748.html ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/18509#discussion_r1583084422