diff --git a/idea/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java b/idea/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java new file mode 100644 index 00000000000..5ead4c14230 --- /dev/null +++ b/idea/src/org/jetbrains/jet/lang/descriptors/VariableAsFunctionDescriptor.java @@ -0,0 +1,33 @@ +package org.jetbrains.jet.lang.descriptors; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.types.JetStandardClasses; +import org.jetbrains.jet.lang.types.JetType; + +import java.util.Collections; + +/** + * @author abreslav + */ +public class VariableAsFunctionDescriptor extends FunctionDescriptorImpl { + public static VariableAsFunctionDescriptor create(@NotNull VariableDescriptor variableDescriptor) { + JetType outType = variableDescriptor.getOutType(); + assert outType != null; + assert JetStandardClasses.isFunctionType(outType); + VariableAsFunctionDescriptor result = new VariableAsFunctionDescriptor(variableDescriptor); + result.initialize(JetStandardClasses.getReceiverType(outType), Collections.emptyList(), JetStandardClasses.getValueParameters(result, outType), JetStandardClasses.getReturnType(outType)); + return result; + } + + private final VariableDescriptor variableDescriptor; + + private VariableAsFunctionDescriptor(VariableDescriptor variableDescriptor) { + super(variableDescriptor.getContainingDeclaration(), Collections.emptyList(), variableDescriptor.getName()); +// super(variableDescriptor.getContainingDeclaration(), Collections.emptyList(), variableDescriptor.getName()); + this.variableDescriptor = variableDescriptor; + } + + public VariableDescriptor getVariableDescriptor() { + return variableDescriptor; + } +} diff --git a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java index 1faf1be7c15..fe667d7c582 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/BindingTraceContext.java @@ -106,7 +106,7 @@ public class BindingTraceContext implements BindingContext, BindingTrace { @Override public void recordDeclarationResolution(@NotNull PsiElement declaration, @NotNull DeclarationDescriptor descriptor) { - safePut(descriptorToDeclarations, descriptor.getOriginal(), declaration); + safePut(descriptorToDeclarations, getOriginal(descriptor), declaration); descriptor.accept(new DeclarationDescriptorVisitor() { @Override public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, PsiElement declaration) { @@ -121,7 +121,7 @@ public class BindingTraceContext implements BindingContext, BindingTrace { } public Void visitDeclarationDescriptor(DeclarationDescriptor descriptor, PsiElement declaration) { - safePut(declarationsToDescriptors, declaration, descriptor.getOriginal()); + safePut(declarationsToDescriptors, declaration, getOriginal(descriptor)); return null; } }, declaration); @@ -129,8 +129,8 @@ public class BindingTraceContext implements BindingContext, BindingTrace { @Override public void recordValueParameterAsPropertyResolution(@NotNull JetParameter declaration, @NotNull PropertyDescriptor descriptor) { - safePut(primaryConstructorParameterDeclarationsToPropertyDescriptors, declaration, (PropertyDescriptor) descriptor.getOriginal()); - safePut(descriptorToDeclarations, descriptor.getOriginal(), declaration); + safePut(primaryConstructorParameterDeclarationsToPropertyDescriptors, declaration, (PropertyDescriptor) getOriginal(descriptor)); + safePut(descriptorToDeclarations, getOriginal(descriptor), declaration); } private void safePut(Map map, K key, V value) { @@ -246,12 +246,20 @@ public class BindingTraceContext implements BindingContext, BindingTrace { if (declarationDescriptor == null) { return labelResolutionResults.get(referenceExpression); } - return descriptorToDeclarations.get(declarationDescriptor.getOriginal()); + return descriptorToDeclarations.get(getOriginal(declarationDescriptor)); + } + + private DeclarationDescriptor getOriginal(DeclarationDescriptor declarationDescriptor) { + if (declarationDescriptor instanceof VariableAsFunctionDescriptor) { + VariableAsFunctionDescriptor descriptor = (VariableAsFunctionDescriptor) declarationDescriptor; + return descriptor.getVariableDescriptor().getOriginal(); + } + return declarationDescriptor.getOriginal(); } @Override public PsiElement getDeclarationPsiElement(@NotNull DeclarationDescriptor descriptor) { - return descriptorToDeclarations.get(descriptor.getOriginal()); + return descriptorToDeclarations.get(getOriginal(descriptor)); } @Override diff --git a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java index aec5ee12569..8330a8b686b 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/ClassDescriptorResolver.java @@ -511,7 +511,7 @@ public class ClassDescriptorResolver { } @NotNull - private JetType getVariableType(@NotNull final JetScope scope, @NotNull JetProperty property, boolean allowDeferred) { + private JetType getVariableType(@NotNull final JetScope scope, @NotNull final JetProperty property, boolean allowDeferred) { // TODO : receiver? JetTypeReference propertyTypeRef = property.getPropertyTypeRef(); @@ -525,7 +525,8 @@ public class ClassDescriptorResolver { LazyValue lazyValue = new LazyValue() { @Override protected JetType compute() { - return semanticServices.getTypeInferrerServices(trace, JetFlowInformationProvider.THROW_EXCEPTION).safeGetType(scope, initializer, false, JetTypeInferrer.NO_EXPECTED_TYPE); + JetFlowInformationProvider flowInformationProvider = computeFlowData(property, initializer); + return semanticServices.getTypeInferrerServices(trace, flowInformationProvider).safeGetType(scope, initializer, false, JetTypeInferrer.NO_EXPECTED_TYPE); } }; if (allowDeferred) { diff --git a/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java b/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java index 71e514080f6..16e823cec13 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/WritableScopeImpl.java @@ -36,6 +36,9 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Nullable private JetType thisType; + private boolean variablesAsFunctionsAdded; + private List variableDescriptors; + public WritableScopeImpl(@NotNull JetScope scope, @NotNull DeclarationDescriptor owner, @NotNull ErrorHandler errorHandler) { super(scope, errorHandler); this.ownerDeclarationDescriptor = owner; @@ -122,6 +125,14 @@ public class WritableScopeImpl extends WritableScopeWithImports { return variableClassOrNamespaceDescriptors; } + @NotNull + private List getVariableDescriptors() { + if (variableDescriptors == null) { + variableDescriptors = Lists.newArrayList(); + } + return variableDescriptors; + } + @Override public void addVariableDescriptor(@NotNull VariableDescriptor variableDescriptor) { Map variableClassOrNamespaceDescriptors = getVariableClassOrNamespaceDescriptors(); @@ -132,6 +143,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { // TODO : Should this always happen? variableClassOrNamespaceDescriptors.put(variableDescriptor.getName(), variableDescriptor); allDescriptors.add(variableDescriptor); + + getVariableDescriptors().add(variableDescriptor); } @Override @@ -174,6 +187,8 @@ public class WritableScopeImpl extends WritableScopeWithImports { @Override @NotNull public FunctionGroup getFunctionGroup(@NotNull String name) { + addVariablesAsFunctions(); + FunctionGroup functionGroup = getFunctionGroups().get(name); FunctionGroup constructors = null; ClassifierDescriptor classifier = getClassifier(name); @@ -212,6 +227,17 @@ public class WritableScopeImpl extends WritableScopeWithImports { return super.getFunctionGroup(name); } + private void addVariablesAsFunctions() { + if (variablesAsFunctionsAdded) return; + variablesAsFunctionsAdded = true; + for (VariableDescriptor variableDescriptor : getVariableDescriptors()) { + JetType outType = variableDescriptor.getOutType(); + if (outType != null && JetStandardClasses.isFunctionType(outType)) { + addFunctionDescriptor(VariableAsFunctionDescriptor.create(variableDescriptor)); + } + } + } + @Override public void addTypeParameterDescriptor(@NotNull TypeParameterDescriptor typeParameterDescriptor) { String name = typeParameterDescriptor.getName(); diff --git a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java index 2e253f17e58..7bfaf8700e0 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetStandardClasses.java @@ -1,5 +1,7 @@ package org.jetbrains.jet.lang.types; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.ErrorHandler; @@ -133,6 +135,9 @@ public class JetStandardClasses { private static final ClassDescriptor[] FUNCTION = new ClassDescriptor[FUNCTION_COUNT]; private static final ClassDescriptor[] RECEIVER_FUNCTION = new ClassDescriptor[FUNCTION_COUNT]; + private static final Set FUNCTION_TYPE_CONSTRUCTORS = Sets.newHashSet(); + private static final Set RECEIVER_FUNCTION_TYPE_CONSTRUCTORS = Sets.newHashSet(); + static { for (int i = 0; i < FUNCTION_COUNT; i++) { ClassDescriptorImpl function = new ClassDescriptorImpl( @@ -143,6 +148,7 @@ public class JetStandardClasses { false, createTypeParameters(i, function), Collections.singleton(getAnyType()), STUB, FunctionGroup.EMPTY, null); + FUNCTION_TYPE_CONSTRUCTORS.add(FUNCTION[i].getTypeConstructor()); ClassDescriptorImpl receiverFunction = new ClassDescriptorImpl( STANDARD_CLASSES_NAMESPACE, @@ -157,6 +163,7 @@ public class JetStandardClasses { false, parameters, Collections.singleton(getAnyType()), STUB, FunctionGroup.EMPTY, null); + RECEIVER_FUNCTION_TYPE_CONSTRUCTORS.add(RECEIVER_FUNCTION[i].getTypeConstructor()); } } @@ -338,4 +345,40 @@ public class JetStandardClasses { private static TypeProjection defaultProjection(JetType returnType) { return new TypeProjection(Variance.INVARIANT, returnType); } + + public static boolean isFunctionType(@NotNull JetType type) { + return FUNCTION_TYPE_CONSTRUCTORS.contains(type.getConstructor()) || RECEIVER_FUNCTION_TYPE_CONSTRUCTORS.contains(type.getConstructor()); + } + + @Nullable + public static JetType getReceiverType(@NotNull JetType type) { + assert isFunctionType(type) : type; + if (RECEIVER_FUNCTION_TYPE_CONSTRUCTORS.contains(type.getConstructor())) { + return type.getArguments().get(0).getType(); + } + return null; + } + + @NotNull + public static List getValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull JetType type) { + assert isFunctionType(type); + List arguments = type.getArguments(); + int first = RECEIVER_FUNCTION_TYPE_CONSTRUCTORS.contains(type.getConstructor()) ? 1 : 0; + int last = arguments.size() - 2; + List valueParameters = Lists.newArrayList(); + for (int i = first; i <= last; i++) { + JetType parameterType = arguments.get(i).getType(); + ValueParameterDescriptorImpl valueParameterDescriptor = new ValueParameterDescriptorImpl(functionDescriptor, i, Collections.emptyList(), "p" + i, null, parameterType, false, false); + valueParameters.add(valueParameterDescriptor); + } + return valueParameters; + } + + @NotNull + public static JetType getReturnType(@NotNull JetType type) { + assert isFunctionType(type); + List arguments = type.getArguments(); + return arguments.get(arguments.size() - 1).getType(); + } + } diff --git a/idea/testData/cfg/ArrayAccess.instructions b/idea/testData/cfg/ArrayAccess.instructions index b2d18a45e79..ea110204bd7 100644 --- a/idea/testData/cfg/ArrayAccess.instructions +++ b/idea/testData/cfg/ArrayAccess.instructions @@ -36,3 +36,15 @@ l1: error: ===================== +== a == +val a = Array +--------------------- +l0: + + r(Array) + r(Array) +l1: + +error: + +===================== diff --git a/idea/testData/cfg/Assignments.instructions b/idea/testData/cfg/Assignments.instructions index 07ceb36d2c8..89fda838fce 100644 --- a/idea/testData/cfg/Assignments.instructions +++ b/idea/testData/cfg/Assignments.instructions @@ -55,3 +55,56 @@ l1: error: ===================== +== x == +var x = 1 +--------------------- +l0: + + r(1) +l1: + +error: + +===================== +== y == +val y = true && false +--------------------- +l0: + + r(true) + jf(l2) + r(false) +l2: + r(true && false) +l1: + +error: + +===================== +== z == +val z = false && true +--------------------- +l0: + + r(false) + jf(l2) + r(true) +l2: + r(false && true) +l1: + +error: + +===================== +== t == +val t = Test() +--------------------- +l0: + + r(Test) + r(Test()) +l1: + +error: + +===================== diff --git a/idea/testData/checker/RecursiveTypeInference.jet b/idea/testData/checker/RecursiveTypeInference.jet index a73cf01cc0e..cb32ac6cefc 100644 --- a/idea/testData/checker/RecursiveTypeInference.jet +++ b/idea/testData/checker/RecursiveTypeInference.jet @@ -1,7 +1,7 @@ namespace a { - val foo = bar() + val foo = bar() - fun bar() = foo + fun bar() = foo } namespace b { diff --git a/idea/testData/resolve/FunctionVariable.jet b/idea/testData/resolve/FunctionVariable.jet new file mode 100644 index 00000000000..b23da26721c --- /dev/null +++ b/idea/testData/resolve/FunctionVariable.jet @@ -0,0 +1,3 @@ +fun invoker(~gen~gen : {() : Int}) : Int { + return `gen`gen() // Says it cannot resolve 'gen' here +} diff --git a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java index 09e5c7e9c21..1e0c9566cc6 100644 --- a/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java +++ b/idea/tests/org/jetbrains/jet/resolve/ExpectedResolveData.java @@ -8,10 +8,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.ErrorHandler; import org.jetbrains.jet.lang.JetSemanticServices; import org.jetbrains.jet.lang.cfg.pseudocode.JetControlFlowDataTraceFactory; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor; -import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; -import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.AnalyzingUtils; import org.jetbrains.jet.lang.resolve.BindingContext; @@ -186,6 +183,10 @@ public class ExpectedResolveData { DeclarationDescriptor actualDescriptor = bindingContext.resolveReferenceExpression(reference); + if (actualDescriptor instanceof VariableAsFunctionDescriptor) { + VariableAsFunctionDescriptor descriptor = (VariableAsFunctionDescriptor) actualDescriptor; + actualDescriptor = descriptor.getVariableDescriptor(); + } assertEquals( "Reference `" + name + "`" + renderReferenceInContext(reference) + " is resolved into " + actualName + ".",