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:
Svetlana Isakova
2013-07-11 13:57:13 +04:00
parent 8d0573f448
commit 517c24c8f6
7 changed files with 184 additions and 25 deletions
@@ -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)) {
@@ -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;
}
}
@@ -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
@@ -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);