resolve elvis operator as call
This commit is contained in:
+15
-16
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.jetbrains.jet.lang.types.expressions;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Multimap;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
@@ -35,6 +36,7 @@ import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowValueFactory;
|
||||
import org.jetbrains.jet.lang.resolve.calls.autocasts.Nullability;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.ExpressionPosition;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallWithTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.VariableAsFunctionResolvedCall;
|
||||
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
|
||||
@@ -1031,25 +1033,22 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
JetExpression left = expression.getLeft();
|
||||
JetExpression right = expression.getRight();
|
||||
|
||||
JetTypeInfo leftTypeInfo = getTypeInfoOrNullType(left, context, facade);
|
||||
if (left == null || right == null) {
|
||||
getTypeInfoOrNullType(left, context, facade);
|
||||
return JetTypeInfo.create(null, context.dataFlowInfo);
|
||||
}
|
||||
|
||||
Call call = createCallForSpecialConstruction(expression, Lists.newArrayList(left, right));
|
||||
ResolvedCall<FunctionDescriptor> resolvedCall = resolveSpecialConstructionAsCall(
|
||||
call, "Elvis", Lists.newArrayList("left", "right"), Lists.newArrayList(true, false), contextWithExpectedType, null);
|
||||
JetTypeInfo leftTypeInfo = BindingContextUtils.getRecordedTypeInfo(left, context.trace.getBindingContext());
|
||||
assert leftTypeInfo != null : "Left expression was not processed: " + expression;
|
||||
JetType leftType = leftTypeInfo.getType();
|
||||
DataFlowInfo dataFlowInfo = leftTypeInfo.getDataFlowInfo();
|
||||
|
||||
if (left == null || leftType == null) return JetTypeInfo.create(null, dataFlowInfo);
|
||||
|
||||
if (isKnownToBeNotNull(left, leftType, context)) {
|
||||
if (leftType != null && isKnownToBeNotNull(left, leftType, context)) {
|
||||
context.trace.report(USELESS_ELVIS.on(left, leftType));
|
||||
}
|
||||
|
||||
ExpressionTypingContext newContext = contextWithExpectedType.replaceDataFlowInfo(dataFlowInfo).replaceScope(context.scope);
|
||||
JetType rightType = right == null ? null : facade.getTypeInfo(right, newContext).getType();
|
||||
|
||||
if (rightType != null) {
|
||||
DataFlowUtils.checkType(TypeUtils.makeNullableAsSpecified(leftType, rightType.isNullable()), left, contextWithExpectedType);
|
||||
return JetTypeInfo.create(TypeUtils.makeNullableAsSpecified(
|
||||
CommonSupertypes.commonSupertype(Arrays.asList(leftType, rightType)), rightType.isNullable()), dataFlowInfo);
|
||||
}
|
||||
return JetTypeInfo.create(null, dataFlowInfo);
|
||||
return JetTypeInfo.create(resolvedCall.getResultingDescriptor().getReturnType(),
|
||||
resolvedCall.getDataFlowInfoForArguments().getResultInfo());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+16
-2
@@ -250,6 +250,11 @@ public class ControlStructureTypingUtils {
|
||||
this.trace = trace;
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
|
||||
CheckTypeContext makeTypeNullable() {
|
||||
if (TypeUtils.noExpectedType(expectedType)) return this;
|
||||
return new CheckTypeContext(trace, TypeUtils.makeNullable(expectedType));
|
||||
}
|
||||
}
|
||||
|
||||
final JetVisitor<Void, CheckTypeContext> checkTypeVisitor = new JetVisitor<Void, CheckTypeContext>() {
|
||||
@@ -280,13 +285,22 @@ public class ControlStructureTypingUtils {
|
||||
@Override
|
||||
public Void visitPostfixExpression(JetPostfixExpression expression, CheckTypeContext c) {
|
||||
if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.EXCLEXCL) {
|
||||
checkExpressionType(expression.getBaseExpression(),
|
||||
new CheckTypeContext(c.trace, TypeUtils.makeNullable(c.expectedType)));
|
||||
checkExpressionType(expression.getBaseExpression(), c.makeTypeNullable());
|
||||
return null;
|
||||
}
|
||||
return super.visitPostfixExpression(expression, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitBinaryExpression(JetBinaryExpression expression, CheckTypeContext c) {
|
||||
if (expression.getOperationReference().getReferencedNameElementType() == JetTokens.ELVIS) {
|
||||
checkExpressionType(expression.getLeft(), c.makeTypeNullable());
|
||||
checkExpressionType(expression.getRight(), c);
|
||||
return null;
|
||||
}
|
||||
return super.visitBinaryExpression(expression, c);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void visitExpression(JetExpression expression, CheckTypeContext c) {
|
||||
JetTypeInfo typeInfo = BindingContextUtils.getRecordedTypeInfo(expression, c.trace.getBindingContext());
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package a
|
||||
|
||||
trait A
|
||||
fun doList(l: List<Int>) = l
|
||||
fun doInt(i: Int) = i
|
||||
fun getList(): List<Int>? = null
|
||||
fun <T> strangeList(f: (T) -> Unit): List<T> = throw Exception("$f")
|
||||
fun <T: A> emptyListOfA(): List<T> = throw Exception()
|
||||
|
||||
//-------------------------------
|
||||
|
||||
fun testElvis(a: Int?, b: Int?) {
|
||||
if (a != null) {
|
||||
doInt(b ?: a)
|
||||
}
|
||||
doList(getList() ?: <!TYPE_INFERENCE_UPPER_BOUND_VIOLATED!>emptyListOfA<!>()) //should be an error
|
||||
doList(getList() ?: strangeList { doInt(it) }) //lambda was not analyzed
|
||||
}
|
||||
|
||||
|
||||
fun testDataFlowInfo1(a: Int?, b: Int?) {
|
||||
val c: Int = a ?: b!!
|
||||
doInt(c)
|
||||
b + 1
|
||||
}
|
||||
|
||||
fun testDataFlowInfo2(a: Int?, b: Int?) {
|
||||
doInt(a ?: b!!)
|
||||
b + 1
|
||||
}
|
||||
|
||||
fun testTypeMismatch(a: String?, b: Any) {
|
||||
doInt(<!TYPE_MISMATCH!>a<!> ?: <!TYPE_MISMATCH!>b<!>)
|
||||
}
|
||||
@@ -4793,6 +4793,11 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/resolve/specialConstructions"), Pattern.compile("^(.+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("elvisAsCall.kt")
|
||||
public void testElvisAsCall() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/specialConstructions/elvisAsCall.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("exclExclAsCall.kt")
|
||||
public void testExclExclAsCall() throws Exception {
|
||||
doTest("compiler/testData/diagnostics/tests/resolve/specialConstructions/exclExclAsCall.kt");
|
||||
|
||||
Reference in New Issue
Block a user