Guard from immediately recursive substitutions
* substitutions of the form T -> T are removed * an assertion added against nontrivial cases like T -> Foo<T>
This commit is contained in:
+6
-1
@@ -140,7 +140,12 @@ public class MutableClassDescriptorLite extends MutableDeclarationDescriptor imp
|
|||||||
|
|
||||||
List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters();
|
List<TypeParameterDescriptor> typeParameters = getTypeConstructor().getParameters();
|
||||||
Map<TypeConstructor, TypeProjection> substitutionContext = SubstitutionUtils.buildSubstitutionContext(typeParameters, typeArguments);
|
Map<TypeConstructor, TypeProjection> substitutionContext = SubstitutionUtils.buildSubstitutionContext(typeParameters, typeArguments);
|
||||||
return new SubstitutingScope(scopeForMemberLookup, TypeSubstitutor.create(substitutionContext));
|
|
||||||
|
// Unsafe substitutor is OK, because no recursion can hurt us upon a trivial substitution:
|
||||||
|
// all the types are written explicitly in the code already, they can not get infinite.
|
||||||
|
// One exception is *-projections, but they need to be handled separately anyways.
|
||||||
|
TypeSubstitutor substitutor = TypeSubstitutor.createUnsafe(substitutionContext);
|
||||||
|
return new SubstitutingScope(scopeForMemberLookup, substitutor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -25,6 +25,7 @@ import org.jetbrains.jet.lang.types.lang.JetStandardClasses;
|
|||||||
import org.jetbrains.jet.util.CommonSuppliers;
|
import org.jetbrains.jet.util.CommonSuppliers;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -120,6 +121,21 @@ public class SubstitutionUtils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Map<TypeConstructor, TypeProjection> removeTrivialSubstitutions(Map<TypeConstructor, TypeProjection> context) {
|
||||||
|
Map<TypeConstructor, TypeProjection> clean = Maps.newHashMap(context);
|
||||||
|
boolean changed = false;
|
||||||
|
for (Iterator<Map.Entry<TypeConstructor, TypeProjection>> iterator = clean.entrySet().iterator(); iterator.hasNext(); ) {
|
||||||
|
Map.Entry<TypeConstructor, TypeProjection> entry = iterator.next();
|
||||||
|
TypeConstructor key = entry.getKey();
|
||||||
|
TypeProjection value = entry.getValue();
|
||||||
|
if (key == value.getType().getConstructor() && value.getProjectionKind() == Variance.INVARIANT) {
|
||||||
|
iterator.remove();
|
||||||
|
changed = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return changed ? clean : context;
|
||||||
|
}
|
||||||
|
|
||||||
public static void assertNotImmediatelyRecursive(Map<TypeConstructor, TypeProjection> context) {
|
public static void assertNotImmediatelyRecursive(Map<TypeConstructor, TypeProjection> context) {
|
||||||
// Make sure we never replace a T with "Foo<T>" or something similar,
|
// Make sure we never replace a T with "Foo<T>" or something similar,
|
||||||
// because the substitution will not terminate in this case
|
// because the substitution will not terminate in this case
|
||||||
|
|||||||
@@ -122,8 +122,16 @@ public class TypeSubstitutor {
|
|||||||
return create(new CompositeTypeSubstitution(substitutions));
|
return create(new CompositeTypeSubstitution(substitutions));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** No assertion for immediate recursion */
|
||||||
|
public static TypeSubstitutor createUnsafe(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext) {
|
||||||
|
Map<TypeConstructor, TypeProjection> cleanContext = SubstitutionUtils.removeTrivialSubstitutions(substitutionContext);
|
||||||
|
return create(new MapToTypeSubstitutionAdapter(cleanContext));
|
||||||
|
}
|
||||||
|
|
||||||
public static TypeSubstitutor create(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext) {
|
public static TypeSubstitutor create(@NotNull Map<TypeConstructor, TypeProjection> substitutionContext) {
|
||||||
return create(new MapToTypeSubstitutionAdapter(substitutionContext));
|
Map<TypeConstructor, TypeProjection> cleanContext = SubstitutionUtils.removeTrivialSubstitutions(substitutionContext);
|
||||||
|
SubstitutionUtils.assertNotImmediatelyRecursive(cleanContext);
|
||||||
|
return createUnsafe(cleanContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static TypeSubstitutor create(@NotNull JetType context) {
|
public static TypeSubstitutor create(@NotNull JetType context) {
|
||||||
|
|||||||
Reference in New Issue
Block a user