Skip to content

Commit

Permalink
Fixed bug #519
Browse files Browse the repository at this point in the history
  • Loading branch information
jlink committed Oct 19, 2023
1 parent ac2ade6 commit d6de16d
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -120,17 +120,28 @@ private TypeResolution resolveVariableLocally(TypeResolution typeResolution) {
}

private TypeResolution resolveVariableInSupertypes(TypeResolution typeResolution) {
return supertypeContexts()
.map(context -> context.resolveVariableLocally(typeResolution))
.filter(TypeResolution::typeHasChanged)
// TODO: Optimize so that only get supertypes of supertypes if necessary
// i.e. it cannot be resolved in direct supertypes
Set<TypeUsage> superTypes = getAllSupertypes(contextType);
List<TypeResolution> typeResolutionList =
superTypes.stream()
.map(GenericsSupport::contextFor)
.map(context -> context.resolveVariableLocally(typeResolution))
.filter(TypeResolution::typeHasChanged)
.collect(Collectors.toList());

return typeResolutionList.stream()
.findFirst()
.orElse(typeResolution.unchanged());
}

private Stream<GenericsClassContext> supertypeContexts() {
Stream<TypeUsage> superclassStream = contextType.getSuperclass().map(Stream::of).orElseGet(Stream::empty);
Stream<TypeUsage> interfacesStream = contextType.getInterfaces().stream();
return Stream.concat(superclassStream, interfacesStream).map(GenericsSupport::contextFor);
private Set<TypeUsage> getAllSupertypes(TypeUsage contextType) {
List<TypeUsage> directSupertypes = contextType.getSuperTypes();
Set<TypeUsage> allSupertypes = new LinkedHashSet<>(directSupertypes);
for (TypeUsage directSupertype : directSupertypes) {
allSupertypes.addAll(getAllSupertypes(directSupertype));
}
return allSupertypes;
}

private static class LookupTypeVariable {
Expand Down
45 changes: 45 additions & 0 deletions engine/src/test/java/examples/bugs/Issue519Bug.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package examples.bugs;

import net.jqwik.api.*;

// See https://github.com/jqwik-team/jqwik/issues/519
class Issue519Bug implements C<MyRecord> {
@Provide("anyT")
@Override
public Arbitrary<MyRecord> anyT() {
return Arbitraries.of(new MyRecord());
}
}

interface A<T> {
@Property
default boolean test1(@ForAll("anyT") T t) {
return true;
}

Arbitrary<T> anyT();
}

interface B<T extends Comparable<? super T>> extends A<T> {
@Property
default boolean test2(@ForAll("anyT") T t) {
return true;
}
}

interface MyType extends Comparable<MyType> { }

interface C<T extends MyType> extends B<T> {
@Property
default boolean test3(@ForAll("anyT") T t) {
return true;
}
}

class MyRecord implements MyType {
@Override
public int compareTo(MyType o) {
return 0;
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -273,9 +273,43 @@ class Inner3 extends Inner2<String> {}
assertThat(typeUsage.isOfType(GenericType.class)).isTrue();
assertThat(typeUsage.getTypeArguments()).hasSize(1);
assertThat(typeUsage.getTypeArgument(0).isOfType(String.class)).isTrue();
}
}

@Example
@Label("Bug from issue#519")
void bug519() throws NoSuchMethodException {
abstract class A<T> {
public boolean myMethod(T t) {
return true;
}
}

abstract class B<T extends Comparable<? super T>> extends A<T> {
}

abstract class MyType implements Comparable<MyType> { }

abstract class C<T extends MyType> extends B<T> {
}

class MyRecord extends MyType {
@Override
public int compareTo(MyType o) {
return 0;
}
}

class ConcreteC extends C<MyRecord> {
}

GenericsClassContext context = GenericsSupport.contextFor(ConcreteC.class);
Method method = A.class.getMethod("myMethod", Object.class);

TypeResolution resolution = context.resolveParameter(method.getParameters()[0]);
TypeUsage typeUsage = TypeUsageImpl.forResolution(resolution);

assertThat(typeUsage.isOfType(MyRecord.class)).isTrue();
}

@Group
Expand Down

0 comments on commit d6de16d

Please sign in to comment.