diff --git a/qual/src/main/java/com/virtuslab/qual/internal/package-info.java b/qual/src/main/java/com/virtuslab/qual/internal/package-info.java deleted file mode 100644 index f8b5414f97..0000000000 --- a/qual/src/main/java/com/virtuslab/qual/internal/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Module private. Do not use outside {@link com.virtuslab.qual}. - */ -package com.virtuslab.qual.internal; diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedLocal.java b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedLocal.java index 77663325be..8824333b85 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedLocal.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedLocal.java @@ -7,7 +7,7 @@ import org.checkerframework.framework.qual.SubtypeOf; -import com.virtuslab.qual.internal.SubtypingTop; +import com.virtuslab.qual.subtyping.internal.SubtypingTop; /** * Used to annotate a type of a {@code com.virtuslab.gitmachete.backend.api.IBranchReference} object diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedNonRoot.java b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedNonRoot.java index 42221c2c1e..19de3438e7 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedNonRoot.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedNonRoot.java @@ -7,7 +7,7 @@ import org.checkerframework.framework.qual.SubtypeOf; -import com.virtuslab.qual.internal.SubtypingTop; +import com.virtuslab.qual.subtyping.internal.SubtypingTop; /** * Used to annotate a type of a {@code com.virtuslab.gitmachete.backend.api.IManagedBranchSnapshot} object diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedRemote.java b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedRemote.java index a6cadc77cd..78c0899ad3 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedRemote.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedRemote.java @@ -7,7 +7,7 @@ import org.checkerframework.framework.qual.SubtypeOf; -import com.virtuslab.qual.internal.SubtypingTop; +import com.virtuslab.qual.subtyping.internal.SubtypingTop; /** * Used to annotate a type of a {@code com.virtuslab.gitmachete.backend.api.IBranchReference} object diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedRoot.java b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedRoot.java index 01a3e4d188..2b013c4ed5 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedRoot.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/backend/api/ConfirmedRoot.java @@ -7,7 +7,7 @@ import org.checkerframework.framework.qual.SubtypeOf; -import com.virtuslab.qual.internal.SubtypingTop; +import com.virtuslab.qual.subtyping.internal.SubtypingTop; /** * Used to annotate a type of a {@code com.virtuslab.gitmachete.backend.api.IManagedBranchSnapshot} object diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/elements/ConfirmedGraphEdge.java b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/elements/ConfirmedGraphEdge.java index 3f2e00594a..fad7129a7a 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/elements/ConfirmedGraphEdge.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/elements/ConfirmedGraphEdge.java @@ -7,7 +7,7 @@ import org.checkerframework.framework.qual.SubtypeOf; -import com.virtuslab.qual.internal.SubtypingTop; +import com.virtuslab.qual.subtyping.internal.SubtypingTop; /** * Used to annotate a type of a {@code com.virtuslab.gitmachete.frontend.graph.api.elements.IGraphElement} object diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/elements/ConfirmedGraphNode.java b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/elements/ConfirmedGraphNode.java index 9dcf2acdfd..b60216656b 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/elements/ConfirmedGraphNode.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/elements/ConfirmedGraphNode.java @@ -7,7 +7,7 @@ import org.checkerframework.framework.qual.SubtypeOf; -import com.virtuslab.qual.internal.SubtypingTop; +import com.virtuslab.qual.subtyping.internal.SubtypingTop; /** * Used to annotate a type of a {@code com.virtuslab.gitmachete.frontend.graph.api.elements.IGraphElement} object diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/items/ConfirmedBranchItem.java b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/items/ConfirmedBranchItem.java index 32b28d851a..e9d8d888ca 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/items/ConfirmedBranchItem.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/items/ConfirmedBranchItem.java @@ -7,7 +7,7 @@ import org.checkerframework.framework.qual.SubtypeOf; -import com.virtuslab.qual.internal.SubtypingTop; +import com.virtuslab.qual.subtyping.internal.SubtypingTop; /** * Used to annotate a type of a {@code com.virtuslab.gitmachete.frontend.graph.api.items.IBranchItem} object diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/items/ConfirmedCommitItem.java b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/items/ConfirmedCommitItem.java index 378494b81e..559ddd452b 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/items/ConfirmedCommitItem.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/gitmachete/frontend/graph/api/items/ConfirmedCommitItem.java @@ -7,7 +7,7 @@ import org.checkerframework.framework.qual.SubtypeOf; -import com.virtuslab.qual.internal.SubtypingTop; +import com.virtuslab.qual.subtyping.internal.SubtypingTop; /** * Used to annotate a type of a {@code com.virtuslab.gitmachete.frontend.graph.api.items.IBranchItem} object diff --git a/qual/src/main/java/com/virtuslab/qual/internal/SubtypingBottom.java b/qual/src/main/java/com/virtuslab/qual/subtyping/internal/SubtypingBottom.java similarity index 93% rename from qual/src/main/java/com/virtuslab/qual/internal/SubtypingBottom.java rename to qual/src/main/java/com/virtuslab/qual/subtyping/internal/SubtypingBottom.java index f771db801a..734e5bf6a8 100644 --- a/qual/src/main/java/com/virtuslab/qual/internal/SubtypingBottom.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/internal/SubtypingBottom.java @@ -1,4 +1,4 @@ -package com.virtuslab.qual.internal; +package com.virtuslab.qual.subtyping.internal; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -21,7 +21,7 @@ /** * There needs to be single subtyping hierarchy with single bottom and top annotation. * We could theoretically create a separate hierarchy with a dedicated top and bottom type - * for each pair of annotations from {@link com.virtuslab.qual.gitmachete}.* packages, + * for each pair of annotations from {@link com.virtuslab.qual.subtyping}.* packages, * but then Subtyping Checker * would raise an error about multiple top/bottom types. */ diff --git a/qual/src/main/java/com/virtuslab/qual/internal/SubtypingTop.java b/qual/src/main/java/com/virtuslab/qual/subtyping/internal/SubtypingTop.java similarity index 85% rename from qual/src/main/java/com/virtuslab/qual/internal/SubtypingTop.java rename to qual/src/main/java/com/virtuslab/qual/subtyping/internal/SubtypingTop.java index 94e5bbf1f2..e185dc3103 100644 --- a/qual/src/main/java/com/virtuslab/qual/internal/SubtypingTop.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/internal/SubtypingTop.java @@ -1,4 +1,4 @@ -package com.virtuslab.qual.internal; +package com.virtuslab.qual.subtyping.internal; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; @@ -11,7 +11,7 @@ /** * There needs to be single subtyping hierarchy with single bottom and top annotation. * We could theoretically create a separate hierarchy with a dedicated top and bottom type - * for each pair of annotations from {@link com.virtuslab.qual.gitmachete}.* packages, + * for each pair of annotations from {@link com.virtuslab.qual.subtyping}.* packages, * but then Subtyping Checker * would raise an error about multiple top/bottom types. */ diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/internal/package-info.java b/qual/src/main/java/com/virtuslab/qual/subtyping/internal/package-info.java new file mode 100644 index 0000000000..d53e2ea56b --- /dev/null +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/internal/package-info.java @@ -0,0 +1,4 @@ +/** + * Module private. Do not use outside {@link com.virtuslab.qual.subtyping}. + */ +package com.virtuslab.qual.subtyping.internal; diff --git a/qual/src/main/java/com/virtuslab/qual/subtyping/package-info.java b/qual/src/main/java/com/virtuslab/qual/subtyping/package-info.java index a0895f6b1e..bc94c38902 100644 --- a/qual/src/main/java/com/virtuslab/qual/subtyping/package-info.java +++ b/qual/src/main/java/com/virtuslab/qual/subtyping/package-info.java @@ -1,11 +1,53 @@ /** * Java 17 allows for pattern matching in switch expressions & statements * (https://www.baeldung.com/java-switch-pattern-matching). - * Still, a quick evaluation shows that Subtyping Checker is more convenient: - *
+ * With Subtyping Checker, the following is possible: + *
+ * if (branch.isRoot()) { + * ... branch.asRoot() ... + * } else { + * ... branch.asNonRoot() ... + * } + *+ *
+ * With {@code instanceof}, it would look like: + *
+ * if (branch instanceof IRootManagedBranchSnapshot rootBranch) { + * ... rootBranch ... + * } else { + * ... ((INonRootManagedBranchSnapshot) branch) ... + * } + *+ * or alternatively + *
+ * if (branch instanceof IRootManagedBranchSnapshot rootBranch) { + * ... rootBranch ... + * } else if (branch instanceof INonRootManagedBranchSnapshot nonRootBranch) { + * ... nonRootBranch .. + * } + *+ *
+ * Pattern matching in switch (Java 17 with {@code --enable-preview}) + * won't work for interfaces that are directly extended by an abstract class + * (and not only by sub-interfaces), as is the case with {@code IManagedBranchSnapshot}. + * The existence of {@code com.virtuslab.gitmachete.backend.impl.BaseManagedBranchSnapshot} would massively mess up the checks + * for sealed interface, which are needed for pattern matching to work properly. + * We can either sacrifice sealedness of {@code IManagedBranchSnapshot}: + *
+ * switch (branch) { + * case IRootManagedBranchSnapshot rootBranch -> ... + * case INonRootManagedBranchSnapshot nonRootBranch -> ... + * // WHOOPS compiler sees this match as non-exhaustive + * } + *+ * or include {@code BaseManagedBranchSnapshot} in {@code permits} clause for {@code IManagedBranchSnapshot}, + * which would also cause the compiler to report a non-exhaustive {@code switch} error. + *
+ * All things consider, as of Java 17, Subtyping Checker remains a cleaner choice for exhaustive matching on subtypes + * than whatever mechanism built into the language. */ package com.virtuslab.qual.subtyping; diff --git a/src/test/java/com/virtuslab/archunit/ClassStructureTestSuite.java b/src/test/java/com/virtuslab/archunit/ClassStructureTestSuite.java index a9377de703..6839637e9c 100644 --- a/src/test/java/com/virtuslab/archunit/ClassStructureTestSuite.java +++ b/src/test/java/com/virtuslab/archunit/ClassStructureTestSuite.java @@ -131,7 +131,7 @@ public void all_classes_should_be_referenced() { .and().resideOutsideOfPackages("com.virtuslab.gitmachete.frontend.defs") .and().doNotBelongToAnyOf(classesReferencedFromPluginXmlAttributes) // SubtypingBottom is processed by CheckerFramework based on its annotations - .and().doNotHaveFullyQualifiedName(com.virtuslab.qual.internal.SubtypingBottom.class.getName()) + .and().doNotHaveFullyQualifiedName(com.virtuslab.qual.subtyping.internal.SubtypingBottom.class.getName()) .should(new BeReferencedFromOutsideItself()) .check(productionClasses); }