added UNKNOWN_EXPECTED_TYPE, NumberValueTypeConstructor
analyze function arguments with UNKNOWN_EXPECTED_TYPE (for several times in different traces yet) for number literals create type with NumberValueTypeConstructor with exact value, transform it to the corresponding type when resolve arguments (expected type is known) doesn't work properly for if, elvis operator, etc. (throws exceptions)
This commit is contained in:
+8
-7
@@ -24,17 +24,15 @@ import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.diagnostics.Errors;
|
||||
import org.jetbrains.jet.lang.psi.*;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.TypeResolver;
|
||||
import org.jetbrains.jet.lang.resolve.*;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.CallResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.CheckValueArgumentsMode;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.ResolveMode;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCallImpl;
|
||||
import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument;
|
||||
import org.jetbrains.jet.lang.resolve.constants.*;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
|
||||
import org.jetbrains.jet.lang.types.ErrorUtils;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.JetTypeInfo;
|
||||
@@ -50,7 +48,6 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.getRecordedTypeInfo;
|
||||
import static org.jetbrains.jet.lang.resolve.BindingContextUtils.recordExpressionType;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.*;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS;
|
||||
import static org.jetbrains.jet.lang.resolve.calls.CallResolverUtil.ResolveArgumentsMode.SKIP_FUNCTION_ARGUMENTS;
|
||||
@@ -73,7 +70,10 @@ public class ArgumentTypeResolver {
|
||||
this.expressionTypingServices = expressionTypingServices;
|
||||
}
|
||||
|
||||
public static boolean isSubtypeOfForArgumentType(@NotNull JetType subtype, @NotNull JetType supertype) {
|
||||
public static boolean isSubtypeOfForArgumentType(
|
||||
@NotNull JetType subtype,
|
||||
@NotNull JetType supertype
|
||||
) {
|
||||
if (subtype == PLACEHOLDER_FUNCTION_TYPE) {
|
||||
return isFunctionOrErrorType(supertype) || KotlinBuiltIns.getInstance().isAny(supertype); //todo function type extends
|
||||
}
|
||||
@@ -180,8 +180,9 @@ public class ArgumentTypeResolver {
|
||||
if (recordedTypeInfo != null) {
|
||||
return recordedTypeInfo;
|
||||
}
|
||||
ResolutionContext newContext = context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceResolveMode(ResolveMode.NESTED_CALL);
|
||||
ResolutionContext newContext = context.replaceExpectedType(TypeUtils.UNKNOWN_EXPECTED_TYPE).replaceResolveMode(ResolveMode.NESTED_CALL);
|
||||
JetTypeInfo result = expressionTypingServices.getTypeInfo(expression, newContext);
|
||||
|
||||
if (traceToCommitForCall != null) {
|
||||
traceToCommitForCall.commit();
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@ public class CandidateResolver {
|
||||
resultingType = type;
|
||||
}
|
||||
else {
|
||||
resultingType = autocastValueArgumentTypeIfPossible(expression, expectedType, type, trace, candidateCall.getDataFlowInfo());
|
||||
resultingType = autocastValueArgumentTypeIfPossible(expression, expectedType, type, newContext);
|
||||
if (resultingType == null) {
|
||||
resultingType = type;
|
||||
resultStatus = OTHER_ERROR;
|
||||
@@ -649,11 +649,10 @@ public class CandidateResolver {
|
||||
@NotNull JetExpression expression,
|
||||
@NotNull JetType expectedType,
|
||||
@NotNull JetType actualType,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull DataFlowInfo dataFlowInfo
|
||||
@NotNull ResolutionContext<?> context
|
||||
) {
|
||||
ExpressionReceiver receiverToCast = new ExpressionReceiver(expression, actualType);
|
||||
List<ReceiverValue> variants = AutoCastUtils.getAutoCastVariants(trace.getBindingContext(), dataFlowInfo, receiverToCast);
|
||||
List<ReceiverValue> variants = AutoCastUtils.getAutoCastVariants(context.trace.getBindingContext(), context.dataFlowInfo, receiverToCast);
|
||||
for (ReceiverValue receiverValue : variants) {
|
||||
JetType possibleType = receiverValue.getType();
|
||||
if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) {
|
||||
|
||||
+8
-5
@@ -40,8 +40,12 @@ public class CompileTimeConstantResolver {
|
||||
|
||||
@NotNull
|
||||
public CompileTimeConstant<?> getIntegerValue(@NotNull String text, @NotNull JetType expectedType) {
|
||||
return getIntegerValue(parseLongValue(text), expectedType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public CompileTimeConstant<?> getIntegerValue(@Nullable Long value, @NotNull JetType expectedType) {
|
||||
if (noExpectedType(expectedType)) {
|
||||
Long value = parseLongValue(text);
|
||||
if (value == null) {
|
||||
return OUT_OF_RANGE;
|
||||
}
|
||||
@@ -80,16 +84,15 @@ public class CompileTimeConstantResolver {
|
||||
JetType intType = builtIns.getIntType();
|
||||
JetType longType = builtIns.getLongType();
|
||||
if (typeChecker.isSubtypeOf(intType, expectedType)) {
|
||||
return getIntegerValue(text, intType);
|
||||
return getIntegerValue(value, intType);
|
||||
}
|
||||
else if (typeChecker.isSubtypeOf(longType, expectedType)) {
|
||||
return getIntegerValue(text, longType);
|
||||
return getIntegerValue(value, longType);
|
||||
}
|
||||
else {
|
||||
return new ErrorValue("An integer literal does not conform to the expected type " + expectedType);
|
||||
}
|
||||
}
|
||||
Long value = parseLongValue(text);
|
||||
|
||||
if (value != null && lowerBound <= value && value <= upperBound) {
|
||||
return create.apply(value);
|
||||
@@ -98,7 +101,7 @@ public class CompileTimeConstantResolver {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Long parseLongValue(String text) {
|
||||
public static Long parseLongValue(String text) {
|
||||
try {
|
||||
long value;
|
||||
if (text.startsWith("0x") || text.startsWith("0X")) {
|
||||
|
||||
@@ -16,16 +16,26 @@
|
||||
|
||||
package org.jetbrains.jet.lang.resolve.constants;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.jet.lang.psi.JetExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetQualifiedExpression;
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
||||
import org.jetbrains.jet.lang.resolve.BindingTrace;
|
||||
import org.jetbrains.jet.lang.resolve.calls.context.ResolutionContext;
|
||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.JetTypeInfo;
|
||||
import org.jetbrains.jet.lang.types.checker.JetTypeChecker;
|
||||
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
|
||||
import static org.jetbrains.jet.lang.diagnostics.Errors.ERROR_COMPILE_TIME_VALUE;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
|
||||
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.getDefaultType;
|
||||
import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.*;
|
||||
import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.BYTE;
|
||||
import static org.jetbrains.jet.lang.types.expressions.OperatorConventions.INT;
|
||||
@@ -63,4 +73,33 @@ public class ConstantUtils {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static JetType updateConstantValueType(
|
||||
@NotNull NumberValueTypeConstructor numberValueTypeConstructor,
|
||||
@NotNull JetType expectedType,
|
||||
@NotNull JetExpression expression,
|
||||
@NotNull ResolutionContext<?> context
|
||||
) {
|
||||
CompileTimeConstantResolver compileTimeConstantResolver = new CompileTimeConstantResolver();
|
||||
CompileTimeConstant<?> value = compileTimeConstantResolver.getIntegerValue(numberValueTypeConstructor.getValue(), expectedType);
|
||||
JetTypeInfo recordedTypeInfo = BindingContextUtils.getRecordedTypeInfo(expression, context.trace.getBindingContext());
|
||||
assert recordedTypeInfo != null : "Expression " + expression + " should have been analyzed";
|
||||
JetScope resolutionScope = context.trace.get(BindingContext.RESOLUTION_SCOPE, expression);
|
||||
assert resolutionScope != null : "Expression " + expression + " should have been analyzed";
|
||||
|
||||
JetType type;
|
||||
if (value instanceof ErrorValue) {
|
||||
ErrorValue errorValue = (ErrorValue) value;
|
||||
type = getDefaultType(expression.getNode().getElementType());
|
||||
if (!noExpectedType(context.expectedType) && JetTypeChecker.INSTANCE.isSubtypeOf(type, context.expectedType)) {
|
||||
context.trace.report(ERROR_COMPILE_TIME_VALUE.on(expression, errorValue.getMessage()));
|
||||
}
|
||||
}
|
||||
else {
|
||||
type = value.getType(KotlinBuiltIns.getInstance());
|
||||
}
|
||||
BindingContextUtils.recordExpressionType(expression, context.trace, resolutionScope,
|
||||
JetTypeInfo.create(type, recordedTypeInfo.getDataFlowInfo()));
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2010-2013 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.jet.lang.resolve.constants;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
|
||||
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
|
||||
import org.jetbrains.jet.lang.types.JetType;
|
||||
import org.jetbrains.jet.lang.types.TypeConstructor;
|
||||
import org.jetbrains.jet.lang.types.TypeProjection;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class NumberValueTypeConstructor implements TypeConstructor {
|
||||
private final Long value;
|
||||
|
||||
public NumberValueTypeConstructor(Long value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public Long getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<TypeParameterDescriptor> getParameters() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Collection<JetType> getSupertypes() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSealed() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDenotable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ClassifierDescriptor getDeclarationDescriptor() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnnotationDescriptor> getAnnotations() {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
NumberValueTypeConstructor type = (NumberValueTypeConstructor) o;
|
||||
|
||||
if (!value.equals(type.value)) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return value.hashCode();
|
||||
}
|
||||
}
|
||||
@@ -38,43 +38,53 @@ import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns;
|
||||
import java.util.*;
|
||||
|
||||
public class TypeUtils {
|
||||
public static final JetType NO_EXPECTED_TYPE = new JetType() {
|
||||
public static class SpecialType implements JetType {
|
||||
private final String name;
|
||||
|
||||
public SpecialType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public TypeConstructor getConstructor() {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public List<TypeProjection> getArguments() {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNullable() {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException(name);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public JetScope getMemberScope() {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<AnnotationDescriptor> getAnnotations() {
|
||||
throw new IllegalStateException();
|
||||
throw new IllegalStateException(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "NO_EXPECTED_TYPE";
|
||||
return name;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public static final JetType NO_EXPECTED_TYPE = new SpecialType("NO_EXPECTED_TYPE");
|
||||
|
||||
public static final JetType UNKNOWN_EXPECTED_TYPE = new SpecialType("UNKNOWN_EXPECTED_TYPE");
|
||||
|
||||
public static boolean noExpectedType(@NotNull JetType type) {
|
||||
return type == NO_EXPECTED_TYPE;
|
||||
return type == NO_EXPECTED_TYPE || type == UNKNOWN_EXPECTED_TYPE;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
|
||||
+14
@@ -67,6 +67,7 @@ import static org.jetbrains.jet.lang.resolve.BindingContext.*;
|
||||
import static org.jetbrains.jet.lang.resolve.DescriptorUtils.getStaticNestedClassesScope;
|
||||
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue.NO_RECEIVER;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.UNKNOWN_EXPECTED_TYPE;
|
||||
import static org.jetbrains.jet.lang.types.TypeUtils.noExpectedType;
|
||||
import static org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils.*;
|
||||
|
||||
@@ -109,6 +110,19 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
|
||||
KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance();
|
||||
CompileTimeConstantResolver compileTimeConstantResolver = context.getCompileTimeConstantResolver();
|
||||
|
||||
if (context.expectedType == UNKNOWN_EXPECTED_TYPE) {
|
||||
if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
|
||||
Long longValue = CompileTimeConstantResolver.parseLongValue(text);
|
||||
if (longValue != null) {
|
||||
JetTypeImpl numberValueType = new JetTypeImpl(
|
||||
Collections.<AnnotationDescriptor>emptyList(), new NumberValueTypeConstructor(longValue), false,
|
||||
Collections.<TypeProjection>emptyList(),
|
||||
ErrorUtils.createErrorScope("Scope for number value type (" + longValue + ")", true));
|
||||
return JetTypeInfo.create(numberValueType, context.dataFlowInfo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CompileTimeConstant<?> value;
|
||||
if (elementType == JetNodeTypes.INTEGER_CONSTANT) {
|
||||
value = compileTimeConstantResolver.getIntegerValue(text, context.expectedType);
|
||||
|
||||
Reference in New Issue
Block a user