diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java index 346ad0fc621..8ea35542bec 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/ArgumentTypeResolver.java @@ -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(); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java index d289fbdbdd3..72ab3c4fe8f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CandidateResolver.java @@ -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 variants = AutoCastUtils.getAutoCastVariants(trace.getBindingContext(), dataFlowInfo, receiverToCast); + List variants = AutoCastUtils.getAutoCastVariants(context.trace.getBindingContext(), context.dataFlowInfo, receiverToCast); for (ReceiverValue receiverValue : variants) { JetType possibleType = receiverValue.getType(); if (ArgumentTypeResolver.isSubtypeOfForArgumentType(possibleType, expectedType)) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantResolver.java index b208022a393..13ee1bb0a88 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/CompileTimeConstantResolver.java @@ -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")) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java index d65639bf492..0488c32a5ad 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/ConstantUtils.java @@ -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; + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/NumberValueTypeConstructor.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/NumberValueTypeConstructor.java new file mode 100644 index 00000000000..5c8ce8038b2 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/constants/NumberValueTypeConstructor.java @@ -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 getParameters() { + throw new IllegalStateException(); + } + + @NotNull + @Override + public Collection 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 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(); + } +} diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java index 0a19e607c20..a87f22e1388 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/TypeUtils.java @@ -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 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 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 diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java index 52d87dee014..4b0e35cf90c 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/expressions/BasicExpressionTypingVisitor.java @@ -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.emptyList(), new NumberValueTypeConstructor(longValue), false, + Collections.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);