bug with automatically casting mutable variables (KT-228) fixed
This commit is contained in:
@@ -12,6 +12,7 @@ import java.util.List;
|
|||||||
* @author abreslav
|
* @author abreslav
|
||||||
*/
|
*/
|
||||||
public class LocalVariableDescriptor extends VariableDescriptorImpl {
|
public class LocalVariableDescriptor extends VariableDescriptorImpl {
|
||||||
|
private boolean isVar;
|
||||||
public LocalVariableDescriptor(
|
public LocalVariableDescriptor(
|
||||||
@NotNull DeclarationDescriptor containingDeclaration,
|
@NotNull DeclarationDescriptor containingDeclaration,
|
||||||
@NotNull List<AnnotationDescriptor> annotations,
|
@NotNull List<AnnotationDescriptor> annotations,
|
||||||
@@ -19,6 +20,7 @@ public class LocalVariableDescriptor extends VariableDescriptorImpl {
|
|||||||
@Nullable JetType type,
|
@Nullable JetType type,
|
||||||
boolean mutable) {
|
boolean mutable) {
|
||||||
super(containingDeclaration, annotations, name, mutable ? type : null, type);
|
super(containingDeclaration, annotations, name, mutable ? type : null, type);
|
||||||
|
isVar = mutable;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@@ -31,4 +33,9 @@ public class LocalVariableDescriptor extends VariableDescriptorImpl {
|
|||||||
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
||||||
return visitor.visitLocalVariableDescriptor(this, data);
|
return visitor.visitLocalVariableDescriptor(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVar() {
|
||||||
|
return isVar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -94,4 +94,9 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
|
|||||||
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
public <R, D> R accept(DeclarationDescriptorVisitor<R, D> visitor, D data) {
|
||||||
return visitor.visitValueParameterDescriptor(this, data);
|
return visitor.visitValueParameterDescriptor(this, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isVar() {
|
||||||
|
return isVar;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,4 +29,6 @@ public interface VariableDescriptor extends DeclarationDescriptor {
|
|||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
VariableDescriptor substitute(TypeSubstitutor substitutor);
|
VariableDescriptor substitute(TypeSubstitutor substitutor);
|
||||||
|
|
||||||
|
boolean isVar();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.jet.lang.ErrorHandlerWithRegions;
|
import org.jetbrains.jet.lang.ErrorHandlerWithRegions;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
@@ -43,7 +44,7 @@ public interface BindingTrace {
|
|||||||
|
|
||||||
void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor);
|
void requireBackingField(@NotNull PropertyDescriptor propertyDescriptor);
|
||||||
|
|
||||||
void recordAutoCast(@NotNull JetExpression expression, @NotNull JetType type);
|
void recordAutoCast(@NotNull JetExpression expression, @NotNull JetType type, @NotNull VariableDescriptor variableDescriptor);
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
ErrorHandlerWithRegions getErrorHandler();
|
ErrorHandlerWithRegions getErrorHandler();
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import org.jetbrains.annotations.NotNull;
|
|||||||
import org.jetbrains.jet.lang.ErrorHandlerWithRegions;
|
import org.jetbrains.jet.lang.ErrorHandlerWithRegions;
|
||||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
import org.jetbrains.jet.lang.descriptors.PropertyDescriptor;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
|
||||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.*;
|
import org.jetbrains.jet.lang.psi.*;
|
||||||
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
|
||||||
@@ -17,8 +18,8 @@ public class BindingTraceAdapter implements BindingTrace {
|
|||||||
private final BindingTrace originalTrace;
|
private final BindingTrace originalTrace;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordAutoCast(@NotNull JetExpression expression, @NotNull JetType type) {
|
public void recordAutoCast(@NotNull JetExpression expression, @NotNull JetType type, @NotNull VariableDescriptor variableDescriptor) {
|
||||||
originalTrace.recordAutoCast(expression, type);
|
originalTrace.recordAutoCast(expression, type, variableDescriptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BindingTraceAdapter(BindingTrace originalTrace) {
|
public BindingTraceAdapter(BindingTrace originalTrace) {
|
||||||
|
|||||||
@@ -167,8 +167,13 @@ public class BindingTraceContext implements BindingContext, BindingTrace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordAutoCast(@NotNull JetExpression expression, @NotNull JetType type) {
|
public void recordAutoCast(@NotNull JetExpression expression, @NotNull JetType type, @NotNull VariableDescriptor variableDescriptor) {
|
||||||
safePut(autoCasts, expression, type);
|
if (variableDescriptor.isVar()) {
|
||||||
|
getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
safePut(autoCasts, expression, type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -763,29 +763,31 @@ public class JetTypeInferrer {
|
|||||||
semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
|
semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
|
||||||
return expressionType;
|
return expressionType;
|
||||||
}
|
}
|
||||||
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context);
|
|
||||||
if (variableDescriptor == null) return expressionType;
|
|
||||||
|
|
||||||
JetType enrichedType = null;
|
JetType enrichedType = null;
|
||||||
List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor));
|
|
||||||
Collections.reverse(possibleTypes);
|
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context);
|
||||||
for (JetType possibleType: possibleTypes) {
|
if (variableDescriptor != null) {
|
||||||
if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) {
|
|
||||||
enrichedType = possibleType;
|
List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor));
|
||||||
break;
|
Collections.reverse(possibleTypes);
|
||||||
|
for (JetType possibleType : possibleTypes) {
|
||||||
|
if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) {
|
||||||
|
enrichedType = possibleType;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (enrichedType == null) {
|
||||||
|
enrichedType = context.dataFlowInfo.getOutType(variableDescriptor);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (enrichedType == null) {
|
|
||||||
enrichedType = context.dataFlowInfo.getOutType(variableDescriptor);
|
|
||||||
}
|
}
|
||||||
if (enrichedType == null) {
|
if (enrichedType == null) {
|
||||||
enrichedType = expressionType;
|
enrichedType = expressionType;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!semanticServices.getTypeChecker().isSubtypeOf(enrichedType, context.expectedType)) {
|
if (variableDescriptor == null || !semanticServices.getTypeChecker().isSubtypeOf(enrichedType, context.expectedType)) {
|
||||||
context.trace.getErrorHandler().typeMismatch(expression, context.expectedType, expressionType);
|
context.trace.getErrorHandler().typeMismatch(expression, context.expectedType, expressionType);
|
||||||
} else {
|
} else {
|
||||||
context.trace.recordAutoCast(expression, context.expectedType);
|
context.trace.recordAutoCast(expression, context.expectedType, variableDescriptor);
|
||||||
}
|
}
|
||||||
return enrichedType;
|
return enrichedType;
|
||||||
}
|
}
|
||||||
@@ -2120,7 +2122,7 @@ public class JetTypeInferrer {
|
|||||||
selectorReturnType = getSelectorReturnType(possibleType, selectorExpression, context);
|
selectorReturnType = getSelectorReturnType(possibleType, selectorExpression, context);
|
||||||
if (selectorReturnType != null) {
|
if (selectorReturnType != null) {
|
||||||
regionToCommit = errorHandler.closeAndReturnCurrentRegion();
|
regionToCommit = errorHandler.closeAndReturnCurrentRegion();
|
||||||
context.trace.recordAutoCast(receiverExpression, possibleType);
|
context.trace.recordAutoCast(receiverExpression, possibleType, variableDescriptor);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -229,6 +229,25 @@ fun mergeAutocasts(a: Any?) {
|
|||||||
is String, is Any => a.<error>compareTo</error>("")
|
is String, is Any => a.<error>compareTo</error>("")
|
||||||
}
|
}
|
||||||
if (a is String && a is Any) {
|
if (a is String && a is Any) {
|
||||||
val i: Int = <info descr="Automatically cast to String">a</info>.length
|
val i: Int = <info descr="Automatically cast to String">a</info>.compareTo("")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//mutability
|
||||||
|
fun f(): String {
|
||||||
|
var a: Any = 11
|
||||||
|
if (a is String) {
|
||||||
|
val i: String = <error>a</error>
|
||||||
|
<error>a</error>.compareTo("f")
|
||||||
|
val f: Function0<String> = { <error>a</error> }
|
||||||
|
return <error>a</error>
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
fun foo(var a: Any): Int {
|
||||||
|
if (a is Int) {
|
||||||
|
return <error>a</error>
|
||||||
|
}
|
||||||
|
return 1
|
||||||
}
|
}
|
||||||
@@ -83,7 +83,7 @@ public class JetTestUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void recordAutoCast(@NotNull JetExpression expression, @NotNull JetType type) {
|
public void recordAutoCast(@NotNull JetExpression expression, @NotNull JetType type, @NotNull VariableDescriptor variableDescriptor) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user