Extract TypeIntersector from TypeUtils
This commit is contained in:
+2
-5
@@ -41,12 +41,9 @@ import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.INCOMPLETE_TY
|
||||
import org.jetbrains.kotlin.resolve.calls.results.ResolutionStatus.OTHER_ERROR
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.*
|
||||
import org.jetbrains.kotlin.types.TypeUtils.DONT_CARE
|
||||
import org.jetbrains.kotlin.types.TypeUtils.makeConstantSubstitutor
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
|
||||
@@ -191,7 +188,7 @@ class GenericCandidateResolver(
|
||||
val possibleTypes = context.dataFlowInfo.getPossibleTypes(dataFlowValue)
|
||||
if (possibleTypes.isEmpty()) return type
|
||||
|
||||
return TypeUtils.intersect(JetTypeChecker.DEFAULT, possibleTypes)
|
||||
return TypeIntersector.intersect(JetTypeChecker.DEFAULT, possibleTypes)
|
||||
}
|
||||
|
||||
public fun <D : CallableDescriptor> completeTypeInferenceDependentOnFunctionArgumentsForCall(
|
||||
|
||||
+2
-1
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ThisReceiver;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.TypeIntersector;
|
||||
import org.jetbrains.kotlin.types.TypeUtils;
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
||||
|
||||
@@ -151,7 +152,7 @@ public class SmartCastUtils {
|
||||
}
|
||||
if (subTypes.isEmpty()) return null;
|
||||
|
||||
JetType intersection = TypeUtils.intersect(JetTypeChecker.DEFAULT, subTypes);
|
||||
JetType intersection = TypeIntersector.intersect(JetTypeChecker.DEFAULT, subTypes);
|
||||
if (intersection == null || !intersection.getConstructor().isDenotable()) {
|
||||
return receiverParameterType;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1251,7 +1251,7 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
JetType rightType = facade.getTypeInfo(right, context).getType();
|
||||
|
||||
if (rightType != null) {
|
||||
if (TypeUtils.isIntersectionEmpty(leftType, rightType)) {
|
||||
if (TypeIntersector.isIntersectionEmpty(leftType, rightType)) {
|
||||
context.trace.report(EQUALITY_NOT_APPLICABLE.on(expression, expression.getOperationReference(), leftType, rightType));
|
||||
}
|
||||
SenselessComparisonChecker.checkSenselessComparisonWithNull(
|
||||
|
||||
+1
-1
@@ -44,8 +44,8 @@ import java.util.Set;
|
||||
import static org.jetbrains.kotlin.builtins.KotlinBuiltIns.isBoolean;
|
||||
import static org.jetbrains.kotlin.diagnostics.Errors.*;
|
||||
import static org.jetbrains.kotlin.resolve.calls.context.ContextDependency.INDEPENDENT;
|
||||
import static org.jetbrains.kotlin.types.TypeIntersector.isIntersectionEmpty;
|
||||
import static org.jetbrains.kotlin.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
import static org.jetbrains.kotlin.types.TypeUtils.isIntersectionEmpty;
|
||||
import static org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.newWritableScopeImpl;
|
||||
|
||||
public class PatternMatchingTypingVisitor extends ExpressionTypingVisitor {
|
||||
|
||||
@@ -523,7 +523,7 @@ public class JetTypeCheckerTest extends JetLiteFixture {
|
||||
for (String type : types) {
|
||||
typesToIntersect.add(makeType(type));
|
||||
}
|
||||
JetType result = TypeUtils.intersect(JetTypeChecker.DEFAULT, typesToIntersect);
|
||||
JetType result = TypeIntersector.intersect(JetTypeChecker.DEFAULT, typesToIntersect);
|
||||
// assertNotNull("Intersection is null for " + typesToIntersect, result);
|
||||
assertEquals(makeType(expected), result);
|
||||
}
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ class LazyJavaTypeResolver(
|
||||
for (supertype in (classifier() as JavaTypeParameter).getUpperBounds()) {
|
||||
supertypesJet.add(transformJavaType(supertype, UPPER_BOUND.toAttributes()))
|
||||
}
|
||||
return TypeUtils.intersect(JetTypeChecker.DEFAULT, supertypesJet)
|
||||
return TypeIntersector.intersect(JetTypeChecker.DEFAULT, supertypesJet)
|
||||
?: ErrorUtils.createErrorType("Can't intersect upper bounds of " + javaType.getPresentableText())
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -135,7 +135,7 @@ public abstract class AbstractTypeParameterDescriptor extends DeclarationDescrip
|
||||
private JetType computeUpperBoundsAsType() {
|
||||
Set<JetType> upperBounds = getUpperBounds();
|
||||
assert !upperBounds.isEmpty() : "Upper bound list is empty in " + getName();
|
||||
JetType upperBoundsAsType = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds);
|
||||
JetType upperBoundsAsType = TypeIntersector.intersect(JetTypeChecker.DEFAULT, upperBounds);
|
||||
return upperBoundsAsType != null ? upperBoundsAsType : getBuiltIns(this).getNothingType();
|
||||
}
|
||||
|
||||
|
||||
@@ -134,7 +134,7 @@ public class TypeBoundsImpl(
|
||||
}
|
||||
|
||||
val upperBounds = filterBounds(bounds, TypeBounds.BoundKind.UPPER_BOUND, values)
|
||||
val intersectionOfUpperBounds = TypeUtils.intersect(JetTypeChecker.DEFAULT, upperBounds)
|
||||
val intersectionOfUpperBounds = TypeIntersector.intersect(JetTypeChecker.DEFAULT, upperBounds)
|
||||
if (!upperBounds.isEmpty() && intersectionOfUpperBounds != null) {
|
||||
if (tryPossibleAnswer(bounds, intersectionOfUpperBounds)) {
|
||||
return setOf(intersectionOfUpperBounds)
|
||||
|
||||
@@ -299,7 +299,7 @@ public class CommonSupertypes {
|
||||
return new TypeProjectionImpl(projectionKind, findCommonSupertype(outs, recursionDepth + 1, maxDepth));
|
||||
}
|
||||
if (ins != null) {
|
||||
JetType intersection = TypeUtils.intersect(JetTypeChecker.DEFAULT, ins);
|
||||
JetType intersection = TypeIntersector.intersect(JetTypeChecker.DEFAULT, ins);
|
||||
if (intersection == null) {
|
||||
return new TypeProjectionImpl(OUT_VARIANCE, findCommonSupertype(parameterDescriptor.getUpperBounds(), recursionDepth + 1, maxDepth));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright 2010-2015 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.types;
|
||||
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl;
|
||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.calls.inference.InferencePackage.registerTypeVariables;
|
||||
import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.SPECIAL;
|
||||
|
||||
public class TypeIntersector {
|
||||
public static boolean isIntersectionEmpty(@NotNull JetType typeA, @NotNull JetType typeB) {
|
||||
return intersect(JetTypeChecker.DEFAULT, new LinkedHashSet<JetType>(Arrays.asList(typeA, typeB))) == null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetType intersect(@NotNull JetTypeChecker typeChecker, @NotNull Set<JetType> types) {
|
||||
if (types.isEmpty()) {
|
||||
return KotlinBuiltIns.getInstance().getNullableAnyType();
|
||||
}
|
||||
|
||||
if (types.size() == 1) {
|
||||
return types.iterator().next();
|
||||
}
|
||||
|
||||
// Intersection of T1..Tn is an intersection of their non-null versions,
|
||||
// made nullable is they all were nullable
|
||||
boolean allNullable = true;
|
||||
boolean nothingTypePresent = false;
|
||||
List<JetType> nullabilityStripped = new ArrayList<JetType>(types.size());
|
||||
for (JetType type : types) {
|
||||
if (type.isError()) continue;
|
||||
|
||||
nothingTypePresent |= KotlinBuiltIns.isNothingOrNullableNothing(type);
|
||||
allNullable &= type.isMarkedNullable();
|
||||
nullabilityStripped.add(TypeUtils.makeNotNullable(type));
|
||||
}
|
||||
|
||||
if (nothingTypePresent) {
|
||||
return allNullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
|
||||
}
|
||||
|
||||
if (nullabilityStripped.isEmpty()) {
|
||||
// All types were errors
|
||||
return ErrorUtils.createErrorType("Intersection of errors types: " + types);
|
||||
}
|
||||
|
||||
// Now we remove types that have subtypes in the list
|
||||
List<JetType> resultingTypes = new ArrayList<JetType>();
|
||||
outer:
|
||||
for (JetType type : nullabilityStripped) {
|
||||
if (!TypeUtils.canHaveSubtypes(typeChecker, type)) {
|
||||
for (JetType other : nullabilityStripped) {
|
||||
// It makes sense to check for subtyping (other <: type), despite that
|
||||
// type is not supposed to be open, for there're enums
|
||||
if (!TypeUnifier.mayBeEqual(type, other) && !typeChecker.isSubtypeOf(type, other) && !typeChecker.isSubtypeOf(other, type)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return TypeUtils.makeNullableAsSpecified(type, allNullable);
|
||||
}
|
||||
else {
|
||||
for (JetType other : nullabilityStripped) {
|
||||
if (!type.equals(other) && typeChecker.isSubtypeOf(other, type)) {
|
||||
continue outer;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Don't add type if it is already present, to avoid trivial type intersections in result
|
||||
for (JetType other : resultingTypes) {
|
||||
if (typeChecker.equalTypes(other, type)) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
resultingTypes.add(type);
|
||||
}
|
||||
|
||||
if (resultingTypes.isEmpty()) {
|
||||
// If we ended up here, it means that all types from `nullabilityStripped` were excluded by the code above
|
||||
// most likely, this is because they are all semantically interchangeable (e.g. List<Foo>! and List<Foo>),
|
||||
// in that case, we can safely select the best representative out of that set and return it
|
||||
// TODO: maybe return the most specific among the types that are subtypes to all others in the `nullabilityStripped`?
|
||||
// TODO: e.g. among {Int, Int?, Int!}, return `Int` (now it returns `Int!`).
|
||||
JetType bestRepresentative = TypesPackage.singleBestRepresentative(nullabilityStripped);
|
||||
if (bestRepresentative == null) {
|
||||
throw new AssertionError("Empty intersection for types " + types);
|
||||
}
|
||||
return TypeUtils.makeNullableAsSpecified(bestRepresentative, allNullable);
|
||||
}
|
||||
|
||||
if (resultingTypes.size() == 1) {
|
||||
return TypeUtils.makeNullableAsSpecified(resultingTypes.get(0), allNullable);
|
||||
}
|
||||
|
||||
TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.EMPTY, resultingTypes);
|
||||
|
||||
JetScope[] scopes = new JetScope[resultingTypes.size()];
|
||||
int i = 0;
|
||||
for (JetType type : resultingTypes) {
|
||||
scopes[i] = type.getMemberScope();
|
||||
i++;
|
||||
}
|
||||
|
||||
return JetTypeImpl.create(
|
||||
Annotations.EMPTY,
|
||||
constructor,
|
||||
allNullable,
|
||||
Collections.<TypeProjection>emptyList(),
|
||||
new IntersectionScope(constructor, scopes)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO : check intersectibility, don't use a chanied scope
|
||||
private static class IntersectionScope extends ChainedScope {
|
||||
public IntersectionScope(@NotNull TypeConstructor constructor, @NotNull JetScope[] scopes) {
|
||||
super(null, "member scope for intersection type " + constructor, scopes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DeclarationDescriptor getContainingDeclaration() {
|
||||
throw new UnsupportedOperationException("Should not call getContainingDeclaration on intersection scope " + this);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeUnifier {
|
||||
private static class TypeParameterUsage {
|
||||
private final TypeParameterDescriptor typeParameterDescriptor;
|
||||
private final Variance howTheTypeParameterIsUsed;
|
||||
|
||||
public TypeParameterUsage(TypeParameterDescriptor typeParameterDescriptor, Variance howTheTypeParameterIsUsed) {
|
||||
this.typeParameterDescriptor = typeParameterDescriptor;
|
||||
this.howTheTypeParameterIsUsed = howTheTypeParameterIsUsed;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean mayBeEqual(@NotNull JetType type, @NotNull JetType other) {
|
||||
return unify(type, other);
|
||||
}
|
||||
|
||||
private static boolean unify(JetType withParameters, JetType expected) {
|
||||
// T -> how T is used
|
||||
final Map<TypeParameterDescriptor, Variance> parameters = new HashMap<TypeParameterDescriptor, Variance>();
|
||||
Function1<TypeParameterUsage, Unit> processor = new Function1<TypeParameterUsage, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(TypeParameterUsage parameterUsage) {
|
||||
Variance howTheTypeIsUsedBefore = parameters.get(parameterUsage.typeParameterDescriptor);
|
||||
if (howTheTypeIsUsedBefore == null) {
|
||||
howTheTypeIsUsedBefore = Variance.INVARIANT;
|
||||
}
|
||||
parameters.put(parameterUsage.typeParameterDescriptor,
|
||||
parameterUsage.howTheTypeParameterIsUsed.superpose(howTheTypeIsUsedBefore));
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
};
|
||||
processAllTypeParameters(withParameters, Variance.INVARIANT, processor);
|
||||
processAllTypeParameters(expected, Variance.INVARIANT, processor);
|
||||
ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
|
||||
registerTypeVariables(constraintSystem, parameters);
|
||||
constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position());
|
||||
|
||||
return constraintSystem.getStatus().isSuccessful();
|
||||
}
|
||||
|
||||
private static void processAllTypeParameters(JetType type, Variance howThisTypeIsUsed, Function1<TypeParameterUsage, Unit> result) {
|
||||
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor instanceof TypeParameterDescriptor) {
|
||||
result.invoke(new TypeParameterUsage((TypeParameterDescriptor) descriptor, howThisTypeIsUsed));
|
||||
}
|
||||
for (TypeProjection projection : type.getArguments()) {
|
||||
if (projection.isStarProjection()) continue;
|
||||
processAllTypeParameters(projection.getType(), projection.getProjectionKind(), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,19 +17,15 @@
|
||||
package org.jetbrains.kotlin.types;
|
||||
|
||||
import kotlin.KotlinPackage;
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.resolve.calls.inference.ConstraintSystemImpl;
|
||||
import org.jetbrains.kotlin.resolve.constants.IntegerValueTypeConstructor;
|
||||
import org.jetbrains.kotlin.resolve.scopes.ChainedScope;
|
||||
import org.jetbrains.kotlin.resolve.scopes.JetScope;
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.kotlin.utils.DFS;
|
||||
@@ -37,9 +33,6 @@ import org.jetbrains.kotlin.utils.UtilsPackage;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.calls.inference.InferencePackage.registerTypeVariables;
|
||||
import static org.jetbrains.kotlin.resolve.calls.inference.constraintPosition.ConstraintPositionKind.SPECIAL;
|
||||
|
||||
public class TypeUtils {
|
||||
public static final JetType DONT_CARE = ErrorUtils.createErrorTypeWithCustomDebugName("DONT_CARE");
|
||||
public static final JetType PLACEHOLDER_FUNCTION_TYPE = ErrorUtils.createErrorTypeWithCustomDebugName("PLACEHOLDER_FUNCTION_TYPE");
|
||||
@@ -165,173 +158,6 @@ public class TypeUtils {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static boolean isIntersectionEmpty(@NotNull JetType typeA, @NotNull JetType typeB) {
|
||||
return intersect(JetTypeChecker.DEFAULT, new LinkedHashSet<JetType>(Arrays.asList(typeA, typeB))) == null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static JetType intersect(@NotNull JetTypeChecker typeChecker, @NotNull Set<JetType> types) {
|
||||
if (types.isEmpty()) {
|
||||
return KotlinBuiltIns.getInstance().getNullableAnyType();
|
||||
}
|
||||
|
||||
if (types.size() == 1) {
|
||||
return types.iterator().next();
|
||||
}
|
||||
|
||||
// Intersection of T1..Tn is an intersection of their non-null versions,
|
||||
// made nullable is they all were nullable
|
||||
boolean allNullable = true;
|
||||
boolean nothingTypePresent = false;
|
||||
List<JetType> nullabilityStripped = new ArrayList<JetType>(types.size());
|
||||
for (JetType type : types) {
|
||||
if (type.isError()) continue;
|
||||
|
||||
nothingTypePresent |= KotlinBuiltIns.isNothingOrNullableNothing(type);
|
||||
allNullable &= type.isMarkedNullable();
|
||||
nullabilityStripped.add(makeNotNullable(type));
|
||||
}
|
||||
|
||||
if (nothingTypePresent) {
|
||||
return allNullable ? KotlinBuiltIns.getInstance().getNullableNothingType() : KotlinBuiltIns.getInstance().getNothingType();
|
||||
}
|
||||
|
||||
if (nullabilityStripped.isEmpty()) {
|
||||
// All types were errors
|
||||
return ErrorUtils.createErrorType("Intersection of errors types: " + types);
|
||||
}
|
||||
|
||||
// Now we remove types that have subtypes in the list
|
||||
List<JetType> resultingTypes = new ArrayList<JetType>();
|
||||
outer:
|
||||
for (JetType type : nullabilityStripped) {
|
||||
if (!canHaveSubtypes(typeChecker, type)) {
|
||||
for (JetType other : nullabilityStripped) {
|
||||
// It makes sense to check for subtyping (other <: type), despite that
|
||||
// type is not supposed to be open, for there're enums
|
||||
if (!TypeUnifier.mayBeEqual(type, other) && !typeChecker.isSubtypeOf(type, other) && !typeChecker.isSubtypeOf(other, type)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return makeNullableAsSpecified(type, allNullable);
|
||||
}
|
||||
else {
|
||||
for (JetType other : nullabilityStripped) {
|
||||
if (!type.equals(other) && typeChecker.isSubtypeOf(other, type)) {
|
||||
continue outer;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Don't add type if it is already present, to avoid trivial type intersections in result
|
||||
for (JetType other : resultingTypes) {
|
||||
if (typeChecker.equalTypes(other, type)) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
resultingTypes.add(type);
|
||||
}
|
||||
|
||||
if (resultingTypes.isEmpty()) {
|
||||
// If we ended up here, it means that all types from `nullabilityStripped` were excluded by the code above
|
||||
// most likely, this is because they are all semantically interchangeable (e.g. List<Foo>! and List<Foo>),
|
||||
// in that case, we can safely select the best representative out of that set and return it
|
||||
// TODO: maybe return the most specific among the types that are subtypes to all others in the `nullabilityStripped`?
|
||||
// TODO: e.g. among {Int, Int?, Int!}, return `Int` (now it returns `Int!`).
|
||||
JetType bestRepresentative = TypesPackage.singleBestRepresentative(nullabilityStripped);
|
||||
if (bestRepresentative == null) {
|
||||
throw new AssertionError("Empty intersection for types " + types);
|
||||
}
|
||||
return makeNullableAsSpecified(bestRepresentative, allNullable);
|
||||
}
|
||||
|
||||
if (resultingTypes.size() == 1) {
|
||||
return makeNullableAsSpecified(resultingTypes.get(0), allNullable);
|
||||
}
|
||||
|
||||
TypeConstructor constructor = new IntersectionTypeConstructor(Annotations.EMPTY, resultingTypes);
|
||||
|
||||
JetScope[] scopes = new JetScope[resultingTypes.size()];
|
||||
int i = 0;
|
||||
for (JetType type : resultingTypes) {
|
||||
scopes[i] = type.getMemberScope();
|
||||
i++;
|
||||
}
|
||||
|
||||
return JetTypeImpl.create(
|
||||
Annotations.EMPTY,
|
||||
constructor,
|
||||
allNullable,
|
||||
Collections.<TypeProjection>emptyList(),
|
||||
new IntersectionScope(constructor, scopes)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO : check intersectibility, don't use a chanied scope
|
||||
public static class IntersectionScope extends ChainedScope {
|
||||
public IntersectionScope(@NotNull TypeConstructor constructor, @NotNull JetScope[] scopes) {
|
||||
super(null, "member scope for intersection type " + constructor, scopes);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public DeclarationDescriptor getContainingDeclaration() {
|
||||
throw new UnsupportedOperationException("Should not call getContainingDeclaration on intersection scope " + this);
|
||||
}
|
||||
}
|
||||
|
||||
private static class TypeUnifier {
|
||||
private static class TypeParameterUsage {
|
||||
private final TypeParameterDescriptor typeParameterDescriptor;
|
||||
private final Variance howTheTypeParameterIsUsed;
|
||||
|
||||
public TypeParameterUsage(TypeParameterDescriptor typeParameterDescriptor, Variance howTheTypeParameterIsUsed) {
|
||||
this.typeParameterDescriptor = typeParameterDescriptor;
|
||||
this.howTheTypeParameterIsUsed = howTheTypeParameterIsUsed;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean mayBeEqual(@NotNull JetType type, @NotNull JetType other) {
|
||||
return unify(type, other);
|
||||
}
|
||||
|
||||
private static boolean unify(JetType withParameters, JetType expected) {
|
||||
// T -> how T is used
|
||||
final Map<TypeParameterDescriptor, Variance> parameters = new HashMap<TypeParameterDescriptor, Variance>();
|
||||
Function1<TypeParameterUsage, Unit> processor = new Function1<TypeParameterUsage, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(TypeParameterUsage parameterUsage) {
|
||||
Variance howTheTypeIsUsedBefore = parameters.get(parameterUsage.typeParameterDescriptor);
|
||||
if (howTheTypeIsUsedBefore == null) {
|
||||
howTheTypeIsUsedBefore = Variance.INVARIANT;
|
||||
}
|
||||
parameters.put(parameterUsage.typeParameterDescriptor,
|
||||
parameterUsage.howTheTypeParameterIsUsed.superpose(howTheTypeIsUsedBefore));
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
};
|
||||
processAllTypeParameters(withParameters, Variance.INVARIANT, processor);
|
||||
processAllTypeParameters(expected, Variance.INVARIANT, processor);
|
||||
ConstraintSystemImpl constraintSystem = new ConstraintSystemImpl();
|
||||
registerTypeVariables(constraintSystem, parameters);
|
||||
constraintSystem.addSubtypeConstraint(withParameters, expected, SPECIAL.position());
|
||||
|
||||
return constraintSystem.getStatus().isSuccessful();
|
||||
}
|
||||
|
||||
private static void processAllTypeParameters(JetType type, Variance howThisTypeIsUsed, Function1<TypeParameterUsage, Unit> result) {
|
||||
ClassifierDescriptor descriptor = type.getConstructor().getDeclarationDescriptor();
|
||||
if (descriptor instanceof TypeParameterDescriptor) {
|
||||
result.invoke(new TypeParameterUsage((TypeParameterDescriptor) descriptor, howThisTypeIsUsed));
|
||||
}
|
||||
for (TypeProjection projection : type.getArguments()) {
|
||||
if (projection.isStarProjection()) continue;
|
||||
processAllTypeParameters(projection.getType(), projection.getProjectionKind(), result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean canHaveSubtypes(JetTypeChecker typeChecker, @NotNull JetType type) {
|
||||
if (type.isMarkedNullable()) {
|
||||
return true;
|
||||
|
||||
+1
-1
@@ -196,7 +196,7 @@ private fun JetNamedDeclaration.guessType(context: BindingContext): Array<JetTyp
|
||||
if (expectedTypes.isEmpty() || expectedTypes.any { expectedType -> ErrorUtils.containsErrorType(expectedType) }) {
|
||||
return arrayOf()
|
||||
}
|
||||
val theType = TypeUtils.intersect(JetTypeChecker.DEFAULT, expectedTypes)
|
||||
val theType = TypeIntersector.intersect(JetTypeChecker.DEFAULT, expectedTypes)
|
||||
if (theType != null) {
|
||||
return arrayOf(theType)
|
||||
}
|
||||
|
||||
+24
-28
@@ -16,36 +16,32 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.quickfix.createFromUsage.createClass
|
||||
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageViewDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.noSubstitutions
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import com.intellij.codeInsight.daemon.quickFix.CreateClassOrPackageFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.DelegatingIntentionAction
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import com.intellij.psi.PsiPackage
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import com.intellij.psi.JavaPsiFacade
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiPackage
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.JetBundle
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
|
||||
import org.jetbrains.kotlin.idea.quickfix.DelegatingIntentionAction
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
|
||||
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.noSubstitutions
|
||||
import org.jetbrains.kotlin.psi.Call
|
||||
import org.jetbrains.kotlin.psi.JetExpression
|
||||
import org.jetbrains.kotlin.psi.JetFile
|
||||
import org.jetbrains.kotlin.psi.JetSimpleNameExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.Qualifier
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind as ClassDescriptorKind
|
||||
|
||||
private fun String.checkClassName(): Boolean = isNotEmpty() && Character.isUpperCase(first())
|
||||
|
||||
+1
-1
@@ -519,7 +519,7 @@ private class MutableParameter(
|
||||
|
||||
private val defaultType: JetType by lazy {
|
||||
writable = false
|
||||
TypeUtils.intersect(JetTypeChecker.DEFAULT, defaultTypes)!!
|
||||
TypeIntersector.intersect(JetTypeChecker.DEFAULT, defaultTypes)!!
|
||||
}
|
||||
|
||||
private val parameterTypeCandidates: List<JetType> by lazy {
|
||||
|
||||
Reference in New Issue
Block a user