From 77c17411624f18ad70c3df7c46ebae17789c6493 Mon Sep 17 00:00:00 2001 From: Gegy Date: Fri, 19 Jan 2024 09:07:24 +0100 Subject: [PATCH 1/3] Fix: properly apply recursive fixers to root types If using the unfolded type instead of the recursive point, a fixer applying to that type will rewrite the entire type without a fold, causing it to only fix the top-level. --- src/main/java/com/mojang/datafixers/DataFixerUpper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/mojang/datafixers/DataFixerUpper.java b/src/main/java/com/mojang/datafixers/DataFixerUpper.java index 248e36a3..d0f417ef 100644 --- a/src/main/java/com/mojang/datafixers/DataFixerUpper.java +++ b/src/main/java/com/mojang/datafixers/DataFixerUpper.java @@ -88,7 +88,7 @@ public Schema getSchema(final int key) { } protected Type getType(final DSL.TypeReference type, final int version) { - return getSchema(DataFixUtils.makeKey(version)).getType(type); + return getSchema(DataFixUtils.makeKey(version)).getTypeRaw(type); } protected static int getLowestSchemaSameVersion(final Int2ObjectSortedMap schemas, final int versionKey) { From 070cfae511458680019f15b878d2072c302838b8 Mon Sep 17 00:00:00 2001 From: Gegy Date: Fri, 19 Jan 2024 10:02:49 +0100 Subject: [PATCH 2/3] Fix: resolve correct input type when applying writeFixAndRead recursively This type is used to encode the Typed structure to data, and matches the type that the fixer actually gets passed. Otherwise, we try to encode the sub-values with the old format, which fails. --- .../java/com/mojang/datafixers/DataFix.java | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/DataFix.java b/src/main/java/com/mojang/datafixers/DataFix.java index 36f51493..6c0aa26d 100644 --- a/src/main/java/com/mojang/datafixers/DataFix.java +++ b/src/main/java/com/mojang/datafixers/DataFix.java @@ -14,6 +14,7 @@ import java.util.BitSet; import java.util.Objects; import java.util.Optional; +import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; public abstract class DataFix { @@ -42,18 +43,24 @@ protected TypeRewriteRule writeAndRead(final String name, final Type type, fi return writeFixAndRead(name, type, newType, Function.identity()); } + @SuppressWarnings("unchecked") protected TypeRewriteRule writeFixAndRead(final String name, final Type type, final Type newType, final Function, Dynamic> fix) { - return fixTypeEverywhere(name, type, newType, ops -> input -> { - final Optional> written = type.writeDynamic(ops, input).resultOrPartial(LOGGER::error); - if (!written.isPresent()) { + final AtomicReference> patchedType = new AtomicReference<>(); + final RewriteResult view = unchecked(name, type, newType, ops -> input -> { + final Optional> written = patchedType.getPlain().writeDynamic(ops, input).resultOrPartial(LOGGER::error); + if (written.isEmpty()) { throw new RuntimeException("Could not write the object in " + name); } final Optional, ?>> read = newType.readTyped(fix.apply(written.get())).resultOrPartial(LOGGER::error); - if (!read.isPresent()) { + if (read.isEmpty()) { throw new RuntimeException("Could not read the new object in " + name); } return read.get().getFirst().getValue(); - }); + }, new BitSet()); + final TypeRewriteRule rule = fixTypeEverywhere(type, view); + // Replace the input type within itself recursively, as this is what is actually passed to the fixer + patchedType.setPlain((Type) type.all(rule, true, false).view().newType()); + return rule; } protected TypeRewriteRule fixTypeEverywhere(final String name, final Type type, final Type newType, final Function, Function> function) { @@ -61,7 +68,7 @@ protected TypeRewriteRule fixTypeEverywhere(final String name, final Type } protected TypeRewriteRule fixTypeEverywhere(final String name, final Type type, final Type newType, final Function, Function> function, final BitSet bitSet) { - return fixTypeEverywhere(type, RewriteResult.create(View.create(name, type, newType, new NamedFunctionWrapper<>(name, function)), bitSet)); + return fixTypeEverywhere(type, unchecked(name, type, newType, function, bitSet)); } protected TypeRewriteRule fixTypeEverywhereTyped(final String name, final Type type, final Function, Typed> function) { @@ -80,6 +87,10 @@ protected TypeRewriteRule fixTypeEverywhereTyped(final String name, final return fixTypeEverywhere(type, checked(name, type, newType, function, bitSet)); } + private static RewriteResult unchecked(final String name, final Type type, final Type newType, final Function, Function> function, final BitSet bitSet) { + return RewriteResult.create(View.create(name, type, newType, new NamedFunctionWrapper<>(name, function)), bitSet); + } + @SuppressWarnings("unchecked") public static RewriteResult checked(final String name, final Type type, final Type newType, final Function, Typed> function, final BitSet bitSet) { return RewriteResult.create(View.create(name, type, newType, new NamedFunctionWrapper<>(name, ops -> a -> { From 4afa75e0a92cc648045ba825fdd2f5db619f186f Mon Sep 17 00:00:00 2001 From: Gegy Date: Tue, 23 Jan 2024 09:01:32 +0100 Subject: [PATCH 3/3] Fix: apply all rules from subversions of target version --- .../com/mojang/datafixers/DataFixerUpper.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/mojang/datafixers/DataFixerUpper.java b/src/main/java/com/mojang/datafixers/DataFixerUpper.java index d0f417ef..a4464616 100644 --- a/src/main/java/com/mojang/datafixers/DataFixerUpper.java +++ b/src/main/java/com/mojang/datafixers/DataFixerUpper.java @@ -107,20 +107,20 @@ private int getLowestFixSameVersion(final int versionKey) { return fixerVersions.subSet(0, versionKey + 1).lastInt(); } - protected TypeRewriteRule getRule(final int version, final int dataVersion) { - if (version >= dataVersion) { + protected TypeRewriteRule getRule(final int version, final int newVersion) { + if (version >= newVersion) { return TypeRewriteRule.nop(); } - final int expandedVersion = getLowestFixSameVersion(DataFixUtils.makeKey(version)); - final int expandedDataVersion = DataFixUtils.makeKey(dataVersion); - - final long key = (long) expandedVersion << 32 | expandedDataVersion; + final long key = (long) version << 32 | newVersion; return rules.computeIfAbsent(key, k -> { + final int expandedVersion = getLowestFixSameVersion(DataFixUtils.makeKey(version)); + final List rules = Lists.newArrayList(); for (final DataFix fix : globalList) { - final int fixVersion = fix.getVersionKey(); - if (fixVersion > expandedVersion && fixVersion <= expandedDataVersion) { + final int expandedFixVersion = fix.getVersionKey(); + final int fixVersion = DataFixUtils.getVersion(expandedFixVersion); + if (expandedFixVersion > expandedVersion && fixVersion <= newVersion) { final TypeRewriteRule fixRule = fix.getRule(); if (fixRule == TypeRewriteRule.nop()) { continue;