Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve nullability annotations and generic variance #576

Merged
merged 5 commits into from
Jun 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 47 additions & 47 deletions api/src/main/java/net/jqwik/api/Arbitraries.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@ public static abstract class ArbitrariesFacade {
implementation = FacadeLoader.load(ArbitrariesFacade.class);
}

public abstract <T> Arbitrary<T> oneOf(Collection<Arbitrary<? extends T>> all);
public abstract <T extends @Nullable Object> Arbitrary<T> oneOf(Collection<? extends Arbitrary<? extends T>> all);

public abstract <M> ActionSequenceArbitrary<M> sequences(Arbitrary<? extends Action<M>> actionArbitrary);
public abstract <M extends @Nullable Object> ActionSequenceArbitrary<M> sequences(Arbitrary<? extends Action<M>> actionArbitrary);

public abstract <T> Arbitrary<T> frequencyOf(List<Tuple2<Integer, Arbitrary<T>>> frequencies);
public abstract <T extends @Nullable Object> Arbitrary<T> frequencyOf(List<? extends Tuple2<Integer, ? extends Arbitrary<T>>> frequencies);

public abstract <@Nullable T> Arbitrary<T> just(@Nullable T value);
public abstract <T extends @Nullable Object> Arbitrary<T> just(T value);

public abstract IntegerArbitrary integers();

Expand All @@ -55,38 +55,38 @@ public static abstract class ArbitrariesFacade {

public abstract <T> Arbitrary<T> defaultFor(Class<T> type, Class<?>[] typeParameters);

public abstract <T> Arbitrary<T> defaultFor(TypeUsage typeUsage, Function<TypeUsage, Arbitrary<Object>> noDefaultResolver);
public abstract <T extends @Nullable Object> Arbitrary<T> defaultFor(TypeUsage typeUsage, Function<? super TypeUsage, ? extends Arbitrary<T>> noDefaultResolver);

public abstract <T> Arbitrary<T> lazy(Supplier<Arbitrary<T>> arbitrarySupplier);
public abstract <T extends @Nullable Object> Arbitrary<T> lazy(Supplier<? extends Arbitrary<T>> arbitrarySupplier);

public abstract <T> TypeArbitrary<T> forType(Class<T> targetType);

public abstract <K, V> MapArbitrary<K, V> maps(Arbitrary<K> keysArbitrary, Arbitrary<V> valuesArbitrary);
public abstract <K extends @Nullable Object, V extends @Nullable Object> MapArbitrary<K, V> maps(Arbitrary<K> keysArbitrary, Arbitrary<V> valuesArbitrary);

public abstract <K, V> Arbitrary<Map.Entry<K, V>> entries(Arbitrary<K> keysArbitrary, Arbitrary<V> valuesArbitrary);
public abstract <K extends @Nullable Object, V extends @Nullable Object> Arbitrary<Map.Entry<K, V>> entries(Arbitrary<K> keysArbitrary, Arbitrary<V> valuesArbitrary);

public abstract <T> Arbitrary<T> recursive(
Supplier<Arbitrary<T>> base,
Function<Arbitrary<T>, Arbitrary<T>> recur,
public abstract <T extends @Nullable Object> Arbitrary<T> recursive(
Supplier<? extends Arbitrary<T>> base,
Function<? super Arbitrary<T>, ? extends Arbitrary<T>> recur,
int minDepth,
int maxDepth
);

public abstract <T> Arbitrary<T> lazyOf(List<Supplier<Arbitrary<T>>> suppliers);
public abstract <T extends @Nullable Object> Arbitrary<T> lazyOf(List<? extends Supplier<? extends Arbitrary<T>>> suppliers);

public abstract <T> TraverseArbitrary<T> traverse(Class<T> targetType, Traverser traverser);

public abstract Arbitrary<Character> of(char[] chars);

public abstract <T> Arbitrary<T> of(Collection<T> values);
public abstract <T extends @Nullable Object> Arbitrary<T> of(Collection<? extends T> values);

public abstract <T> Arbitrary<T> create(Supplier<T> supplier);
public abstract <T extends @Nullable Object> Arbitrary<T> create(Supplier<T> supplier);

public abstract <T> Arbitrary<List<T>> shuffle(List<T> values);
public abstract <T extends @Nullable Object> Arbitrary<List<T>> shuffle(List<T> values);

public abstract <T> Arbitrary<T> fromGenerator(IntFunction<RandomGenerator<T>> generatorSupplier);
public abstract <T extends @Nullable Object> Arbitrary<T> fromGenerator(IntFunction<? extends RandomGenerator<T>> generatorSupplier);

public abstract <T> Arbitrary<T> frequency(List<Tuple2<Integer, T>> frequencies);
public abstract <T extends @Nullable Object> Arbitrary<T> frequency(List<? extends Tuple2<Integer, T>> frequencies);
}

private Arbitraries() {
Expand All @@ -99,7 +99,7 @@ private Arbitraries() {
* @param <T> The type of values to generate
* @return a new arbitrary instance
*/
public static <T> Arbitrary<T> fromGenerator(RandomGenerator<T> generator) {
public static <T extends @Nullable Object> Arbitrary<T> fromGenerator(RandomGenerator<T> generator) {
return fromGeneratorWithSize(ignore -> generator);
}

Expand All @@ -111,7 +111,7 @@ public static <T> Arbitrary<T> fromGenerator(RandomGenerator<T> generator) {
* @return a new arbitrary instance
*/
@API(status = EXPERIMENTAL, since = "1.8.0")
public static <T> Arbitrary<T> fromGeneratorWithSize(IntFunction<RandomGenerator<T>> generatorSupplier) {
public static <T extends @Nullable Object> Arbitrary<T> fromGeneratorWithSize(IntFunction<RandomGenerator<T>> generatorSupplier) {
return ArbitrariesFacade.implementation.fromGenerator(generatorSupplier);
}

Expand All @@ -123,7 +123,7 @@ public static <T> Arbitrary<T> fromGeneratorWithSize(IntFunction<RandomGenerator
* @param <T> The type of values to generate
* @return a new arbitrary instance
*/
public static <T> Arbitrary<T> randomValue(Function<Random, T> generator) {
public static <T extends @Nullable Object> Arbitrary<T> randomValue(Function<Random, T> generator) {
IntFunction<RandomGenerator<T>> generatorSupplier = ignore -> random -> Shrinkable.unshrinkable(generator.apply(random));
return fromGeneratorWithSize(generatorSupplier);
}
Expand Down Expand Up @@ -153,7 +153,7 @@ public static Arbitrary<Random> randoms() {
* @return a new arbitrary instance
*/
@SafeVarargs
public static <T> Arbitrary<T> of(T... values) {
public static <T extends @Nullable Object> Arbitrary<T> of(T... values) {
return of(Arrays.asList(values));
}

Expand All @@ -172,7 +172,7 @@ public static <T> Arbitrary<T> of(T... values) {
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.3.1")
public static <@Nullable T> Arbitrary<T> of(Collection<T> values) {
public static <T extends @Nullable Object> Arbitrary<T> of(Collection<? extends T> values) {
return ArbitrariesFacade.implementation.of(values);
}

Expand All @@ -192,7 +192,7 @@ public static <T> Arbitrary<T> of(T... values) {
*/
@API(status = MAINTAINED, since = "1.3.0")
@SafeVarargs
public static <T> Arbitrary<T> ofSuppliers(Supplier<T>... valueSuppliers) {
public static <T extends @Nullable Object> Arbitrary<T> ofSuppliers(Supplier<T>... valueSuppliers) {
return of(valueSuppliers).map(Supplier::get);
}

Expand All @@ -211,7 +211,7 @@ public static <T> Arbitrary<T> ofSuppliers(Supplier<T>... valueSuppliers) {
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.3.1")
public static <T> Arbitrary<T> ofSuppliers(Collection<Supplier<T>> valueSuppliers) {
public static <T extends @Nullable Object> Arbitrary<T> ofSuppliers(Collection<Supplier<T>> valueSuppliers) {
return of(valueSuppliers).map(Supplier::get);
}

Expand Down Expand Up @@ -247,7 +247,7 @@ public static <T extends Enum<T>> Arbitrary<T> of(Class<T> enumClass) {
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public static <T> Arbitrary<T> oneOf(Arbitrary<? extends T> first, Arbitrary<? extends T>... rest) {
public static <T extends @Nullable Object> Arbitrary<T> oneOf(Arbitrary<? extends T> first, Arbitrary<? extends T>... rest) {
List<Arbitrary<? extends T>> all = new ArrayList<>();
all.add(first);
for (Arbitrary<?> arbitrary : rest) {
Expand All @@ -264,7 +264,7 @@ public static <T> Arbitrary<T> oneOf(Arbitrary<? extends T> first, Arbitrary<? e
* @return a new arbitrary instance
*/
@SuppressWarnings("unchecked")
public static <T> Arbitrary<T> oneOf(Collection<Arbitrary<? extends T>> choices) {
public static <T extends @Nullable Object> Arbitrary<T> oneOf(Collection<? extends Arbitrary<? extends T>> choices) {
if (choices.isEmpty()) {
String message = "oneOf() must not be called with no choices";
throw new JqwikException(message);
Expand All @@ -285,7 +285,7 @@ public static <T> Arbitrary<T> oneOf(Collection<Arbitrary<? extends T>> choices)
* @return a new arbitrary instance
*/
@SafeVarargs
public static <T> Arbitrary<T> frequency(Tuple2<Integer, T>... frequencies) {
public static <T extends @Nullable Object> Arbitrary<T> frequency(Tuple2<Integer, T>... frequencies) {
return frequency(Arrays.asList(frequencies));
}

Expand All @@ -297,7 +297,7 @@ public static <T> Arbitrary<T> frequency(Tuple2<Integer, T>... frequencies) {
* @param <T> The type of values to generate
* @return a new arbitrary instance
*/
public static <@Nullable T> Arbitrary<T> frequency(List<Tuple2<Integer, T>> frequencies) {
public static <T extends @Nullable Object> Arbitrary<T> frequency(List<? extends Tuple2<Integer, T>> frequencies) {
return ArbitrariesFacade.implementation.frequency(frequencies);
}

Expand All @@ -311,7 +311,7 @@ public static <T> Arbitrary<T> frequency(Tuple2<Integer, T>... frequencies) {
*/
@SuppressWarnings("unchecked")
@SafeVarargs
public static <T> Arbitrary<T> frequencyOf(Tuple2<Integer, Arbitrary<? extends T>>... frequencies) {
public static <T extends @Nullable Object> Arbitrary<T> frequencyOf(Tuple2<Integer, Arbitrary<? extends T>>... frequencies) {
List<Tuple2<Integer, Arbitrary<T>>> all = new ArrayList<>();
for (Tuple2<Integer, Arbitrary<? extends T>> frequency : frequencies) {
all.add(Tuple.of(frequency.get1(), (Arbitrary<T>) frequency.get2()));
Expand All @@ -327,7 +327,7 @@ public static <T> Arbitrary<T> frequencyOf(Tuple2<Integer, Arbitrary<? extends T
* @param <T> The type of values to generate
* @return a new arbitrary instance
*/
public static <@Nullable T> Arbitrary<T> frequencyOf(List<Tuple2<Integer, Arbitrary<T>>> frequencies) {
public static <T extends @Nullable Object> Arbitrary<T> frequencyOf(List<? extends Tuple2<Integer, ? extends Arbitrary<T>>> frequencies) {
// Simple flatMapping is not enough because of configurations
return ArbitrariesFacade.implementation.frequencyOf(frequencies);
}
Expand Down Expand Up @@ -430,7 +430,7 @@ public static CharacterArbitrary chars() {
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.3.2")
public static <@Nullable T> Arbitrary<T> just(@Nullable T value) {
public static <T extends @Nullable Object> Arbitrary<T> just(T value) {
return ArbitrariesFacade.implementation.just(value);
}

Expand All @@ -454,7 +454,7 @@ public static CharacterArbitrary chars() {
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.1.1")
public static <T> Arbitrary<T> create(Supplier<T> supplier) {
Copy link
Collaborator

@jlink jlink Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that methods that previously returned <T> should now return <T extends @Nullable...>. It might be the right choice, but then it should be a different PR IMO. Or is it necessary to peacify the compiler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean you want forbid creating Arbitrary<String?> with this method?

Consider the use case: Arbitraries.create(() -> random.nextBoolean() ? "hi" : null).
Previous declaration (<T>) forbids such use cases, however, they are pretty valid.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm with you that the new signature is correct, but it changes the previous return type. So I'd rather have it in a different PR. If it's too bothersome to pick those changes out, leave them in.

public static <T extends @Nullable Object> Arbitrary<T> create(Supplier<T> supplier) {
return ArbitrariesFacade.implementation.create(supplier);
}

Expand All @@ -468,7 +468,7 @@ public static <T> Arbitrary<T> create(Supplier<T> supplier) {
* @return a new arbitrary instance
*/
@SafeVarargs
public static <T> Arbitrary<List<T>> shuffle(T... values) {
public static <T extends @Nullable Object> Arbitrary<List<T>> shuffle(T... values) {
return shuffle(Arrays.asList(values));
}

Expand All @@ -481,7 +481,7 @@ public static <T> Arbitrary<List<T>> shuffle(T... values) {
* @param <T> The type of values to generate
* @return a new arbitrary instance
*/
public static <T> Arbitrary<List<T>> shuffle(List<T> values) {
public static <T extends @Nullable Object> Arbitrary<List<T>> shuffle(List<T> values) {
return ArbitrariesFacade.implementation.shuffle(values);
}

Expand Down Expand Up @@ -515,7 +515,7 @@ public static <T> Arbitrary<T> defaultFor(Class<T> type, Class<?>... typeParamet
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.1")
public static <T> Arbitrary<T> defaultFor(TypeUsage typeUsage) {
public static <T extends @Nullable Object> Arbitrary<T> defaultFor(TypeUsage typeUsage) {
return defaultFor(typeUsage, ignore -> {throw new CannotFindArbitraryException(typeUsage);});
}

Expand All @@ -534,7 +534,7 @@ public static <T> Arbitrary<T> defaultFor(TypeUsage typeUsage) {
* @return a new arbitrary instance
*/
@API(status = EXPERIMENTAL, since = "1.6.1")
public static <T> Arbitrary<T> defaultFor(TypeUsage typeUsage, Function<TypeUsage, Arbitrary<Object>> noDefaultResolver) {
public static <T> Arbitrary<T> defaultFor(TypeUsage typeUsage, Function<? super TypeUsage, ? extends Arbitrary<T>> noDefaultResolver) {
return ArbitrariesFacade.implementation.defaultFor(typeUsage, noDefaultResolver);
}

Expand Down Expand Up @@ -591,7 +591,7 @@ public static <T> TraverseArbitrary<T> traverse(Class<T> targetType, Traverser t
* @see #recursive(Supplier, Function, int)
* @see #lazyOf(Supplier, Supplier[])
*/
public static <T> Arbitrary<T> lazy(Supplier<Arbitrary<T>> arbitrarySupplier) {
public static <T extends @Nullable Object> Arbitrary<T> lazy(Supplier<? extends Arbitrary<T>> arbitrarySupplier) {
return ArbitrariesFacade.implementation.lazy(arbitrarySupplier);
}

Expand All @@ -609,9 +609,9 @@ public static <T> Arbitrary<T> lazy(Supplier<Arbitrary<T>> arbitrarySupplier) {
* @return a new arbitrary instance
* @see #lazy(Supplier)
*/
public static <T> Arbitrary<T> recursive(
Supplier<Arbitrary<T>> base,
Function<Arbitrary<T>, Arbitrary<T>> recur,
public static <T extends @Nullable Object> Arbitrary<T> recursive(
Supplier<? extends Arbitrary<T>> base,
Function<? super Arbitrary<T>, ? extends Arbitrary<T>> recur,
int depth
) {
return ArbitrariesFacade.implementation.recursive(base, recur, depth, depth);
Expand All @@ -633,9 +633,9 @@ public static <T> Arbitrary<T> recursive(
* @see #lazy(Supplier)
*/
@API(status = MAINTAINED, since = "1.6.4")
public static <T> Arbitrary<T> recursive(
Supplier<Arbitrary<T>> base,
Function<Arbitrary<T>, Arbitrary<T>> recur,
public static <T extends @Nullable Object> Arbitrary<T> recursive(
Supplier<? extends Arbitrary<T>> base,
Function<? super Arbitrary<T>, ? extends Arbitrary<T>> recur,
int minDepth,
int maxDepth
) {
Expand Down Expand Up @@ -671,7 +671,7 @@ public static <T> Arbitrary<T> recursive(
@SuppressWarnings("unchecked")
@SafeVarargs
@API(status = MAINTAINED, since = "1.3.4")
public static <T> Arbitrary<T> lazyOf(Supplier<Arbitrary<? extends T>> first, Supplier<Arbitrary<? extends T>>... rest) {
public static <T extends @Nullable Object> Arbitrary<T> lazyOf(Supplier<Arbitrary<? extends T>> first, Supplier<Arbitrary<? extends T>>... rest) {
List<Supplier<Arbitrary<T>>> all = new ArrayList<>();
all.add(() -> (Arbitrary<T>) first.get());
for (Supplier<Arbitrary<? extends T>> arbitrarySupplier : rest) {
Expand Down Expand Up @@ -739,8 +739,8 @@ public static Arbitrary<Void> nothing() {
* @return a new arbitrary instance
*/
@API(status = MAINTAINED, since = "1.6.4")
public static <@Nullable T> SetArbitrary<T> subsetOf(Collection<T> values) {
return of(values).set();
public static <T extends @Nullable Object> SetArbitrary<T> subsetOf(Collection<? extends T> values) {
return Arbitraries.<T>of(values).set();
}

/**
Expand All @@ -750,7 +750,7 @@ public static Arbitrary<Void> nothing() {
*/
@SafeVarargs
@API(status = MAINTAINED, since = "1.6.4")
public static <T> SetArbitrary<T> subsetOf(T... values) {
public static <T extends @Nullable Object> SetArbitrary<T> subsetOf(T... values) {
return subsetOf(Arrays.asList(values));
}

Expand Down
Loading
Loading