Ensure deterministic insertion of checkExpressionValueIsNotNull.

Kotlinc source’s file DescriptorUtils.kt demonstarted non-deterministic
insertion of checkExpressionValueIsNotNull for value returned by
CallableDescriptor::getOriginal(). It was difficult to reproduce
this behavior on ф smaller example, but I added a test which was
failing once in 5-10 times while I was testing manually.

I believe this bug is close to KT-23704.

This PR addresses non-determinism to a degree when I can run 120
Compilations with './gradlew dist' and get same classes in all
jars in 'dist'.

NOTE that thew fact that insertion of checkExpressionValueIsNotNull may
depend on order of the types seems suspicios. This CL only addresses
non-determinism part, but I believe it’s worth looking into this more
from semantics point of view.
This commit is contained in:
Denis Vnukov
2018-04-20 02:27:30 -07:00
committed by Alexander Udalov
parent 10da41b136
commit c5373c9029
3 changed files with 120 additions and 5 deletions
@@ -100,7 +100,7 @@ public class CommonSupertypes {
@NotNull
private static SimpleType commonSuperTypeForInflexible(@NotNull Collection<SimpleType> types, int recursionDepth, int maxDepth) {
assert !types.isEmpty();
Collection<SimpleType> typeSet = new HashSet<>(types);
Collection<SimpleType> typeSet = new LinkedHashSet<>(types);
// If any of the types is nullable, the result must be nullable
// This also removed Nothing and Nothing? because they are subtypes of everything else
@@ -132,7 +132,7 @@ public class CommonSupertypes {
// constructor of the supertype -> all of its instantiations occurring as supertypes
Map<TypeConstructor, Set<SimpleType>> commonSupertypes = computeCommonRawSupertypes(typeSet);
while (commonSupertypes.size() > 1) {
Set<SimpleType> merge = new HashSet<>();
Set<SimpleType> merge = new LinkedHashSet<>();
for (Set<SimpleType> supertypes : commonSupertypes.values()) {
merge.addAll(supertypes);
}
@@ -244,7 +244,7 @@ public class CommonSupertypes {
List<TypeParameterDescriptor> parameters = constructor.getParameters();
List<TypeProjection> newProjections = new ArrayList<>(parameters.size());
for (TypeParameterDescriptor parameterDescriptor : parameters) {
Set<TypeProjection> typeProjections = new HashSet<>();
Set<TypeProjection> typeProjections = new LinkedHashSet<>();
for (KotlinType type : types) {
typeProjections.add(type.getArguments().get(parameterDescriptor.getIndex()));
}
@@ -287,8 +287,8 @@ public class CommonSupertypes {
return TypeUtils.makeStarProjection(parameterDescriptor);
}
Set<KotlinType> ins = new HashSet<>();
Set<KotlinType> outs = new HashSet<>();
Set<KotlinType> ins = new LinkedHashSet<>();
Set<KotlinType> outs = new LinkedHashSet<>();
Variance variance = parameterDescriptor.getVariance();
switch (variance) {
@@ -0,0 +1,109 @@
// FILE: test/DeclarationDescriptor.java
package test;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface DeclarationDescriptor {
@NotNull
DeclarationDescriptor getOriginal();
@Nullable
DeclarationDescriptor getContainingDeclaration();
}
// FILE: test/DeclarationDescriptorWithVisibility.java
package test;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface DeclarationDescriptorWithVisibility extends DeclarationDescriptor {
}
// FILE: test/DeclarationDescriptorWithSource.java
package test;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface DeclarationDescriptorWithSource extends DeclarationDescriptor {
@Override
@NotNull
DeclarationDescriptorWithSource getOriginal();
}
// FILE: test/DeclarationDescriptorNonRoot.java
package test;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface DeclarationDescriptorNonRoot extends DeclarationDescriptorWithSource {
}
// FILE: test/CallableDescriptor.java
package test;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
public interface CallableDescriptor extends DeclarationDescriptorWithVisibility, DeclarationDescriptorNonRoot {
@NotNull
@Override
CallableDescriptor getOriginal();
@NotNull
Collection<? extends CallableDescriptor> getOverriddenDescriptors();
}
// FILE: test/k.kt
package test
fun <D : CallableDescriptor> D.overriddenTreeUniqueAsSequenceA(useOriginal: Boolean): Sequence<D> {
val set = hashSetOf<D>()
@Suppress("UNCHECKED_CAST")
fun D.doBuildOverriddenTreeAsSequence(): Sequence<D> {
return with(if (useOriginal) original as D else this) {
if (original in set)
emptySequence()
else {
emptySequence()
}
}
}
return doBuildOverriddenTreeAsSequence()
}
fun <D : CallableDescriptor> D.overriddenTreeUniqueAsSequenceB(useOriginal: Boolean): Sequence<D> {
val set = hashSetOf<D>()
@Suppress("UNCHECKED_CAST")
fun D.doBuildOverriddenTreeAsSequence(): Sequence<D> {
return with(if (useOriginal) original as D else this) {
if (original in set)
emptySequence()
else {
emptySequence()
}
}
}
return doBuildOverriddenTreeAsSequence()
}
// @KKt.class:
// 0 checkExpressionValueIsNotNull
@@ -2344,6 +2344,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/alreadyCheckedForNull.kt");
}
@TestMetadata("deterministicNotNullChecks.kt")
public void testDeterministicNotNullChecks() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/nullCheckOptimization/deterministicNotNullChecks.kt");
doTest(fileName);
}
@TestMetadata("expressionValueIsNotNull.kt")
public void testExpressionValueIsNotNull() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/nullCheckOptimization/expressionValueIsNotNull.kt");