Move and expand hack about not-null smart casts for type parameters
This commit is contained in:
+50
@@ -198,6 +198,56 @@ public class SmartCastManager {
|
||||
return canBeCast;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SmartCastResult checkAndRecordPossibleCast(
|
||||
@NotNull DataFlowValue dataFlowValue,
|
||||
@NotNull JetType expectedType,
|
||||
@Nullable JetExpression expression,
|
||||
@NotNull ResolutionContext c,
|
||||
boolean recordExpressionType
|
||||
) {
|
||||
for (JetType possibleType : c.dataFlowInfo.getPossibleTypes(dataFlowValue)) {
|
||||
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) {
|
||||
if (expression != null) {
|
||||
recordCastOrError(expression, possibleType, c.trace, dataFlowValue.isPredictable(), recordExpressionType);
|
||||
}
|
||||
return new SmartCastResult(possibleType, dataFlowValue.isPredictable());
|
||||
}
|
||||
}
|
||||
|
||||
if (!c.dataFlowInfo.getNullability(dataFlowValue).canBeNull() && !expectedType.isMarkedNullable()) {
|
||||
// Handling cases like:
|
||||
// fun bar(x: Any) {}
|
||||
// fun <T : Any?> foo(x: T) {
|
||||
// if (x != null) {
|
||||
// bar(x) // Should be allowed with smart cast
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// It doesn't handled by lower code with getPossibleTypes because smart cast of T after `x != null` is still has same type T.
|
||||
// But at the same time we're sure that `x` can't be null and just check for such cases manually
|
||||
|
||||
// E.g. in case x!! when x has type of T where T is type parameter with nullable upper bounds
|
||||
// x!! is immanently not null (see DataFlowValueFactory.createDataFlowValue for expression)
|
||||
boolean immanentlyNotNull = !dataFlowValue.getImmanentNullability().canBeNull();
|
||||
JetType nullableExpectedType = TypeUtils.makeNullable(expectedType);
|
||||
|
||||
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(dataFlowValue.getType(), nullableExpectedType)) {
|
||||
if (!immanentlyNotNull) {
|
||||
if (expression != null) {
|
||||
recordCastOrError(expression, dataFlowValue.getType(), c.trace, dataFlowValue.isPredictable(),
|
||||
recordExpressionType);
|
||||
}
|
||||
}
|
||||
|
||||
return new SmartCastResult(dataFlowValue.getType(), immanentlyNotNull || dataFlowValue.isPredictable());
|
||||
}
|
||||
return checkAndRecordPossibleCast(dataFlowValue, nullableExpectedType, expression, c, recordExpressionType);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean recordSmartCastToNotNullIfPossible(
|
||||
@NotNull ReceiverValue receiver,
|
||||
@NotNull ResolutionContext context
|
||||
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* 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.resolve.calls.smartcasts
|
||||
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
|
||||
public class SmartCastResult(public val resultType: JetType, public val isCorrect: Boolean)
|
||||
@@ -28,10 +28,7 @@ import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace;
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.AdditionalTypeChecker;
|
||||
import org.jetbrains.kotlin.resolve.calls.context.ResolutionContext;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.SmartCastManager;
|
||||
import org.jetbrains.kotlin.resolve.calls.smartcasts.*;
|
||||
import org.jetbrains.kotlin.resolve.constants.*;
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
@@ -219,30 +216,8 @@ public class DataFlowAnalyzer {
|
||||
) {
|
||||
DataFlowValue dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, expressionType, c);
|
||||
|
||||
for (JetType possibleType : c.dataFlowInfo.getPossibleTypes(dataFlowValue)) {
|
||||
if (JetTypeChecker.DEFAULT.isSubtypeOf(possibleType, c.expectedType)) {
|
||||
smartCastManager.recordCastOrError(expression, possibleType, c.trace, dataFlowValue.isPredictable(), false);
|
||||
return possibleType;
|
||||
}
|
||||
}
|
||||
|
||||
// For cases like:
|
||||
// fun bar(x: Any) {}
|
||||
// fun <T : Any?> foo(x: T) {
|
||||
// if (x != null) {
|
||||
// bar(x) // Should be allowed with smart cast
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// It doesn't handled by upper code with getPossibleTypes because smart cast of T after `x != null` is still has same type T.
|
||||
// But at the same time we're sure that `x` can't be null and just check for such cases manually
|
||||
if (!c.dataFlowInfo.getNullability(dataFlowValue).canBeNull()
|
||||
&& JetTypeChecker.DEFAULT.isSubtypeOf(expressionType, TypeUtils.makeNullable(c.expectedType))) {
|
||||
smartCastManager.recordCastOrError(expression, expressionType, c.trace, dataFlowValue.isPredictable(), false);
|
||||
return expressionType;
|
||||
}
|
||||
|
||||
return null;
|
||||
SmartCastResult result = smartCastManager.checkAndRecordPossibleCast(dataFlowValue, c.expectedType, expression, c, false);
|
||||
return result != null ? result.getResultType() : null;
|
||||
}
|
||||
|
||||
public void recordExpectedType(@NotNull BindingTrace trace, @NotNull JetExpression expression, @NotNull JetType expectedType) {
|
||||
|
||||
Reference in New Issue
Block a user