[epilogue] Fix v3 scheduler incompatibility with epilogue (#8458)

Was caused by checking assignability like`Protobuf<Scheduler,
ProtoMessage>` instead of `Protobuf<Scheduler, ? extends
ProtoMessage<?>>`

This epilogue bug would have also applied to other protobuf-serializable
types
This commit is contained in:
Sam Carlberg
2025-12-07 01:38:10 -05:00
committed by GitHub
parent 59edbdd3cc
commit 44cf645632
4 changed files with 33 additions and 7 deletions

View File

@@ -66,8 +66,12 @@ wpilib_java_library(
wpilib_java_junit5_test(
name = "commandsv3-java-test",
srcs = glob(["src/test/java/**/*.java"]),
plugins = [
"//epilogue-processor:plugin",
],
deps = [
":commandsv3-java",
"//epilogue-runtime:epilogue-java",
"//hal:hal-java",
"//ntcore:ntcore-java",
"//wpiannotations",

View File

@@ -27,7 +27,9 @@ dependencies {
implementation project(':wpilibj')
api("us.hebi.quickbuf:quickbuf-runtime:1.4")
testAnnotationProcessor project(':javacPlugin')
testAnnotationProcessor project(':epilogue-processor')
testImplementation 'org.mockito:mockito-core:4.1.0'
testImplementation project(':epilogue-runtime')
}
sourceSets.main.java.srcDir "${projectDir}/src/generated/main/java"

View File

@@ -0,0 +1,16 @@
// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.
package org.wpilib.command3.epilogue;
import org.wpilib.command3.Scheduler;
import org.wpilib.epilogue.Logged;
// This class will fail to compile if m_scheduler is not considered loggable
// Note that this assumes epilogue is set up correctly.
@Logged
public class SchedulerIsLoggableWithEpilogue {
@Logged(name = "Scheduler (logged via protobuf)")
private final Scheduler m_scheduler = Scheduler.createIndependentScheduler();
}

View File

@@ -58,14 +58,20 @@ public class ProtobufHandler extends ElementHandler {
return false;
}
// eg `Protobuf<Rotation2d, ?>` instead of the raw `Protobuf` type. The message type doesn't
// really matter here; we can leave it as a wildcard.
// Build a type like `Protobuf<SerializableType, ? extends ProtoMessage<?>>` to match
// implementations such as `SchedulerProto implements Protobuf<Scheduler, ProtobufScheduler>`.
// Note: Using `ProtoMessage` raw as the upper bound causes assignability to fail; we must use
// `ProtoMessage<?>` as the bound, then wrap that with an extends wildcard.
var protoMessageElement = m_elementUtils.getTypeElement("us.hebi.quickbuf.ProtoMessage");
var protoMessageWildcard =
m_typeUtils.getDeclaredType(protoMessageElement, m_typeUtils.getWildcardType(null, null));
var boundedProtoMessageWildcard = m_typeUtils.getWildcardType(protoMessageWildcard, null);
var sharpProtobufType =
m_typeUtils.getDeclaredType(
m_protobufType,
typeElement.asType(), // the serializable type
m_typeUtils.getWildcardType(
m_elementUtils.getTypeElement("us.hebi.quickbuf.ProtoMessage").asType(), null));
boundedProtoMessageWildcard);
boolean hasProto =
typeElement.getEnclosedElements().stream()
@@ -78,9 +84,7 @@ public class ProtobufHandler extends ElementHandler {
field
.getModifiers()
.containsAll(Set.of(Modifier.PUBLIC, Modifier.STATIC, Modifier.FINAL));
var typeMatch =
m_typeUtils.isAssignable(
m_typeUtils.erasure(field.asType()), sharpProtobufType);
var typeMatch = m_typeUtils.isAssignable(field.asType(), sharpProtobufType);
return nameMatch && modifiersMatch && typeMatch;
});
return m_typeUtils.isAssignable(type, m_serializable) && hasProto;