Refactoring done, something broken in label resolution

This commit is contained in:
Andrey Breslav
2011-10-14 13:23:01 +04:00
parent 3894eff5f2
commit bca8e84deb
39 changed files with 3246 additions and 3078 deletions
@@ -2,10 +2,12 @@ package org.jetbrains.jet.lang;
import com.intellij.openapi.project.Project;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
import org.jetbrains.jet.lang.types.JetStandardLibrary;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import org.jetbrains.jet.lang.types.expressions.ExpressionTyperServices;
/**
* @author abreslav
@@ -44,13 +46,12 @@ public class JetSemanticServices {
}
@NotNull
public JetTypeInferrer.Services getTypeInferrerServices(@NotNull BindingTrace trace) {
return new JetTypeInferrer(this).getServices(trace);
public ExpressionTyperServices getTypeInferrerServices(@NotNull BindingTrace trace) {
return new ExpressionTyperServices(this, trace);
}
@NotNull
public JetTypeChecker getTypeChecker() {
return typeChecker;
}
}
@@ -10,7 +10,7 @@ import org.jetbrains.jet.lang.resolve.BindingContextUtils;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInferrer;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
@@ -216,7 +216,7 @@ public class JetControlFlowProcessor {
builder.unsupported(expression); // TODO
}
}
else if (JetTypeInferrer.assignmentOperationNames.containsKey(operationType)) {
else if (OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
JetExpression left = JetPsiUtil.deparenthesize(expression.getLeft());
if (left != null) {
value(left, false);
@@ -8,6 +8,7 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import org.jetbrains.jet.util.lazy.LazyValue;
import java.util.Collections;
import java.util.List;
@@ -4,21 +4,23 @@ import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.JetAnnotationEntry;
import org.jetbrains.jet.lang.psi.JetExpression;
import org.jetbrains.jet.lang.psi.JetModifierList;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collections;
import java.util.List;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
/**
* @author abreslav
@@ -34,7 +36,7 @@ public class AnnotationResolver {
this.trace = trace;
// this.typeInferrer = new JetTypeInferrer(JetFlowInformationProvider.THROW_EXCEPTION, semanticServices);
// this.services = typeInferrer.getServices(this.trace);
this.callResolver = new CallResolver(semanticServices, new JetTypeInferrer(semanticServices), DataFlowInfo.getEmpty());
this.callResolver = new CallResolver(semanticServices, DataFlowInfo.getEmpty());
}
@NotNull
@@ -6,15 +6,17 @@ import com.intellij.lang.ASTNode;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.Queue;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.expressions.ExpressionTyperServices;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.util.lazy.ReenteringLazyValueComputationException;
import org.jetbrains.jet.util.slicedmap.WritableSlice;
import java.util.*;
@@ -23,7 +25,7 @@ import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.DEFERRED_TYPE;
import static org.jetbrains.jet.lang.resolve.BindingContext.DEFERRED_TYPES;
import static org.jetbrains.jet.lang.resolve.BindingContext.DeferredTypeKey.DEFERRED_TYPE_KEY;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
/**
* @author abreslav
@@ -125,7 +127,7 @@ public class BodyResolver {
final JetScope scopeForConstructor = primaryConstructor == null
? null
: getInnerScopeForConstructor(primaryConstructor, descriptor.getScopeForMemberResolution(), true);
final JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); // TODO : flow
final ExpressionTyperServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors); // TODO : flow
final Map<JetTypeReference, JetType> supertypes = Maps.newLinkedHashMap();
JetVisitorVoid visitor = new JetVisitorVoid() {
@@ -292,7 +294,7 @@ public class BodyResolver {
ConstructorDescriptor primaryConstructor = classDescriptor.getUnsubstitutedPrimaryConstructor();
assert primaryConstructor != null;
final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(createFieldAssignTrackingTrace()); // TODO : flow
ExpressionTyperServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(createFieldAssignTrackingTrace()); // TODO : flow
for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), NO_EXPECTED_TYPE);
}
@@ -318,7 +320,7 @@ public class BodyResolver {
private void resolveSecondaryConstructorBody(JetConstructor declaration, final ConstructorDescriptor descriptor, final JetScope declaringScope) {
final JetScope functionInnerScope = getInnerScopeForConstructor(descriptor, declaringScope, false);
final JetTypeInferrer.Services typeInferrerForInitializers = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
final ExpressionTyperServices typeInferrerForInitializers = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
JetClass containingClass = PsiTreeUtil.getParentOfType(declaration, JetClass.class);
assert containingClass != null : "This must be guaranteed by the parser";
@@ -382,7 +384,7 @@ public class BodyResolver {
if (bodyExpression != null) {
//context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression);
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(declaration, bodyExpression);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
ExpressionTyperServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
typeInferrer.checkFunctionReturnType(functionInnerScope, declaration, descriptor, JetStandardClasses.getUnitType());
}
@@ -520,7 +522,7 @@ public class BodyResolver {
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(property, initializer); // TODO : flow JET-15
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
ExpressionTyperServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(traceForConstructors);
JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, NO_EXPECTED_TYPE);
JetType expectedType = propertyDescriptor.getInType();
@@ -556,12 +558,12 @@ public class BodyResolver {
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression != null) {
//JetFlowInformationProvider flowInformationProvider = context.getClassDescriptorResolver().computeFlowData(function.asElement(), bodyExpression);
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
ExpressionTyperServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
typeInferrer.checkFunctionReturnType(declaringScope, function, functionDescriptor);
}
JetTypeInferrer.Services typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
ExpressionTyperServices typeInferrer = context.getSemanticServices().getTypeInferrerServices(trace);
List<JetParameter> valueParameters = function.getValueParameters();
for (int i = 0; i < valueParameters.size(); i++) {
ValueParameterDescriptor valueParameterDescriptor = functionDescriptor.getValueParameters().get(i);
@@ -22,6 +22,8 @@ import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.util.lazy.LazyValue;
import org.jetbrains.jet.util.lazy.LazyValueWithDefault;
import java.util.*;
@@ -541,7 +543,7 @@ public class ClassDescriptorResolver {
@Override
protected JetType compute() {
//JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer);
return semanticServices.getTypeInferrerServices(trace).safeGetType(scope, initializer, JetTypeInferrer.NO_EXPECTED_TYPE);
return semanticServices.getTypeInferrerServices(trace).safeGetType(scope, initializer, TypeUtils.NO_EXPECTED_TYPE);
}
};
if (allowDeferred) {
@@ -10,22 +10,21 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInferrer;
import org.jetbrains.jet.lang.types.expressions.ExpressionTyperServices;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
/**
* @author svtk
*/
public class ControlFlowAnalyzer {
private TopDownAnalysisContext context;
private JetTypeInferrer.Services typeInferrer;
private ExpressionTyperServices typeInferrer;
public ControlFlowAnalyzer(TopDownAnalysisContext context) {
this.context = context;
@@ -8,7 +8,6 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiNameIdentifierOwner;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
@@ -16,6 +15,7 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.resolve.scopes.WriteThroughScope;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.expressions.ExpressionTyperServices;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
@@ -218,7 +218,7 @@ public class TypeHierarchyResolver {
if (importDirective.isAllUnder()) {
JetExpression importedReference = importDirective.getImportedReference();
if (importedReference != null) {
JetTypeInferrer.Services typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace());
ExpressionTyperServices typeInferrerServices = context.getSemanticServices().getTypeInferrerServices(context.getTrace());
JetType type = typeInferrerServices.getTypeWithNamespaces(namespaceScope, importedReference);
if (type != null) {
namespaceScope.importScope(type.getMemberScope());
@@ -12,6 +12,7 @@ import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.LazyScopeAdapter;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.util.lazy.LazyValue;
import java.util.ArrayList;
import java.util.Collections;
@@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.resolve.calls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.DataFlowInfo;
import java.util.Collections;
import java.util.List;
@@ -3,7 +3,6 @@ package org.jetbrains.jet.lang.resolve.calls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.DataFlowInfo;
import java.util.List;
@@ -11,7 +11,6 @@ import org.jetbrains.jet.lang.psi.JetThisExpression;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.receivers.*;
import org.jetbrains.jet.lang.types.DataFlowInfo;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
@@ -1,4 +1,4 @@
package org.jetbrains.jet.lang.types;
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.Lists;
import com.intellij.lang.ASTNode;
@@ -15,6 +15,8 @@ import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.expressions.ExpressionTyperServices;
import org.jetbrains.jet.lang.types.expressions.OperatorConventions;
import org.jetbrains.jet.lang.types.inference.ConstraintSystem;
import org.jetbrains.jet.lexer.JetTokens;
@@ -26,20 +28,17 @@ import static org.jetbrains.jet.lang.resolve.calls.ResolutionStatus.*;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_CANDIDATE;
import static org.jetbrains.jet.lang.resolve.calls.ResolvedCall.MAP_TO_RESULT;
import static org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor.NO_RECEIVER;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE;
/**
* @author abreslav
*/
public class CallResolver {
private final JetTypeInferrer typeInferrer;
private final JetSemanticServices semanticServices;
private final OverloadingConflictResolver overloadingConflictResolver;
private final DataFlowInfo dataFlowInfo;
public CallResolver(JetSemanticServices semanticServices, JetTypeInferrer typeInferrer, DataFlowInfo dataFlowInfo) {
this.typeInferrer = typeInferrer;
public CallResolver(JetSemanticServices semanticServices, DataFlowInfo dataFlowInfo) {
this.semanticServices = semanticServices;
this.overloadingConflictResolver = new OverloadingConflictResolver(semanticServices);
this.dataFlowInfo = dataFlowInfo;
@@ -301,7 +300,7 @@ public class CallResolver {
if (callElement instanceof JetBinaryExpression) {
JetBinaryExpression binaryExpression = (JetBinaryExpression) callElement;
JetSimpleNameExpression operationReference = binaryExpression.getOperationReference();
String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? operationReference.getText() : JetTypeInferrer.getNameForOperationSymbol(operationReference.getReferencedNameElementType());
String operationString = operationReference.getReferencedNameElementType() == JetTokens.IDENTIFIER ? operationReference.getText() : OperatorConventions.getNameForOperationSymbol(operationReference.getReferencedNameElementType());
trace.report(UNSAFE_INFIX_CALL.on(reference, binaryExpression.getLeft().getText(), operationString, binaryExpression.getRight().getText()));
}
else {
@@ -385,7 +384,7 @@ public class CallResolver {
for (JetExpression expression : valueArgument.getArgumentExpressions()) {
// JetExpression expression = valueArgument.getArgumentExpression();
// TODO : more attempts, with different expected types
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace);
ExpressionTyperServices temporaryServices = new ExpressionTyperServices(semanticServices, temporaryTrace);
JetType type = temporaryServices.getType(scope, expression, NO_EXPECTED_TYPE);
if (type != null) {
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
@@ -510,15 +509,16 @@ public class CallResolver {
}
private void checkTypesWithNoCallee(BindingTrace trace, JetScope scope, Call call) {
ExpressionTyperServices typeInferrerServices = new ExpressionTyperServices(semanticServices, trace);
for (ValueArgument valueArgument : call.getValueArguments()) {
JetExpression argumentExpression = valueArgument.getArgumentExpression();
if (argumentExpression != null) {
typeInferrer.getServices(trace).getType(scope, argumentExpression, NO_EXPECTED_TYPE);
typeInferrerServices.getType(scope, argumentExpression, NO_EXPECTED_TYPE);
}
}
for (JetExpression expression : call.getFunctionLiteralArguments()) {
typeInferrer.getServices(trace).getType(scope, expression, NO_EXPECTED_TYPE);
typeInferrerServices.getType(scope, expression, NO_EXPECTED_TYPE);
}
for (JetTypeProjection typeProjection : call.getTypeArguments()) {
@@ -602,7 +602,7 @@ public class CallResolver {
List<JetExpression> argumentExpressions = resolvedArgument.getArgumentExpressions();
for (JetExpression argumentExpression : argumentExpressions) {
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(candidateCall.getTrace());
ExpressionTyperServices temporaryServices = new ExpressionTyperServices(semanticServices, candidateCall.getTrace());
JetType type = temporaryServices.getType(scope, argumentExpression, parameterType);
if (type == null) {
candidateCall.argumentHasNoType();
@@ -1,10 +1,12 @@
package org.jetbrains.jet.lang.types;
package org.jetbrains.jet.lang.resolve.calls;
import com.google.common.collect.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import org.jetbrains.jet.util.CommonSuppliers;
import java.util.*;
@@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.CallableDescriptor;
import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.types.DataFlowInfo;
import java.util.Collection;
@@ -10,7 +10,6 @@ import org.jetbrains.jet.lang.psi.Call;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.DataFlowInfo;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import org.jetbrains.jet.lang.types.NamespaceType;
@@ -8,7 +8,6 @@ import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.CallMaker;
import java.util.List;
import java.util.Map;
@@ -260,7 +260,7 @@ public class CompileTimeConstantResolver {
}
private boolean noExpectedType(JetType expectedType) {
return expectedType == JetTypeInferrer.NO_EXPECTED_TYPE || JetStandardClasses.isUnit(expectedType);
return expectedType == TypeUtils.NO_EXPECTED_TYPE || JetStandardClasses.isUnit(expectedType);
}
}
@@ -2,7 +2,7 @@ package org.jetbrains.jet.lang.resolve.scopes;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.AbstractScopeAdapter;
import org.jetbrains.jet.lang.types.LazyValue;
import org.jetbrains.jet.util.lazy.LazyValue;
/**
* @author abreslav
@@ -4,6 +4,8 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.util.lazy.LazyValue;
import org.jetbrains.jet.util.lazy.ReenteringLazyValueComputationException;
import java.util.List;
@@ -1,19 +0,0 @@
package org.jetbrains.jet.lang.types;
/**
* @author abreslav
*/
public class DfsNodeHandler<R> {
public void beforeChildren(JetType current) {
}
public void afterChildren(JetType current) {
}
public R result() {
return null;
}
}
@@ -173,7 +173,7 @@ public class ErrorUtils {
}
public static boolean isErrorType(@NotNull JetType type) {
return type != JetTypeInferrer.NO_EXPECTED_TYPE &&(
return type != TypeUtils.NO_EXPECTED_TYPE &&(
(type instanceof DeferredType && ((DeferredType) type).getActualType() == null) ||
type instanceof ErrorTypeImpl ||
isError(type.getConstructor()));
@@ -598,4 +598,20 @@ public class JetTypeChecker {
return result;
}
}
private static class DfsNodeHandler<R> {
public void beforeChildren(JetType current) {
}
public void afterChildren(JetType current) {
}
public R result() {
return null;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -17,6 +17,75 @@ import java.util.*;
* @author abreslav
*/
public class TypeUtils {
public static final JetType FORBIDDEN = new JetType() {
@NotNull
@Override
public TypeConstructor getConstructor() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public List<TypeProjection> getArguments() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public boolean isNullable() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public JetScope getMemberScope() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public List<AnnotationDescriptor> getAnnotations() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public String toString() {
return "FORBIDDEN";
}
};
public static final JetType NO_EXPECTED_TYPE = new JetType() {
@NotNull
@Override
public TypeConstructor getConstructor() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public List<TypeProjection> getArguments() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public boolean isNullable() {
throw new UnsupportedOperationException(); // TODO
}
@NotNull
@Override
public JetScope getMemberScope() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public List<AnnotationDescriptor> getAnnotations() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public String toString() {
return "NO_EXPECTED_TYPE";
}
};
public static JetType makeNullable(@NotNull JetType type) {
return makeNullableAsSpecified(type, true);
}
@@ -0,0 +1,9 @@
package org.jetbrains.jet.lang.types.expressions;
/**
* @author abreslav
*/
public enum CoercionStrategy {
NO_COERCION,
COERCION_TO_UNIT
}
@@ -0,0 +1,484 @@
package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptorUtil;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.diagnostics.Diagnostic;
import org.jetbrains.jet.lang.diagnostics.DiagnosticWithPsiElement;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.resolve.calls.AutoCastUtils;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.WritableScopeImpl;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.TYPE_MISMATCH;
import static org.jetbrains.jet.lang.resolve.BindingContext.*;
/**
* @author abreslav
*/
public class ExpressionTyperServices {
private final JetSemanticServices semanticServices;
private final BindingTrace trace;
private final ExpressionTyperVisitor expressionTyperVisitor;
private final CallResolver callResolver;
public ExpressionTyperServices(JetSemanticServices semanticServices, BindingTrace trace) {
this.semanticServices = semanticServices;
this.trace = trace;
this.expressionTyperVisitor = new ExpressionTyperVisitor();
this.callResolver = new CallResolver(semanticServices, DataFlowInfo.getEmpty());
}
public ExpressionTyperVisitorWithWritableScope newTypeInferrerVisitorWithWritableScope(WritableScope scope) {
return new ExpressionTyperVisitorWithWritableScope(scope);
}
@NotNull
public JetType safeGetType(@NotNull JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType) {
JetType type = getType(scope, expression, expectedType);
if (type != null) {
return type;
}
return ErrorUtils.createErrorType("Type for " + expression.getText());
}
@Nullable
public JetType getType(@NotNull final JetScope scope, @NotNull JetExpression expression, @NotNull JetType expectedType) {
return expressionTyperVisitor.getType(expression, ExpressionTypingContext.newRootContext(semanticServices, trace, scope, DataFlowInfo.getEmpty(), expectedType, TypeUtils.FORBIDDEN));
}
public JetType getTypeWithNamespaces(@NotNull final JetScope scope, @NotNull JetExpression expression) {
return ExpressionTyperVisitorWithNamespaces.INSTANCE.getType(expression, ExpressionTypingContext.newRootContext(semanticServices, trace, scope, DataFlowInfo.getEmpty(), TypeUtils.NO_EXPECTED_TYPE, TypeUtils.NO_EXPECTED_TYPE));
}
public CallResolver getCallResolver() {
return callResolver;
}
// TODO JetElement -> JetWhenConditionCall || JetQualifiedExpression
// private void checkNullSafety(@Nullable JetType receiverType, @NotNull ASTNode operationTokenNode, @Nullable FunctionDescriptor callee, @NotNull JetElement element) {
// if (receiverType != null && callee != null) {
// boolean namespaceType = receiverType instanceof NamespaceType;
// boolean nullableReceiver = !namespaceType && receiverType.isNullable();
// ReceiverDescriptor calleeReceiver = callee.getReceiverParameter();
// boolean calleeForbidsNullableReceiver = !calleeReceiver.exists() || !calleeReceiver.getType().isNullable();
//
// IElementType operationSign = operationTokenNode.getElementType();
// if (nullableReceiver && calleeForbidsNullableReceiver && operationSign == JetTokens.DOT) {
//// trace.getErrorHandler().genericError(operationTokenNode, "Only safe calls (?.) are allowed on a nullable receiver of type " + receiverType);
// trace.report(UNSAFE_CALL.on(operationTokenNode, receiverType));
// }
// else if ((!nullableReceiver || !calleeForbidsNullableReceiver) && operationSign == JetTokens.SAFE_ACCESS) {
// if (namespaceType) {
//// trace.getErrorHandler().genericError(operationTokenNode, "Safe calls are not allowed on namespaces");
// trace.report(SAFE_CALLS_ARE_NOT_ALLOWED_ON_NAMESPACES.on(operationTokenNode));
// }
// else {
//// trace.getErrorHandler().genericWarning(operationTokenNode, "Unnecessary safe call on a non-null receiver of type " + receiverType);
//
// trace.report(UNNECESSARY_SAFE_CALL.on(element, operationTokenNode, receiverType));
//
// }
// }
// }
// }
public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) {
checkFunctionReturnType(outerScope, function, functionDescriptor, DataFlowInfo.getEmpty());
}
/*package*/ void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor, DataFlowInfo dataFlowInfo) {
JetType expectedReturnType = functionDescriptor.getReturnType();
if (!function.hasBlockBody() && !function.hasDeclaredReturnType()) {
expectedReturnType = TypeUtils.NO_EXPECTED_TYPE;
}
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
checkFunctionReturnType(functionInnerScope, function, functionDescriptor, expectedReturnType, dataFlowInfo);
// Map<JetElement, JetType> typeMap = collectReturnedExpressionsWithTypes(outerScope, function, functionDescriptor, expectedReturnType);
// if (typeMap.isEmpty()) {
// return; // The function returns Nothing
// }
// for (Map.Entry<JetElement, JetType> entry : typeMap.entrySet()) {
// JetType actualType = entry.castValue();
// JetElement element = entry.getKey();
// JetTypeChecker typeChecker = semanticServices.getTypeChecker();
// if (!typeChecker.isSubtypeOf(actualType, expectedReturnType)) {
// if (typeChecker.isConvertibleBySpecialConversion(actualType, expectedReturnType)) {
// if (expectedReturnType.getConstructor().equals(JetStandardClasses.getUnitType().getConstructor())
// && element.getParent() instanceof JetReturnExpression) {
// context.trace.getErrorHandler().genericError(element.getNode(), "This function must return a value of type Unit");
// }
// }
// else {
// if (element == function) {
// JetExpression bodyExpression = function.getBodyExpression();
// assert bodyExpression != null;
// context.trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType);
// }
// else if (element instanceof JetExpression) {
// JetExpression expression = (JetExpression) element;
// context.trace.report(TYPE_MISMATCH.on(expression, expectedReturnType, actualType));
// }
// else {
// context.trace.getErrorHandler().genericError(element.getNode(), "This function must return a value of type " + expectedReturnType);
// }
// }
// }
// }
}
public void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, @NotNull final JetType expectedReturnType) {
checkFunctionReturnType(functionInnerScope, function, functionDescriptor, expectedReturnType, DataFlowInfo.getEmpty());
}
/*package*/ void checkFunctionReturnType(JetScope functionInnerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor, @NotNull final JetType expectedReturnType, @NotNull DataFlowInfo dataFlowInfo) {
JetExpression bodyExpression = function.getBodyExpression();
if (bodyExpression == null) return;
final boolean blockBody = function.hasBlockBody();
final ExpressionTypingContext context =
blockBody
? ExpressionTypingContext.newRootContext(semanticServices, trace, functionInnerScope, dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, expectedReturnType)
: ExpressionTypingContext.newRootContext(semanticServices, trace, functionInnerScope, dataFlowInfo, expectedReturnType, TypeUtils.FORBIDDEN);
if (function instanceof JetFunctionLiteralExpression) {
JetFunctionLiteralExpression functionLiteralExpression = (JetFunctionLiteralExpression) function;
getBlockReturnedType(functionInnerScope, functionLiteralExpression.getBodyExpression(), CoercionStrategy.COERCION_TO_UNIT, context);
}
else {
expressionTyperVisitor.getType(bodyExpression, context);
}
// List<JetElement> unreachableElements = Lists.newArrayList();
// flowInformationProvider.collectUnreachableExpressions(function.asElement(), unreachableElements);
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
// final Set<JetElement> rootUnreachableElements = JetPsiUtil.findRootExpressions(unreachableElements);
// TODO : (return 1) || (return 2) -- only || and right of it is unreachable
// TODO : try {return 1} finally {return 2}. Currently 'return 1' is reported as unreachable,
// though it'd better be reported more specifically
// for (JetElement element : rootUnreachableElements) {
// //trace.report(UNREACHABLE_CODE.on(element));
// }
// List<JetExpression> returnedExpressions = Lists.newArrayList();
// flowInformationProvider.collectReturnExpressions(function.asElement(), returnedExpressions);
// boolean nothingReturned = returnedExpressions.isEmpty();
//returnedExpressions.remove(function); // This will be the only "expression" if the body is empty
// Map<JetExpression, JetType> typeMap = collectReturnedExpressionsWithTypes(trace, functionInnerScope, function, functionDescriptor);
// Set<JetExpression> returnedExpressions = typeMap.keySet();
//
//
// if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty()) {
// trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType));
// }
// if (expectedReturnType != NO_EXPECTED_TYPE && !JetStandardClasses.isUnit(expectedReturnType) && returnedExpressions.isEmpty() && !nothingReturned) {
//// trace.getErrorHandler().genericError(bodyExpression.getNode(), "This function must return a value of type " + expectedReturnType);
// trace.report(RETURN_TYPE_MISMATCH.on(bodyExpression, expectedReturnType));
// }
//
// for (JetExpression returnedExpression : returnedExpressions) {
// returnedExpression.accept(new JetVisitorVoid() {
// @Override
// public void visitReturnExpression(JetReturnExpression expression) {
// if (!blockBody) {
//// trace.getErrorHandler().genericError(expression.getNode(), "Returns are not allowed for functions with expression body. Use block body in '{...}'");
// trace.report(RETURN_IN_FUNCTION_WITH_EXPRESSION_BODY.on(expression));
// }
// }
//
// @Override
// public void visitExpression(JetExpression expression) {
// if (blockBody && !JetStandardClasses.isUnit(expectedReturnType) && !rootUnreachableElements.contains(expression)) {
// //TODO move to pseudocode
// JetType type = expressionTyperVisitor.getType(expression, context.replaceExpectedType(NO_EXPECTED_TYPE));
// if (type == null || !JetStandardClasses.isNothing(type)) {
//// trace.getErrorHandler().genericError(expression.getNode(), "A 'return' expression required in a function with a block body ('{...}')");
// trace.report(NO_RETURN_IN_FUNCTION_WITH_BLOCK_BODY.on(expression));
// }
// }
// }
// });
// }
}
@Nullable
/*package*/ JetType getBlockReturnedType(@NotNull JetScope outerScope, @NotNull JetBlockExpression expression, @NotNull CoercionStrategy coercionStrategyForLastExpression, ExpressionTypingContext context) {
List<JetElement> block = expression.getStatements();
if (block.isEmpty()) {
return checkType(JetStandardClasses.getUnitType(), expression, context);
}
DeclarationDescriptor containingDescriptor = outerScope.getContainingDeclaration();
WritableScope scope = new WritableScopeImpl(outerScope, containingDescriptor, new TraceBasedRedeclarationHandler(context.trace)).setDebugName("getBlockReturnedType");
return getBlockReturnedTypeWithWritableScope(scope, block, coercionStrategyForLastExpression, context);
}
@NotNull
public JetType inferFunctionReturnType(@NotNull JetScope outerScope, JetDeclarationWithBody function, FunctionDescriptor functionDescriptor) {
Map<JetExpression, JetType> typeMap = collectReturnedExpressionsWithTypes(trace, outerScope, function, functionDescriptor);
Collection<JetType> types = typeMap.values();
return types.isEmpty()
? JetStandardClasses.getNothingType()
: semanticServices.getTypeChecker().commonSupertype(types);
}
private Map<JetExpression, JetType> collectReturnedExpressionsWithTypes(
final @NotNull BindingTrace trace,
JetScope outerScope,
final JetDeclarationWithBody function,
FunctionDescriptor functionDescriptor) {
JetExpression bodyExpression = function.getBodyExpression();
assert bodyExpression != null;
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(outerScope, functionDescriptor, trace);
expressionTyperVisitor.getType(bodyExpression, ExpressionTypingContext.newRootContext(semanticServices, trace, functionInnerScope, DataFlowInfo.getEmpty(), TypeUtils.NO_EXPECTED_TYPE, TypeUtils.FORBIDDEN));
//todo function literals
final Collection<JetExpression> returnedExpressions = new ArrayList<JetExpression>();
if (function.hasBlockBody()) {
//now this code is never invoked!, it should be invoked for inference of return type of function literal with local returns
bodyExpression.visit(new JetTreeVisitor<JetDeclarationWithBody>() {
@Override
public Void visitReturnExpression(JetReturnExpression expression, JetDeclarationWithBody outerFunction) {
JetSimpleNameExpression targetLabel = expression.getTargetLabel();
PsiElement element = targetLabel != null ? trace.get(LABEL_TARGET, targetLabel) : null;
if (element == function || (targetLabel == null && outerFunction == function)) {
returnedExpressions.add(expression);
}
return null;
}
@Override
public Void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression, JetDeclarationWithBody outerFunction) {
return super.visitFunctionLiteralExpression(expression, expression.getFunctionLiteral());
}
@Override
public Void visitNamedFunction(JetNamedFunction function, JetDeclarationWithBody outerFunction) {
return super.visitNamedFunction(function, function);
}
}, function);
}
else {
returnedExpressions.add(bodyExpression);
}
Map<JetExpression, JetType> typeMap = new HashMap<JetExpression, JetType>();
for (JetExpression returnedExpression : returnedExpressions) {
JetType cachedType = trace.getBindingContext().get(BindingContext.EXPRESSION_TYPE, returnedExpression);
trace.record(STATEMENT, returnedExpression, false);
if (cachedType != null) {
typeMap.put(returnedExpression, cachedType);
}
}
return typeMap;
}
/*package*/ JetType getBlockReturnedTypeWithWritableScope(@NotNull WritableScope scope, @NotNull List<? extends JetElement> block, @NotNull CoercionStrategy coercionStrategyForLastExpression, ExpressionTypingContext context) {
if (block.isEmpty()) {
return JetStandardClasses.getUnitType();
}
ExpressionTyperVisitorWithWritableScope blockLevelVisitor = newTypeInferrerVisitorWithWritableScope(scope);
ExpressionTypingContext newContext = ExpressionTypingContext.newRootContext(semanticServices, trace, scope, context.dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, context.expectedReturnType);
JetType result = null;
for (Iterator<? extends JetElement> iterator = block.iterator(); iterator.hasNext(); ) {
final JetElement statement = iterator.next();
trace.record(STATEMENT, statement);
final JetExpression statementExpression = (JetExpression) statement;
//TODO constructor assert context.expectedType != FORBIDDEN : ""
if (!iterator.hasNext()) {
if (context.expectedType != TypeUtils.NO_EXPECTED_TYPE) {
if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT && JetStandardClasses.isUnit(context.expectedType)) {
// This implements coercion to Unit
TemporaryBindingTrace temporaryTraceExpectingUnit = TemporaryBindingTrace.create(trace);
final boolean[] mismatch = new boolean[1];
ObservableBindingTrace errorInterceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceExpectingUnit, statementExpression, mismatch);
newContext = ExpressionTypingContext.newRootContext(semanticServices, errorInterceptingTrace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
result = blockLevelVisitor.getType(statementExpression, newContext);
if (mismatch[0]) {
TemporaryBindingTrace temporaryTraceNoExpectedType = TemporaryBindingTrace.create(trace);
mismatch[0] = false;
ObservableBindingTrace interceptingTrace = makeTraceInterceptingTypeMismatch(temporaryTraceNoExpectedType, statementExpression, mismatch);
newContext = ExpressionTypingContext.newRootContext(semanticServices, interceptingTrace, scope, newContext.dataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, context.expectedReturnType);
result = blockLevelVisitor.getType(statementExpression, newContext);
if (mismatch[0]) {
temporaryTraceExpectingUnit.commit();
}
else {
temporaryTraceNoExpectedType.commit();
}
}
else {
temporaryTraceExpectingUnit.commit();
}
}
else {
newContext = ExpressionTypingContext.newRootContext(semanticServices, trace, scope, newContext.dataFlowInfo, context.expectedType, context.expectedReturnType);
result = blockLevelVisitor.getType(statementExpression, newContext);
}
}
else {
result = blockLevelVisitor.getType(statementExpression, newContext);
if (coercionStrategyForLastExpression == CoercionStrategy.COERCION_TO_UNIT) {
boolean mightBeUnit = false;
if (statementExpression instanceof JetDeclaration) {
mightBeUnit = true;
}
if (statementExpression instanceof JetBinaryExpression) {
JetBinaryExpression binaryExpression = (JetBinaryExpression) statementExpression;
IElementType operationType = binaryExpression.getOperationToken();
if (operationType == JetTokens.EQ || OperatorConventions.ASSIGNMENT_OPERATIONS.containsKey(operationType)) {
mightBeUnit = true;
}
}
if (mightBeUnit) {
// ExpressionTyperVisitorWithWritableScope should return only null or Unit for declarations and assignments
assert result == null || JetStandardClasses.isUnit(result);
result = JetStandardClasses.getUnitType();
}
}
}
}
else {
result = blockLevelVisitor.getType(statementExpression, newContext);
}
DataFlowInfo newDataFlowInfo = blockLevelVisitor.getResultingDataFlowInfo();
if (newDataFlowInfo == null) {
newDataFlowInfo = context.dataFlowInfo;
}
if (newDataFlowInfo != context.dataFlowInfo) {
newContext = ExpressionTypingContext.newRootContext(semanticServices, trace, scope, newDataFlowInfo, TypeUtils.NO_EXPECTED_TYPE, context.expectedReturnType);
}
blockLevelVisitor.resetResult(); // TODO : maybe it's better to recreate the visitors with the same scope?
}
return result;
}
private ObservableBindingTrace makeTraceInterceptingTypeMismatch(final BindingTrace trace, final JetExpression expressionToWatch, final boolean[] mismatchFound) {
return new ObservableBindingTrace(trace) {
@Override
public void report(@NotNull Diagnostic diagnostic) {
if (diagnostic.getFactory() == TYPE_MISMATCH && ((DiagnosticWithPsiElement) diagnostic).getPsiElement() == expressionToWatch) {
mismatchFound[0] = true;
}
super.report(diagnostic);
}
};
}
// //TODO
// private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull ExpressionTypingContext context) {
// if (expression == null) return initialType;
// VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context);
// if (variableDescriptor != null) {
// return context.dataFlowInfo.getOutType(variableDescriptor);
// }
// return initialType;
// }
// @Nullable
// private JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context) {
// if (expressionType != null && context.expectedType != null && context.expectedType != NO_EXPECTED_TYPE) {
// if (!semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
// context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
// }
// }
// return expressionType;
// }
@Nullable
/*package*/ JetType checkType(@Nullable JetType expressionType, @NotNull JetExpression expression, @NotNull ExpressionTypingContext context) {
if (expressionType == null || context.expectedType == null || context.expectedType == TypeUtils.NO_EXPECTED_TYPE ||
semanticServices.getTypeChecker().isSubtypeOf(expressionType, context.expectedType)) {
return expressionType;
}
// VariableDescriptor variableDescriptor = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), expression);
// boolean appropriateTypeFound = false;
// if (variableDescriptor != null) {
// List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypesForVariable(variableDescriptor));
// Collections.reverse(possibleTypes);
// for (JetType possibleType : possibleTypes) {
// if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) {
// appropriateTypeFound = true;
// break;
// }
// }
// if (!appropriateTypeFound) {
// JetType notnullType = context.dataFlowInfo.getOutType(variableDescriptor);
// if (notnullType != null && semanticServices.getTypeChecker().isSubtypeOf(notnullType, context.expectedType)) {
// appropriateTypeFound = true;
// }
// }
// }
if (AutoCastUtils.castExpression(expression, context.expectedType, context.dataFlowInfo, context.trace) == null) {
// context.trace.getErrorHandler().typeMismatch(expression, context.expectedType, expressionType);
context.trace.report(TYPE_MISMATCH.on(expression, context.expectedType, expressionType));
return expressionType;
}
// checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace);
return context.expectedType;
}
// private void checkAutoCast(JetExpression expression, JetType type, VariableDescriptor variableDescriptor, BindingTrace trace) {
// if (variableDescriptor.isVar()) {
//// trace.getErrorHandler().genericError(expression.getNode(), "Automatic cast to " + type + " is impossible, because variable " + variableDescriptor.getName() + " is mutable");
// trace.report(AUTOCAST_IMPOSSIBLE.on(expression, type, variableDescriptor));
// } else {
// trace.record(BindingContext.AUTOCAST, expression, type);
// }
// }
@NotNull
/*package*/ List<JetType> checkArgumentTypes(@NotNull List<JetType> argumentTypes, @NotNull List<JetExpression> arguments, @NotNull List<TypeProjection> expectedArgumentTypes, @NotNull ExpressionTypingContext context) {
if (arguments.size() == 0 || argumentTypes.size() != arguments.size() || expectedArgumentTypes.size() != arguments.size()) {
return argumentTypes;
}
List<JetType> result = Lists.newArrayListWithCapacity(arguments.size());
for (int i = 0, argumentTypesSize = argumentTypes.size(); i < argumentTypesSize; i++) {
result.add(checkType(argumentTypes.get(i), arguments.get(i), context.replaceExpectedType(expectedArgumentTypes.get(i).getType())));
}
return result;
}
@Nullable
/*package*/ VariableDescriptor getVariableDescriptorFromSimpleName(@NotNull JetExpression receiverExpression, @NotNull ExpressionTypingContext context) {
if (receiverExpression instanceof JetBinaryExpressionWithTypeRHS) {
JetBinaryExpressionWithTypeRHS expression = (JetBinaryExpressionWithTypeRHS) receiverExpression;
if (expression.getOperationSign().getReferencedNameElementType() == JetTokens.COLON) {
return getVariableDescriptorFromSimpleName(expression.getLeft(), context);
}
}
VariableDescriptor variableDescriptor = null;
if (receiverExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiverExpression;
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, nameExpression);
if (declarationDescriptor instanceof VariableDescriptor) {
variableDescriptor = (VariableDescriptor) declarationDescriptor;
}
}
return variableDescriptor;
}
}
@@ -0,0 +1,33 @@
package org.jetbrains.jet.lang.types.expressions;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.JetRootNamespaceExpression;
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression;
import org.jetbrains.jet.lang.resolve.JetModuleUtil;
import org.jetbrains.jet.lang.types.JetType;
/**
* @author abreslav
*/
public class ExpressionTyperVisitorWithNamespaces extends ExpressionTyperVisitor {
public static final ExpressionTyperVisitorWithNamespaces INSTANCE = new ExpressionTyperVisitorWithNamespaces();
private ExpressionTyperVisitorWithNamespaces() {}
@Override
public boolean isNamespacePosition() {
return true;
}
@Override
public JetType visitRootNamespaceExpression(JetRootNamespaceExpression expression, ExpressionTypingContext context) {
return context.getServices().checkType(JetModuleUtil.getRootNamespaceType(expression), expression, context);
}
@Override
protected boolean furtherNameLookup(@NotNull JetSimpleNameExpression expression, @NotNull String referencedName, @NotNull JetType[] result, ExpressionTypingContext context) {
result[0] = lookupNamespaceType(expression, referencedName, context);
return result[0] != null;
}
}
@@ -0,0 +1,205 @@
package org.jetbrains.jet.lang.types.expressions;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.TemporaryBindingTrace;
import org.jetbrains.jet.lang.resolve.TopDownAnalyzer;
import org.jetbrains.jet.lang.resolve.calls.AutoCastUtils;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.scopes.WritableScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
import static org.jetbrains.jet.lang.diagnostics.Errors.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.MUST_BE_WRAPPED_IN_A_REF;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
/**
* @author abreslav
*/
public class ExpressionTyperVisitorWithWritableScope extends ExpressionTyperVisitor {
private final WritableScope scope;
public ExpressionTyperVisitorWithWritableScope(@NotNull WritableScope scope) {
this.scope = scope;
}
@Override
public JetType visitObjectDeclaration(JetObjectDeclaration declaration, ExpressionTypingContext context) {
TopDownAnalyzer.processObject(context.semanticServices, context.trace, scope, scope.getContainingDeclaration(), declaration);
ClassDescriptor classDescriptor = context.trace.getBindingContext().get(BindingContext.CLASS, declaration);
if (classDescriptor != null) {
PropertyDescriptor propertyDescriptor = context.getClassDescriptorResolver().resolveObjectDeclarationAsPropertyDescriptor(scope.getContainingDeclaration(), declaration, classDescriptor);
scope.addVariableDescriptor(propertyDescriptor);
}
return checkExpectedType(declaration, context);
}
@Override
public JetType visitProperty(JetProperty property, ExpressionTypingContext context) {
JetTypeReference receiverTypeRef = property.getReceiverTypeRef();
if (receiverTypeRef != null) {
// context.trace.getErrorHandler().genericError(receiverTypeRef.getNode(), "Local receiver-properties are not allowed");
context.trace.report(LOCAL_EXTENSION_PROPERTY.on(receiverTypeRef));
}
JetPropertyAccessor getter = property.getGetter();
if (getter != null) {
// context.trace.getErrorHandler().genericError(getter.getNode(), "Local variables are not allowed to have getters");
context.trace.report(LOCAL_VARIABLE_WITH_GETTER.on(getter));
}
JetPropertyAccessor setter = property.getSetter();
if (setter != null) {
// context.trace.getErrorHandler().genericError(setter.getNode(), "Local variables are not allowed to have setters");
context.trace.report(LOCAL_VARIABLE_WITH_SETTER.on(setter));
}
VariableDescriptor propertyDescriptor = context.getClassDescriptorResolver().resolveLocalVariableDescriptor(scope.getContainingDeclaration(), scope, property);
JetExpression initializer = property.getInitializer();
if (property.getPropertyTypeRef() != null && initializer != null) {
JetType outType = propertyDescriptor.getOutType();
JetType initializerType = getType(initializer, context.replaceExpectedType(outType).replaceScope(scope));
// if (outType != null &&
// initializerType != null &&
// !semanticServices.getTypeChecker().isConvertibleTo(initializerType, outType)) {
// context.trace.report(TYPE_MISMATCH.on(initializer, outType, initializerType));
// }
}
scope.addVariableDescriptor(propertyDescriptor);
return checkExpectedType(property, context);
}
@Override
public JetType visitNamedFunction(JetNamedFunction function, ExpressionTypingContext context) {
FunctionDescriptorImpl functionDescriptor = context.getClassDescriptorResolver().resolveFunctionDescriptor(scope.getContainingDeclaration(), scope, function);
scope.addFunctionDescriptor(functionDescriptor);
context.getServices().checkFunctionReturnType(context.scope, function, functionDescriptor, context.dataFlowInfo);
return checkExpectedType(function, context);
}
@Override
public JetType visitClass(JetClass klass, ExpressionTypingContext context) {
return super.visitClass(klass, context); // TODO
}
@Override
public JetType visitTypedef(JetTypedef typedef, ExpressionTypingContext context) {
return super.visitTypedef(typedef, context); // TODO
}
@Override
public JetType visitDeclaration(JetDeclaration dcl, ExpressionTypingContext context) {
return checkExpectedType(dcl, context);
}
@Override
protected JetType visitAssignmentOperation(JetBinaryExpression expression, ExpressionTypingContext context) {
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
String name = OperatorConventions.ASSIGNMENT_OPERATIONS.get(operationType);
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace);
JetType assignmentOperationType = getTypeForBinaryCall(scope, name, context.replaceBindingTrace(temporaryBindingTrace), expression);
if (assignmentOperationType == null) {
String counterpartName = OperatorConventions.BINARY_OPERATION_NAMES.get(OperatorConventions.ASSIGNMENT_OPERATION_COUNTERPARTS.get(operationType));
JetType typeForBinaryCall = getTypeForBinaryCall(scope, counterpartName, context, expression);
if (typeForBinaryCall != null) {
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
}
}
else {
temporaryBindingTrace.commit();
}
return checkExpectedType(expression, context);
}
@Nullable
private JetType checkExpectedType(JetExpression expression, ExpressionTypingContext context) {
if (context.expectedType != TypeUtils.NO_EXPECTED_TYPE) {
if (JetStandardClasses.isUnit(context.expectedType)) {
return JetStandardClasses.getUnitType();
}
context.trace.report(EXPECTED_TYPE_MISMATCH.on(expression, context.expectedType));
}
return null;
}
@Override
protected JetType visitAssignment(JetBinaryExpression expression, ExpressionTypingContext context) {
JetExpression left = expression.getLeft();
JetExpression deparenthesized = JetPsiUtil.deparenthesize(left);
JetExpression right = expression.getRight();
if (deparenthesized instanceof JetArrayAccessExpression) {
JetArrayAccessExpression arrayAccessExpression = (JetArrayAccessExpression) deparenthesized;
return resolveArrayAccessToLValue(arrayAccessExpression, right, expression.getOperationReference(), context);
}
JetType leftType = getType(left, context.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceScope(scope));
if (right != null) {
JetType rightType = getType(right, context.replaceExpectedType(leftType).replaceScope(scope));
// if (rightType != null &&
// leftType != null &&
// !semanticServices.getTypeChecker().isConvertibleTo(rightType, leftType)) {
// context.trace.report(TYPE_MISMATCH.on(right, leftType, rightType));
// }
}
if (left instanceof JetSimpleNameExpression) {
JetSimpleNameExpression simpleName = (JetSimpleNameExpression) left;
String referencedName = simpleName.getReferencedName();
if (simpleName.getReferencedNameElementType() == JetTokens.FIELD_IDENTIFIER
&& referencedName != null) {
PropertyDescriptor property = context.scope.getPropertyByFieldReference(referencedName);
if (property != null) {
context.trace.record(BindingContext.VARIABLE_ASSIGNMENT, simpleName, property);
}
}
VariableDescriptor variable = AutoCastUtils.getVariableDescriptorFromSimpleName(context.trace.getBindingContext(), simpleName);
if (variable != null) {
DeclarationDescriptor containingDeclaration = variable.getContainingDeclaration();
if (context.scope.getContainingDeclaration() != containingDeclaration && containingDeclaration instanceof CallableDescriptor) {
context.trace.record(MUST_BE_WRAPPED_IN_A_REF, variable);
}
}
}
return checkExpectedType(expression, context);
}
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, ExpressionTypingContext context) {
ExpressionReceiver receiver = getExpressionReceiver(arrayAccessExpression.getArrayExpression(), context.replaceScope(scope));
if (receiver == null) return null;
//
Call call = CallMaker.makeCall(receiver, arrayAccessExpression, rightHandSide);
// // TODO : nasty hack: effort is duplicated
// callResolver.resolveCallWithGivenName(
// scope,
// call,
// arrayAccessExpression,
// "set", arrayAccessExpression.getArrayExpression(), NO_EXPECTED_TYPE);
FunctionDescriptor functionDescriptor = context.replaceScope(scope).replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).resolveCallWithGivenName(
call,
arrayAccessExpression,
"set", receiver);
if (functionDescriptor == null) return null;
context.trace.record(REFERENCE_TARGET, operationSign, functionDescriptor);
return context.getServices().checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
}
@Override
public JetType visitAnnotatedExpression(JetAnnotatedExpression expression, ExpressionTypingContext data) {
return getType(expression.getBaseExpression(), data);
}
@Override
public JetType visitJetElement(JetElement element, ExpressionTypingContext context) {
context.trace.report(UNSUPPORTED.on(element, "in a block"));
// context.trace.getErrorHandler().genericError(element.getNode(), "Unsupported element in a block: " + element + " " + element.getClass().getCanonicalName());
return null;
}
}
@@ -0,0 +1,191 @@
package org.jetbrains.jet.lang.types.expressions;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingTrace;
import org.jetbrains.jet.lang.resolve.ClassDescriptorResolver;
import org.jetbrains.jet.lang.resolve.TypeResolver;
import org.jetbrains.jet.lang.resolve.calls.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
import org.jetbrains.jet.lang.resolve.scopes.JetScope;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeUtils;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
/*package*/ class ExpressionTypingContext {
@NotNull
public static ExpressionTypingContext newContext(
@NotNull JetSemanticServices semanticServices,
@NotNull Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo,
@NotNull Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists,
@NotNull LabelResolver labelResolver,
@NotNull BindingTrace trace,
@NotNull JetScope scope,
@NotNull DataFlowInfo dataFlowInfo,
@NotNull JetType expectedType,
@NotNull JetType expectedReturnType) {
return new ExpressionTypingContext(semanticServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver, trace, scope, dataFlowInfo, expectedType, expectedReturnType);
}
@NotNull
public static ExpressionTypingContext newRootContext(
@NotNull JetSemanticServices semanticServices,
@NotNull BindingTrace trace,
@NotNull JetScope scope,
@NotNull DataFlowInfo dataFlowInfo,
@NotNull JetType expectedType,
@NotNull JetType expectedReturnType) {
return new ExpressionTypingContext(semanticServices, new HashMap<JetPattern, DataFlowInfo>(), new HashMap<JetPattern, List<VariableDescriptor>>(), new LabelResolver(), trace, scope, dataFlowInfo, expectedType, expectedReturnType);
}
public final JetSemanticServices semanticServices;
public final BindingTrace trace;
public final JetScope scope;
public final DataFlowInfo dataFlowInfo;
public final JetType expectedType;
public final JetType expectedReturnType;
public final Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo;
public final Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists;
public final LabelResolver labelResolver;
private CallResolver callResolver;
private TypeResolver typeResolver;
private ClassDescriptorResolver classDescriptorResolver;
private ExpressionTyperServices services;
private CompileTimeConstantResolver compileTimeConstantResolver;
private ExpressionTypingContext(
@NotNull JetSemanticServices semanticServices,
@NotNull Map<JetPattern, DataFlowInfo> patternsToDataFlowInfo,
@NotNull Map<JetPattern, List<VariableDescriptor>> patternsToBoundVariableLists,
@NotNull LabelResolver labelResolver,
@NotNull BindingTrace trace,
@NotNull JetScope scope,
@NotNull DataFlowInfo dataFlowInfo,
@NotNull JetType expectedType,
@NotNull JetType expectedReturnType) {
this.trace = trace;
// this.typeResolver = new TypeResolver(semanticServices, trace, true);
this.patternsToBoundVariableLists = patternsToBoundVariableLists;
this.patternsToDataFlowInfo = patternsToDataFlowInfo;
this.labelResolver = labelResolver;
this.scope = scope;
// this.services = new ExpressionTyperServices(semanticServices, trace);
this.semanticServices = semanticServices;
// this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace);
this.dataFlowInfo = dataFlowInfo;
this.expectedType = expectedType;
this.expectedReturnType = expectedReturnType;
}
public ExpressionTypingContext replaceDataFlowInfo(DataFlowInfo newDataFlowInfo) {
return newContext(semanticServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver, trace, scope, newDataFlowInfo, expectedType, expectedReturnType);
}
public ExpressionTypingContext replaceExpectedType(@Nullable JetType newExpectedType) {
if (newExpectedType == null) return replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE);
if (expectedType == newExpectedType) return this;
return newContext(semanticServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver, trace, scope, dataFlowInfo, newExpectedType, expectedReturnType);
}
public ExpressionTypingContext replaceExpectedReturnType(@Nullable JetType newExpectedReturnType) {
if (newExpectedReturnType == null) return replaceExpectedReturnType(TypeUtils.NO_EXPECTED_TYPE);
if (expectedReturnType == newExpectedReturnType) return this;
return newContext(semanticServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver, trace, scope, dataFlowInfo, expectedType, newExpectedReturnType);
}
public ExpressionTypingContext replaceBindingTrace(@NotNull BindingTrace newTrace) {
if (newTrace == trace) return this;
return newContext(semanticServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver, newTrace, scope, dataFlowInfo, expectedType, expectedReturnType);
}
public ExpressionTypingContext replaceExpectedTypeAndTrace(@NotNull JetType newExpectedType, @NotNull BindingTrace newTrace) {
if (newExpectedType == expectedType && newTrace == trace) return this;
return newContext(semanticServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver, newTrace, scope, dataFlowInfo, newExpectedType, expectedReturnType);
}
@NotNull
public ExpressionTypingContext replaceScope(@NotNull JetScope newScope) {
if (newScope == scope) return this;
return newContext(semanticServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver, trace, newScope, dataFlowInfo, expectedType, expectedReturnType);
}
@NotNull
public ExpressionTypingContext replaceExpectedTypes(@NotNull JetType newExpectedType, @NotNull JetType newExpectedReturnType) {
if (expectedType == newExpectedType && expectedReturnType == newExpectedReturnType) return this;
return newContext(semanticServices, patternsToDataFlowInfo, patternsToBoundVariableLists, labelResolver, trace, scope, dataFlowInfo, newExpectedType, newExpectedReturnType);
}
public CallResolver getCallResolver() {
if (callResolver == null) {
callResolver = new CallResolver(semanticServices, dataFlowInfo);
}
return callResolver;
}
@Nullable
public FunctionDescriptor resolveCallWithGivenName(@NotNull Call call, @NotNull JetReferenceExpression functionReference, @NotNull String name, @NotNull ReceiverDescriptor receiver) {
return getCallResolver().resolveCallWithGivenName(trace, scope, call, functionReference, name, expectedType);
}
@Nullable
public JetType resolveCall(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetCallExpression callExpression) {
return getCallResolver().resolveCall(trace, scope, CallMaker.makeCall(receiver, callOperationNode, callExpression), expectedType);
}
@Nullable
public VariableDescriptor resolveSimpleProperty(@NotNull ReceiverDescriptor receiver, @Nullable ASTNode callOperationNode, @NotNull JetSimpleNameExpression nameExpression) {
Call call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression);
return getCallResolver().resolveSimpleProperty(trace, scope, call, expectedType);
}
@NotNull
public OverloadResolutionResults<FunctionDescriptor> resolveExactSignature(@NotNull ReceiverDescriptor receiver, @NotNull String name, @NotNull List<JetType> parameterTypes) {
return getCallResolver().resolveExactSignature(scope, receiver, name, parameterTypes);
}
public ExpressionTyperServices getServices() {
if (services == null) {
services = new ExpressionTyperServices(semanticServices, trace);
}
return services;
}
public TypeResolver getTypeResolver() {
if (typeResolver == null) {
typeResolver = new TypeResolver(semanticServices, trace, true);
}
return typeResolver;
}
public ClassDescriptorResolver getClassDescriptorResolver() {
if (classDescriptorResolver == null) {
classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace);
}
return classDescriptorResolver;
}
public CompileTimeConstantResolver getCompileTimeConstantResolver() {
if (compileTimeConstantResolver == null) {
compileTimeConstantResolver = new CompileTimeConstantResolver(semanticServices, trace);
}
return compileTimeConstantResolver;
}
}
@@ -0,0 +1,154 @@
package org.jetbrains.jet.lang.types.expressions;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.ClassDescriptor;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import java.util.*;
import static org.jetbrains.jet.lang.diagnostics.Errors.AMBIGUOUS_LABEL;
import static org.jetbrains.jet.lang.diagnostics.Errors.LABEL_NAME_CLASH;
import static org.jetbrains.jet.lang.diagnostics.Errors.UNRESOLVED_REFERENCE;
import static org.jetbrains.jet.lang.resolve.BindingContext.DESCRIPTOR_TO_DECLARATION;
import static org.jetbrains.jet.lang.resolve.BindingContext.LABEL_TARGET;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
/**
* @author abreslav
*/
public class LabelResolver {
private final Map<String, Stack<JetElement>> labeledElements = new HashMap<String, Stack<JetElement>>();
public void enterLabeledElement(@NotNull String labelName, @NotNull JetExpression labeledExpression) {
JetExpression deparenthesized = JetPsiUtil.deparenthesize(labeledExpression);
if (deparenthesized != null) {
Stack<JetElement> stack = labeledElements.get(labelName);
if (stack == null) {
stack = new Stack<JetElement>();
labeledElements.put(labelName, stack);
}
stack.push(deparenthesized);
}
}
public void exitLabeledElement(@NotNull JetExpression expression) {
JetExpression deparenthesized = JetPsiUtil.deparenthesize(expression);
// TODO : really suboptimal
for (Iterator<Map.Entry<String, Stack<JetElement>>> mapIter = labeledElements.entrySet().iterator(); mapIter.hasNext(); ) {
Map.Entry<String, Stack<JetElement>> entry = mapIter.next();
Stack<JetElement> stack = entry.getValue();
for (Iterator<JetElement> stackIter = stack.iterator(); stackIter.hasNext(); ) {
JetElement recorded = stackIter.next();
if (recorded == deparenthesized) {
stackIter.remove();
}
}
if (stack.isEmpty()) {
mapIter.remove();
}
}
}
private JetElement resolveControlLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, ExpressionTypingContext context) {
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
int size = declarationsByLabel.size();
if (size == 1) {
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
JetElement element;
if (declarationDescriptor instanceof FunctionDescriptor || declarationDescriptor instanceof ClassDescriptor) {
element = (JetElement) context.trace.get(BindingContext.DESCRIPTOR_TO_DECLARATION, declarationDescriptor);
}
else {
throw new UnsupportedOperationException(); // TODO
}
context.trace.record(LABEL_TARGET, labelExpression, element);
return element;
}
else if (size == 0) {
return resolveNamedLabel(labelName, labelExpression, reportUnresolved, context);
}
context.trace.report(AMBIGUOUS_LABEL.on(labelExpression));
return null;
}
public void recordLabel(JetLabelQualifiedExpression expression, ExpressionTypingContext context) {
JetSimpleNameExpression labelElement = expression.getTargetLabel();
if (labelElement != null) {
String labelName = expression.getLabelName();
assert labelName != null;
resolveControlLabel(labelName, labelElement, true, context);
}
}
private JetElement resolveNamedLabel(@NotNull String labelName, @NotNull JetSimpleNameExpression labelExpression, boolean reportUnresolved, ExpressionTypingContext context) {
Stack<JetElement> stack = labeledElements.get(labelName);
if (stack == null || stack.isEmpty()) {
if (reportUnresolved) {
context.trace.report(UNRESOLVED_REFERENCE.on(labelExpression));
}
return null;
}
else if (stack.size() > 1) {
context.trace.report(LABEL_NAME_CLASH.on(labelExpression));
}
JetElement result = stack.peek();
context.trace.record(BindingContext.LABEL_TARGET, labelExpression, result);
return result;
}
public ReceiverDescriptor resolveThisLabel(JetThisExpression expression, ExpressionTypingContext context, ReceiverDescriptor thisReceiver, String labelName) {
Collection<DeclarationDescriptor> declarationsByLabel = context.scope.getDeclarationsByLabel(labelName);
int size = declarationsByLabel.size();
final JetSimpleNameExpression targetLabel = expression.getTargetLabel();
assert targetLabel != null;
if (size == 1) {
DeclarationDescriptor declarationDescriptor = declarationsByLabel.iterator().next();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
thisReceiver = classDescriptor.getImplicitReceiver();
}
else if (declarationDescriptor instanceof FunctionDescriptor) {
FunctionDescriptor functionDescriptor = (FunctionDescriptor) declarationDescriptor;
thisReceiver = functionDescriptor.getReceiverParameter();
}
else {
throw new UnsupportedOperationException(); // TODO
}
PsiElement element = context.trace.get(DESCRIPTOR_TO_DECLARATION, declarationDescriptor);
assert element != null;
context.trace.record(LABEL_TARGET, targetLabel, element);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
}
else if (size == 0) {
JetElement element = resolveNamedLabel(labelName, targetLabel, false, context);
if (element instanceof JetFunctionLiteralExpression) {
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.DECLARATION_TO_DESCRIPTOR, element);
if (declarationDescriptor instanceof FunctionDescriptor) {
thisReceiver = ((FunctionDescriptor) declarationDescriptor).getReceiverParameter();
if (thisReceiver.exists()) {
context.trace.record(LABEL_TARGET, targetLabel, element);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
}
}
else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
}
}
else {
context.trace.report(UNRESOLVED_REFERENCE.on(targetLabel));
}
}
else {
context.trace.report(AMBIGUOUS_LABEL.on(targetLabel));
}
return thisReceiver;
}
}
@@ -0,0 +1,78 @@
package org.jetbrains.jet.lang.types.expressions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.intellij.psi.tree.IElementType;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lexer.JetTokens;
/**
* @author abreslav
*/
public class OperatorConventions {
private OperatorConventions() {}
public static final ImmutableSet<String> NUMBER_CONVERSIONS = ImmutableSet.of(
"dbl",
"flt",
"lng",
"sht",
"byt",
"int"
);
public static final ImmutableMap<IElementType, String> UNARY_OPERATION_NAMES = ImmutableMap.<IElementType, String>builder()
.put(JetTokens.PLUSPLUS, "inc")
.put(JetTokens.MINUSMINUS, "dec")
.put(JetTokens.PLUS, "plus")
.put(JetTokens.MINUS, "minus")
.put(JetTokens.EXCL, "not")
.build();
public static final ImmutableMap<IElementType, String> BINARY_OPERATION_NAMES = ImmutableMap.<IElementType, String>builder()
.put(JetTokens.MUL, "times")
.put(JetTokens.PLUS, "plus")
.put(JetTokens.MINUS, "minus")
.put(JetTokens.DIV, "div")
.put(JetTokens.PERC, "mod")
.put(JetTokens.ARROW, "arrow")
.put(JetTokens.RANGE, "rangeTo")
.build();
public static final ImmutableSet<IElementType> COMPARISON_OPERATIONS = ImmutableSet.<IElementType>of(JetTokens.LT, JetTokens.GT, JetTokens.LTEQ, JetTokens.GTEQ);
public static final ImmutableSet<IElementType> EQUALS_OPERATIONS = ImmutableSet.<IElementType>of(JetTokens.EQEQ, JetTokens.EXCLEQ);
public static final ImmutableSet<IElementType> IN_OPERATIONS = ImmutableSet.<IElementType>of(JetTokens.IN_KEYWORD, JetTokens.NOT_IN);
public static final ImmutableMap<IElementType, String> ASSIGNMENT_OPERATIONS = ImmutableMap.<IElementType, String>builder()
.put(JetTokens.MULTEQ, "timesAssign")
.put(JetTokens.DIVEQ, "divAssign")
.put(JetTokens.PERCEQ, "modAssign")
.put(JetTokens.PLUSEQ, "plusAssign")
.put(JetTokens.MINUSEQ, "minusAssign")
.build();
public static final ImmutableMap<IElementType, IElementType> ASSIGNMENT_OPERATION_COUNTERPARTS = ImmutableMap.<IElementType, IElementType>builder()
.put(JetTokens.MULTEQ, JetTokens.MUL)
.put(JetTokens.DIVEQ, JetTokens.DIV)
.put(JetTokens.PERCEQ, JetTokens.PERC)
.put(JetTokens.PLUSEQ, JetTokens.PLUS)
.put(JetTokens.MINUSEQ, JetTokens.MINUS)
.build();
@Nullable
public static String getNameForOperationSymbol(@NotNull IElementType token) {
String name = UNARY_OPERATION_NAMES.get(token);
if (name != null) return name;
name = BINARY_OPERATION_NAMES.get(token);
if (name != null) return name;
name = ASSIGNMENT_OPERATIONS.get(token);
if (name != null) return name;
if (COMPARISON_OPERATIONS.contains(token)) return "compareTo";
if (EQUALS_OPERATIONS.contains(token)) return "equals";
if (IN_OPERATIONS.contains(token)) return "contains";
return null;
}
}
@@ -1,4 +1,4 @@
package org.jetbrains.jet.lang.types;
package org.jetbrains.jet.util.lazy;
/**
* @author abreslav
@@ -1,4 +1,4 @@
package org.jetbrains.jet.lang.types;
package org.jetbrains.jet.util.lazy;
/**
* @author abreslav
@@ -1,4 +1,4 @@
package org.jetbrains.jet.lang.types;
package org.jetbrains.jet.util.lazy;
/**
* @author abreslav
@@ -18,7 +18,7 @@ import org.jetbrains.jet.lang.resolve.calls.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.ResolvedCall;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.expressions.JetTypeInferrerServices;
import org.jetbrains.jet.lang.types.expressions.ExpressionTyperServices;
import org.jetbrains.jet.parsing.JetParsingTest;
import java.io.File;
@@ -106,7 +106,7 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
@NotNull
private FunctionDescriptor standardFunction(ClassDescriptor classDescriptor, List<TypeProjection> typeArguments, String name, JetType... parameterType) {
List<JetType> parameterTypeList = Arrays.asList(parameterType);
JetTypeInferrerServices typeInferrerServices = JetSemanticServices.createSemanticServices(getProject()).getTypeInferrerServices(new BindingTraceContext());
ExpressionTyperServices typeInferrerServices = JetSemanticServices.createSemanticServices(getProject()).getTypeInferrerServices(new BindingTraceContext());
OverloadResolutionResults<FunctionDescriptor> functions = typeInferrerServices.getCallResolver().resolveExactSignature(
classDescriptor.getMemberScope(typeArguments), ReceiverDescriptor.NO_RECEIVER, name, parameterTypeList);
@@ -20,7 +20,6 @@ import org.jetbrains.jet.lang.resolve.scopes.*;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverDescriptor;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lang.types.expressions.JetTypeInferrer;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.parsing.JetParsingTest;
@@ -493,14 +492,14 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
private void assertType(String expression, JetType expectedType) {
Project project = getProject();
JetExpression jetExpression = JetPsiFactory.createExpression(project, expression);
JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).getType(scopeWithImports, jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE);
JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).getType(scopeWithImports, jetExpression, TypeUtils.NO_EXPECTED_TYPE);
assertTrue(type + " != " + expectedType, type.equals(expectedType));
}
private void assertErrorType(String expression) {
Project project = getProject();
JetExpression jetExpression = JetPsiFactory.createExpression(project, expression);
JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).safeGetType(scopeWithImports, jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE);
JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).safeGetType(scopeWithImports, jetExpression, TypeUtils.NO_EXPECTED_TYPE);
assertTrue("Error type expected but " + type + " returned", ErrorUtils.isErrorType(type));
}
@@ -523,7 +522,7 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
private void assertType(JetScope scope, String expression, String expectedTypeStr) {
Project project = getProject();
JetExpression jetExpression = JetPsiFactory.createExpression(project, expression);
JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).getType(addImports(scope), jetExpression, JetTypeInferrer.NO_EXPECTED_TYPE);
JetType type = semanticServices.getTypeInferrerServices(JetTestUtils.DUMMY_TRACE).getType(addImports(scope), jetExpression, TypeUtils.NO_EXPECTED_TYPE);
JetType expectedType = expectedTypeStr == null ? null : makeType(expectedTypeStr);
assertEquals(expectedType, type);
}