Working on type inference for function literals

This commit is contained in:
Andrey Breslav
2011-08-26 17:51:15 +04:00
parent 4710835bd4
commit 86e8142e3c
36 changed files with 1151 additions and 1030 deletions
+1 -1
View File
@@ -29,7 +29,7 @@ public interface JetNodeTypes {
JetNodeType DELEGATOR_BY = new JetNodeType("DELEGATOR_BY", JetDelegatorByExpressionSpecifier.class);
JetNodeType DELEGATOR_SUPER_CALL = new JetNodeType("DELEGATOR_SUPER_CALL", JetDelegatorToSuperCall.class);
JetNodeType DELEGATOR_SUPER_CLASS = new JetNodeType("DELEGATOR_SUPER_CLASS", JetDelegatorToSuperClass.class);
JetNodeType CONSTRUCTOR_CALLEE = new JetNodeType("CONSTRUCTOR_CALLEE", JetConstructorCalleeExpression.class);
JetNodeType CONSTRUCTOR_CALLEE = new JetNodeType("CONSTRUCTOR_CALLEE", JetConstructorCalleeExpression.class);
JetNodeType VALUE_PARAMETER_LIST = new JetNodeType("VALUE_PARAMETER_LIST", JetParameterList.class);
JetNodeType VALUE_PARAMETER = new JetNodeType("VALUE_PARAMETER", JetParameter.class);
@@ -63,7 +63,7 @@ public class ConstructorDescriptorImpl extends FunctionDescriptorImpl implements
@NotNull
@Override
public Set<? extends FunctionDescriptor> getOverriddenFunctions() {
return null;
return Collections.emptySet();
}
@Override
@@ -1,14 +1,15 @@
package org.jetbrains.jet.lang.descriptors;
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.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.types.DescriptorSubstitutor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import org.jetbrains.jet.lang.types.Variance;
import java.util.Collections;
import java.util.List;
import java.util.Set;
@@ -22,7 +23,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
private JetType unsubstitutedReturnType;
private JetType receiverType;
private final Set<FunctionDescriptor> overriddenFunctions = Sets.newHashSet();
private final Set<FunctionDescriptor> overriddenFunctions = Sets.newLinkedHashSet();
private final FunctionDescriptor original;
public FunctionDescriptorImpl(
@@ -97,12 +98,14 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
}
@Override
public final FunctionDescriptor substitute(TypeSubstitutor substitutor) {
if (substitutor.isEmpty()) {
public final FunctionDescriptor substitute(TypeSubstitutor originalSubstitutor) {
if (originalSubstitutor.isEmpty()) {
return this;
}
FunctionDescriptorImpl substitutedDescriptor;
substitutedDescriptor = createSubstitutedCopy();
FunctionDescriptorImpl substitutedDescriptor = createSubstitutedCopy();
List<TypeParameterDescriptor> substitutedTypeParameters = Lists.newArrayList();
TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(getTypeParameters(), originalSubstitutor, substitutedDescriptor, substitutedTypeParameters);
JetType receiverType = getReceiverType();
JetType substitutedReceiverType = null;
@@ -125,7 +128,7 @@ public class FunctionDescriptorImpl extends DeclarationDescriptorImpl implements
substitutedDescriptor.initialize(
substitutedReceiverType,
Collections.<TypeParameterDescriptor>emptyList(), // TODO : questionable
substitutedTypeParameters,
substitutedValueParameters,
substitutedReturnType
);
@@ -13,6 +13,8 @@ import org.jetbrains.jet.lang.types.*;
import java.util.*;
import static org.jetbrains.jet.lang.types.TypeSubstitutor.TypeSubstitution;
/**
* @author abreslav
*/
@@ -110,6 +112,59 @@ public class FunctionDescriptorUtil {
return parameterScope;
}
@NotNull
public static FunctionDescriptor substituteBounds(@NotNull FunctionDescriptor functionDescriptor) {
final List<TypeParameterDescriptor> typeParameters = functionDescriptor.getTypeParameters();
if (typeParameters.isEmpty()) return functionDescriptor;
final Map<TypeConstructor, TypeParameterDescriptor> typeConstructors = Maps.newHashMap();
for (TypeParameterDescriptor typeParameter : typeParameters) {
typeConstructors.put(typeParameter.getTypeConstructor(), typeParameter);
}
return functionDescriptor.substitute(new TypeSubstitutor(TypeSubstitution.EMPTY) {
@Override
public boolean inRange(@NotNull TypeConstructor typeConstructor) {
return typeConstructors.containsKey(typeConstructor);
}
@Override
public boolean isEmpty() {
return typeParameters.isEmpty();
}
@NotNull
@Override
public TypeSubstitution getSubstitution() {
throw new UnsupportedOperationException();
}
@NotNull
@Override
public JetType safeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
JetType substituted = substitute(type, howThisTypeIsUsed);
if (substituted == null) {
return ErrorUtils.createErrorType("Substitution failed");
}
return substituted;
}
@Override
public JetType substitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) {
TypeParameterDescriptor typeParameterDescriptor = typeConstructors.get(type.getConstructor());
if (typeParameterDescriptor != null) {
switch (howThisTypeIsUsed) {
case INVARIANT:
return type;
case IN_VARIANCE:
throw new UnsupportedOperationException(); // TODO : lower bounds
case OUT_VARIANCE:
return typeParameterDescriptor.getDefaultType();
}
}
return super.substitute(type, howThisTypeIsUsed);
}
});
}
public static class OverrideCompatibilityInfo {
private static final OverrideCompatibilityInfo SUCCESS = new OverrideCompatibilityInfo(false, "SUCCESS");
@@ -1,11 +1,8 @@
package org.jetbrains.jet.lang.descriptors;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import org.jetbrains.jet.lang.types.JetType;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
@@ -19,12 +16,6 @@ public interface FunctionGroup extends Named {
return "<empty>";
}
@NotNull
@Override
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
return OverloadResolutionResult.nameNotFound();
}
@Override
public boolean isEmpty() {
return true;
@@ -42,9 +33,6 @@ public interface FunctionGroup extends Named {
@Override
String getName();
@NotNull
OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes);
boolean isEmpty();
@NotNull
@@ -16,27 +16,40 @@ import java.util.List;
public class LazySubstitutingClassDescriptor implements ClassDescriptor {
private final ClassDescriptor original;
private final TypeSubstitutor originalSubstitutor;
private TypeSubstitutor newSubstitutor;
private List<TypeParameterDescriptor> typeParameters;
private TypeConstructor typeConstructor;
private final TypeSubstitutor substitutor;
public LazySubstitutingClassDescriptor(ClassDescriptor descriptor, TypeSubstitutor substitutor) {
this.original = descriptor;
this.substitutor = substitutor;
this.originalSubstitutor = substitutor;
}
private TypeSubstitutor getSubstitutor() {
if (newSubstitutor == null) {
if (originalSubstitutor.isEmpty()) {
newSubstitutor = originalSubstitutor;
}
else {
typeParameters = Lists.newArrayList();
newSubstitutor = DescriptorSubstitutor.substituteTypeParameters(original.getTypeConstructor().getParameters(), originalSubstitutor, this, typeParameters);
}
}
return newSubstitutor;
}
@NotNull
@Override
public TypeConstructor getTypeConstructor() {
TypeConstructor originalTypeConstructor = original.getTypeConstructor();
if (substitutor.isEmpty()) {
if (originalSubstitutor.isEmpty()) {
return originalTypeConstructor;
}
if (typeConstructor == null) {
List<TypeParameterDescriptor> parameters = Lists.newArrayList();
for (TypeParameterDescriptor parameterDescriptor : originalTypeConstructor.getParameters()) {
parameters.add(parameterDescriptor.substitute(substitutor));
}
TypeSubstitutor substitutor = getSubstitutor();
Collection<JetType> supertypes = Lists.newArrayList();
for (JetType supertype : originalTypeConstructor.getSupertypes()) {
supertypes.add(substitutor.substitute(supertype, Variance.INVARIANT));
@@ -47,7 +60,7 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
originalTypeConstructor.getAnnotations(),
originalTypeConstructor.isSealed(),
originalTypeConstructor.toString(),
parameters,
typeParameters,
supertypes
);
}
@@ -59,10 +72,10 @@ public class LazySubstitutingClassDescriptor implements ClassDescriptor {
@Override
public JetScope getMemberScope(List<TypeProjection> typeArguments) {
JetScope memberScope = original.getMemberScope(typeArguments);
if (substitutor.isEmpty()) {
if (originalSubstitutor.isEmpty()) {
return memberScope;
}
return new SubstitutingScope(memberScope, substitutor); // TODO : compose substitutors
return new SubstitutingScope(memberScope, getSubstitutor());
}
@NotNull
@@ -2,14 +2,9 @@ package org.jetbrains.jet.lang.descriptors;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.TypeSubstitutor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Collections;
import java.util.Set;
/**
@@ -31,30 +26,6 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
return functionGroup.getName();
}
@NotNull
@Override
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
OverloadResolutionResult resolutionResult = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
if (resolutionResult.isNothing()) return resolutionResult;
Collection<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
for (FunctionDescriptor function : resolutionResult.getFunctionDescriptors()) {
FunctionDescriptor functionDescriptor = substitute(function);
if (functionDescriptor != null) {
result.add(functionDescriptor);
}
}
return resolutionResult.newContents(result);
}
@Nullable
private FunctionDescriptor substitute(
@NotNull FunctionDescriptor functionDescriptor) {
if (substitutor.isEmpty()) return functionDescriptor;
return functionDescriptor.substitute(substitutor);
}
@Override
public boolean isEmpty() {
return functionGroup.isEmpty();
@@ -68,13 +39,14 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
functionDescriptors = functionGroup.getFunctionDescriptors();
}
else {
functionDescriptors = Sets.newHashSet();
Set<FunctionDescriptor> functionDescriptorSet = Sets.newLinkedHashSet();
for (FunctionDescriptor descriptor : functionGroup.getFunctionDescriptors()) {
FunctionDescriptor substitute = descriptor.substitute(substitutor);
if (substitute != null) {
functionDescriptors.add(substitute);
functionDescriptorSet.add(substitute);
}
}
functionDescriptors = Collections.unmodifiableSet(functionDescriptorSet);
}
}
return functionDescriptors;
@@ -103,8 +103,9 @@ public class TypeParameterDescriptor extends DeclarationDescriptorImpl implement
@NotNull
@Override
@Deprecated // Use the static method TypeParameterDescriptor.substitute()
public TypeParameterDescriptor substitute(TypeSubstitutor substitutor) {
throw new UnsupportedOperationException(); // TODO
throw new UnsupportedOperationException();
}
@Override
@@ -2,11 +2,8 @@ package org.jetbrains.jet.lang.descriptors;
import com.google.common.collect.Sets;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import org.jetbrains.jet.lang.types.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Collections;
import java.util.Set;
/**
@@ -15,6 +12,7 @@ import java.util.Set;
public class WritableFunctionGroup implements FunctionGroup {
private final String name;
private Set<FunctionDescriptor> functionDescriptors;
private Set<FunctionDescriptor> unmodifiableFunctionDescriptors;
public WritableFunctionGroup(String name) {
this.name = name;
@@ -34,51 +32,32 @@ public class WritableFunctionGroup implements FunctionGroup {
}
public void addFunction(@NotNull FunctionDescriptor functionDescriptor) {
getFunctionDescriptors().add(functionDescriptor);
getWritableFunctionDescriptors().add(functionDescriptor);
}
@Override
@NotNull
public Set<FunctionDescriptor> getFunctionDescriptors() {
if (unmodifiableFunctionDescriptors == null) {
unmodifiableFunctionDescriptors = Collections.unmodifiableSet(getWritableFunctionDescriptors());
}
return unmodifiableFunctionDescriptors;
}
private Set<FunctionDescriptor> getWritableFunctionDescriptors() {
if (functionDescriptors == null) {
functionDescriptors = Sets.newLinkedHashSet();
}
return functionDescriptors;
}
@NotNull
@Override
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
Set<FunctionDescriptor> functionDescriptors = getFunctionDescriptors();
if (functionDescriptors.isEmpty()) return OverloadResolutionResult.nameNotFound();
int typeArgCount = typeArguments.size();
int valueArgCount = positionedValueArgumentTypes.size();
List<FunctionDescriptor> result = new ArrayList<FunctionDescriptor>();
for (FunctionDescriptor functionDescriptor : functionDescriptors) {
// TODO : type argument inference breaks this logic
if (functionDescriptor.getTypeParameters().size() == typeArgCount) {
if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount &&
valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) {
FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor);
assert substitutedFunctionDescriptor != null;
result.add(substitutedFunctionDescriptor);
}
}
}
if (result.isEmpty()) {
assert !functionDescriptors.isEmpty();
if (functionDescriptors.size() == 1) {
return OverloadResolutionResult.singleFunctionArgumentMismatch(functionDescriptors.iterator().next());
}
}
if (result.size() == 1) {
return OverloadResolutionResult.success(result.get(0));
}
return OverloadResolutionResult.ambiguity(result);
}
@Override
public boolean isEmpty() {
return functionDescriptors == null || functionDescriptors.isEmpty();
}
public void addAllFunctions(@NotNull FunctionGroup functionGroup) {
if (functionGroup.isEmpty()) return;
getWritableFunctionDescriptors().addAll(functionGroup.getFunctionDescriptors());
}
}
@@ -24,7 +24,10 @@ public class JetConstructorCalleeExpression extends JetExpression {
return null;
}
JetTypeElement typeElement = typeReference.getTypeElement();
assert typeElement instanceof JetUserType;
if (typeElement == null) {
return null;
}
assert typeElement instanceof JetUserType : typeElement;
return ((JetUserType) typeElement).getReferenceExpression();
}
@@ -55,11 +55,16 @@ public class ChainedScope implements JetScope {
@NotNull
@Override
public FunctionGroup getFunctionGroup(@NotNull String name) {
for (JetScope jetScope : scopeChain) {
FunctionGroup functionGroup = jetScope.getFunctionGroup(name);
if (!functionGroup.isEmpty()) return functionGroup;
if (scopeChain.length == 0) {
return FunctionGroup.EMPTY;
}
return FunctionGroup.EMPTY;
WritableFunctionGroup result = new WritableFunctionGroup(name);
for (JetScope jetScope : scopeChain) {
result.addAllFunctions(jetScope.getFunctionGroup(name));
}
return result;
}
@NotNull
@@ -67,7 +67,7 @@ public class ClassDescriptorResolver {
: resolveDelegationSpecifiers(parameterScope, delegationSpecifiers, typeResolver);
boolean open = classElement.hasModifier(JetTokens.OPEN_KEYWORD);
final WritableScope memberDeclarations = new WritableScopeImpl(parameterScope, classDescriptor, trace.getErrorHandler());
final WritableScope memberDeclarations = new WritableScopeImpl(JetScope.EMPTY, classDescriptor, trace.getErrorHandler());
List<JetDeclaration> declarations = classElement.getDeclarations();
for (JetDeclaration declaration : declarations) {
@@ -0,0 +1,79 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.CollectingErrorHandler;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.JetDiagnostic;
import org.jetbrains.jet.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
public class DelegatingBindingTrace implements BindingTrace {
private final BindingContext parentContext;
private final MutableManyMap map = ManyMapImpl.create();
private final List<JetDiagnostic> diagnostics = Lists.newArrayList();
private final ErrorHandler errorHandler = new CollectingErrorHandler(diagnostics);
private final BindingContext bindingContext = new BindingContext() {
@Override
public Collection<JetDiagnostic> getDiagnostics() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
return DelegatingBindingTrace.this.get(slice, key);
}
};
public DelegatingBindingTrace(BindingContext parentContext) {
this.parentContext = parentContext;
}
@Override
@NotNull
public ErrorHandler getErrorHandler() {
return errorHandler;
}
@Override
public BindingContext getBindingContext() {
return bindingContext;
}
@Override
public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
map.put(slice, key, value);
}
@Override
public <K> void record(WritableSlice<K, Boolean> slice, K key) {
record(slice, key, true);
}
@Override
public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
if (map.containsKey(slice, key)) {
return map.get(slice, key);
}
return parentContext.get(slice, key);
}
public void addAllMyDataTo(BindingTrace trace) {
for (Map.Entry<ManyMapKey<?, ?>, ?> entry : map) {
ManyMapKey manyMapKey = entry.getKey();
Object value = entry.getValue();
//noinspection unchecked
trace.record(manyMapKey.getSlice(), manyMapKey.getKey(), value);
}
AnalyzingUtils.applyHandler(trace.getErrorHandler(), diagnostics);
}
}
@@ -1,87 +1,74 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
/**
* @author abreslav
*/
public class ScopeWithReceiver extends JetScopeImpl {
private final JetType receiverType;
private final JetScope outerScope;
private final JetTypeChecker typeChecker;
public ScopeWithReceiver(@NotNull JetScope outerScope, @NotNull JetType receiverType, @NotNull JetTypeChecker typeChecker) {
this.outerScope = outerScope;
this.receiverType = receiverType;
this.typeChecker = typeChecker;
}
@NotNull
@Override
public FunctionGroup getFunctionGroup(@NotNull String name) {
JetScope memberScope = receiverType.getMemberScope();
FunctionGroup functionGroup = memberScope.getFunctionGroup(name);
if (functionGroup.isEmpty()) {
return outerScope.getFunctionGroup(name);
// return FunctionDescriptorUtil.filteredFunctionGroup(outerScope.getFunctionGroup(name),
// new Function<FunctionDescriptor, Boolean>() {
// @Override
// public Boolean apply(@Nullable FunctionDescriptor functionDescriptor) {
// if (functionDescriptor == null) return false;
// JetType functionReceiverType = functionDescriptor.getReceiverType();
// if (functionReceiverType == null) {
// return false;
// }
// // TODO : in case of inferred type arguments, substitute the receiver type first
// return typeChecker.startForPairOfTypes(receiverType, functionReceiverType);
// }
// });
}
return functionGroup; // TODO
}
@Override
public ClassifierDescriptor getClassifier(@NotNull String name) {
return receiverType.getMemberScope().getClassifier(name);
}
@Override
public VariableDescriptor getVariable(@NotNull String name) {
VariableDescriptor variable = receiverType.getMemberScope().getVariable(name);
if (variable != null) {
return variable;
}
variable = outerScope.getVariable(name);
if (variable instanceof PropertyDescriptor) {
PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variable;
JetType receiverType = propertyDescriptor.getReceiverType();
// TODO : in case of type arguments, substitute the receiver type first
if (receiverType != null
&& typeChecker.isSubtypeOf(receiverType, receiverType)) {
return variable;
}
}
return null;
}
@Override
public NamespaceDescriptor getNamespace(@NotNull String name) {
return receiverType.getMemberScope().getNamespace(name);
}
@NotNull
@Override
public JetType getThisType() {
return receiverType;
}
@NotNull
@Override
public DeclarationDescriptor getContainingDeclaration() {
return outerScope.getContainingDeclaration();
}
}
//package org.jetbrains.jet.lang.resolve;
//
//import org.jetbrains.annotations.NotNull;
//import org.jetbrains.jet.lang.descriptors.*;
//import org.jetbrains.jet.lang.types.JetType;
//import org.jetbrains.jet.lang.types.JetTypeChecker;
//
///**
// * @author abreslav
// */
//public class ScopeWithReceiver extends JetScopeImpl {
//
// private final JetType receiverType;
// private final JetScope outerScope;
// private final JetTypeChecker typeChecker;
//
// public ScopeWithReceiver(@NotNull JetScope outerScope, @NotNull JetType receiverType, @NotNull JetTypeChecker typeChecker) {
// this.outerScope = outerScope;
// this.receiverType = receiverType;
// this.typeChecker = typeChecker;
// }
//
// @NotNull
// @Override
// public FunctionGroup getFunctionGroup(@NotNull String name) {
// WritableFunctionGroup result = new WritableFunctionGroup(name);
//
// result.addAllFunctions(receiverType.getMemberScope().getFunctionGroup(name));
// result.addAllFunctions(outerScope.getFunctionGroup(name));
//
// return result;
// }
//
// @Override
// public ClassifierDescriptor getClassifier(@NotNull String name) {
// return receiverType.getMemberScope().getClassifier(name);
// }
//
// @Override
// public VariableDescriptor getVariable(@NotNull String name) {
// VariableDescriptor variable = receiverType.getMemberScope().getVariable(name);
// if (variable != null) {
// return variable;
// }
// variable = outerScope.getVariable(name);
// if (variable instanceof PropertyDescriptor) {
// PropertyDescriptor propertyDescriptor = (PropertyDescriptor) variable;
// JetType receiverType = propertyDescriptor.getReceiverType();
// // TODO : in case of type arguments, substitute the receiver type first
// if (receiverType != null
// && typeChecker.isSubtypeOf(receiverType, receiverType)) {
// return variable;
// }
// }
// return null;
// }
//
// @Override
// public NamespaceDescriptor getNamespace(@NotNull String name) {
// return receiverType.getMemberScope().getNamespace(name);
// }
//
// @NotNull
// @Override
// public JetType getThisType() {
// return receiverType;
// }
//
// @NotNull
// @Override
// public DeclarationDescriptor getContainingDeclaration() {
// return outerScope.getContainingDeclaration();
// }
//}
@@ -14,7 +14,6 @@ import java.util.Collection;
public class SubstitutingScope implements JetScope {
private final JetScope workerScope;
// private final Map<TypeConstructor, TypeProjection> substitutionContext;
private final TypeSubstitutor substitutor;
private Collection<DeclarationDescriptor> allDescriptors;
@@ -60,7 +59,7 @@ public class SubstitutingScope implements JetScope {
@Override
public FunctionGroup getFunctionGroup(@NotNull String name) {
FunctionGroup functionGroup = workerScope.getFunctionGroup(name);
if (substitutor.isEmpty()) {
if (substitutor.isEmpty() || functionGroup.isEmpty()) {
return functionGroup;
}
return new LazySubstitutingFunctionGroup(substitutor, functionGroup);
@@ -1,79 +1,22 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.collect.Lists;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.CollectingErrorHandler;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.JetDiagnostic;
import org.jetbrains.jet.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
public class TemporaryBindingTrace implements BindingTrace {
private final BindingContext parentContext;
private final MutableManyMap map = ManyMapImpl.create();
private final List<JetDiagnostic> diagnostics = Lists.newArrayList();
private final ErrorHandler errorHandler = new CollectingErrorHandler(diagnostics);
public class TemporaryBindingTrace extends DelegatingBindingTrace {
private final BindingContext bindingContext = new BindingContext() {
@Override
public Collection<JetDiagnostic> getDiagnostics() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
return TemporaryBindingTrace.this.get(slice, key);
}
};
public TemporaryBindingTrace(BindingContext parentContext) {
this.parentContext = parentContext;
public static TemporaryBindingTrace create(BindingTrace trace) {
return new TemporaryBindingTrace(trace);
}
@Override
@NotNull
public ErrorHandler getErrorHandler() {
return errorHandler;
private final BindingTrace trace;
private TemporaryBindingTrace(BindingTrace trace) {
super(trace.getBindingContext());
this.trace = trace;
}
@Override
public BindingContext getBindingContext() {
return bindingContext;
public void commit() {
addAllMyDataTo(trace);
}
@Override
public <K, V> void record(WritableSlice<K, V> slice, K key, V value) {
map.put(slice, key, value);
}
@Override
public <K> void record(WritableSlice<K, Boolean> slice, K key) {
record(slice, key, true);
}
@Override
public <K, V> V get(ReadOnlySlice<K, V> slice, K key) {
if (map.containsKey(slice, key)) {
return map.get(slice, key);
}
return parentContext.get(slice, key);
}
public void addAllMyDataTo(BindingTrace trace) {
for (Map.Entry<ManyMapKey<?, ?>, ?> entry : map) {
ManyMapKey manyMapKey = entry.getKey();
Object value = entry.getValue();
//noinspection unchecked
trace.record(manyMapKey.getSlice(), manyMapKey.getKey(), value);
}
AnalyzingUtils.applyHandler(trace.getErrorHandler(), diagnostics);
}
}
}
@@ -478,6 +478,8 @@ public class TopDownAnalyzer {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void resolveBehaviorDeclarationBodies() {
bindOverrides();
resolveDelegationSpecifierLists();
resolveClassAnnotations();
@@ -488,8 +490,6 @@ public class TopDownAnalyzer {
resolveFunctionBodies();
checkIfPrimaryConstructorIsNecessary();
bindOverrides();
}
private void bindOverrides() {
@@ -580,7 +580,7 @@ public class TopDownAnalyzer {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
typeInferrer.getCallResolver().resolveCall(scopeForConstructor, call, NO_EXPECTED_TYPE);
typeInferrer.getCallResolver().resolveCall(scopeForConstructor, null, call, NO_EXPECTED_TYPE);
}
else {
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
@@ -685,7 +685,7 @@ public class TopDownAnalyzer {
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
typeInferrerForInitializers.getCallResolver().resolveCall(functionInnerScope, call, NO_EXPECTED_TYPE);
typeInferrerForInitializers.getCallResolver().resolveCall(functionInnerScope, null, call, NO_EXPECTED_TYPE);
}
}
@@ -196,49 +196,28 @@ public class WritableScopeImpl extends WritableScopeWithImports {
public FunctionGroup getFunctionGroup(@NotNull String name) {
addVariablesAsFunctions();
WritableFunctionGroup result = new WritableFunctionGroup(name);
FunctionGroup functionGroup = getFunctionGroups().get(name);
FunctionGroup constructors = null;
ClassifierDescriptor classifier = getClassifier(name);
if (classifier instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
constructors = classDescriptor.getConstructors();
}
if (functionGroup != null && !functionGroup.isEmpty()) {
if (constructors != null) {
WritableFunctionGroup result = new WritableFunctionGroup(name);
for (FunctionDescriptor functionDescriptor : functionGroup.getFunctionDescriptors()) {
result.addFunction(functionDescriptor);
}
for (FunctionDescriptor functionDescriptor : constructors.getFunctionDescriptors()) {
result.addFunction(functionDescriptor);
}
return result;
}
return functionGroup;
}
if (constructors != null && !constructors.isEmpty()) {
return constructors;
if (functionGroup != null) {
result.addAllFunctions(functionGroup);
}
// ClassifierDescriptor classifier = getClassifier(name);
// if (classifier instanceof ClassDescriptor) {
// ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
// result.addAllFunctions(classDescriptor.getConstructors());
// }
if (thisType != null) {
functionGroup = getThisType().getMemberScope().getFunctionGroup(name);
if (!functionGroup.isEmpty()) {
return functionGroup;
}
result.addAllFunctions(getThisType().getMemberScope().getFunctionGroup(name));
}
// TODO : this logic is questionable
functionGroup = getWorkerScope().getFunctionGroup(name);
if (!functionGroup.isEmpty()) return functionGroup;
// for (JetScope imported : getImports()) {
// FunctionGroup importedDescriptor = imported.getFunctionGroup(name);
// if (!importedDescriptor.isEmpty()) {
// return importedDescriptor;
// }
// }
// return functionGroup;
return super.getFunctionGroup(name);
result.addAllFunctions(getWorkerScope().getFunctionGroup(name));
result.addAllFunctions(super.getFunctionGroup(name));
return result;
}
private void addVariablesAsFunctions() {
@@ -3,10 +3,7 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.ErrorHandler;
import org.jetbrains.jet.lang.descriptors.ClassifierDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionGroup;
import org.jetbrains.jet.lang.descriptors.NamespaceDescriptor;
import org.jetbrains.jet.lang.descriptors.VariableDescriptor;
import org.jetbrains.jet.lang.descriptors.*;
import java.util.ArrayList;
import java.util.List;
@@ -63,13 +60,17 @@ public abstract class WritableScopeWithImports extends JetScopeAdapter implement
@NotNull
@Override
public FunctionGroup getFunctionGroup(@NotNull String name) {
if (getImports().isEmpty()) {
return FunctionGroup.EMPTY;
}
WritableFunctionGroup result = new WritableFunctionGroup(name);
for (JetScope imported : getImports()) {
FunctionGroup importedDescriptor = imported.getFunctionGroup(name);
if (!importedDescriptor.isEmpty()) {
return importedDescriptor;
FunctionGroup importedFunctions = imported.getFunctionGroup(name);
if (!importedFunctions.isEmpty()) {
result.addAllFunctions(importedFunctions);
}
}
return FunctionGroup.EMPTY;
return result;
}
@Override
@@ -48,13 +48,15 @@ public class WriteThroughScope extends WritableScopeWithImports {
@Override
@NotNull
public FunctionGroup getFunctionGroup(@NotNull String name) {
FunctionGroup functionGroup = writableWorker.getFunctionGroup(name);
if (!functionGroup.isEmpty()) return functionGroup; // TODO : Overloads from different places
WritableFunctionGroup result = new WritableFunctionGroup(name);
functionGroup = getWorkerScope().getFunctionGroup(name);
if (!functionGroup.isEmpty()) return functionGroup; // TODO : Overloads from different places
result.addAllFunctions(writableWorker.getFunctionGroup(name));
return super.getFunctionGroup(name); // Imports
result.addAllFunctions(getWorkerScope().getFunctionGroup(name));
result.addAllFunctions(super.getFunctionGroup(name)); // Imports
return result;
}
@Override
@@ -32,11 +32,11 @@ public class JavaPackageScope extends JetScopeImpl {
@NotNull
@Override
public FunctionGroup getFunctionGroup(@NotNull String name) {
ClassifierDescriptor classifier = getClassifier(name);
if (classifier instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
return classDescriptor.getConstructors();
}
// ClassifierDescriptor classifier = getClassifier(name);
// if (classifier instanceof ClassDescriptor) {
// ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
// return classDescriptor.getConstructors();
// }
return FunctionGroup.EMPTY;
}
@@ -93,9 +93,9 @@ public class CallMaker {
}
public static Call makeCall(final JetExpression calleeExpression, final List<JetExpression> argumentExpressions) {
List<ExpressionValueArgument> arguments = Lists.newArrayList();
List<ValueArgument> arguments = Lists.newArrayList();
for (JetExpression argumentExpression : argumentExpressions) {
arguments.add(new ExpressionValueArgument(argumentExpression));
arguments.add(makeValueArgument(argumentExpression));
}
return makeCallWithArguments(calleeExpression, arguments);
}
@@ -114,4 +114,7 @@ public class CallMaker {
return makeCall(arrayAccessExpression, arguments);
}
public static ValueArgument makeValueArgument(JetExpression expression) {
return new ExpressionValueArgument(expression);
}
}
@@ -1,5 +1,8 @@
package org.jetbrains.jet.lang.types;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
@@ -22,21 +25,31 @@ import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
*/
public class CallResolver {
private static abstract class ResolutionTask {
private static class ResolutionTask {
private final Collection<FunctionDescriptor> candidates;
private final JetExpression receiver;
private final JetType receiverType;
private final List<JetTypeProjection> typeArguments;
private final List<? extends ValueArgument> valueArguments;
private final List<JetExpression> functionLiteralArguments;
protected ResolutionTask(
@NotNull Collection<FunctionDescriptor> candidates,
@Nullable JetExpression receiver,
@Nullable JetType receiverType,
@NotNull List<JetTypeProjection> typeArguments,
@NotNull List<? extends ValueArgument> valueArguments) {
@NotNull List<? extends ValueArgument> valueArguments,
@NotNull List<JetExpression> functionLiteralArguments) {
this.candidates = candidates;
this.receiver = receiver;
this.receiverType = receiverType;
this.typeArguments = typeArguments;
this.valueArguments = valueArguments;
this.functionLiteralArguments = functionLiteralArguments;
}
public ResolutionTask(
@NotNull Collection<FunctionDescriptor> candidates,
@Nullable JetType receiverType,
@NotNull Call call) {
this(candidates, receiverType, call.getTypeArguments(), call.getValueArguments(), call.getFunctionLiteralArguments());
}
@NotNull
@@ -45,8 +58,8 @@ public class CallResolver {
}
@Nullable
public JetExpression getReceiver() {
return receiver;
public JetType getReceiverType() {
return receiverType;
}
@NotNull
@@ -59,15 +72,24 @@ public class CallResolver {
return valueArguments;
}
public abstract void bindFunctionReference(@NotNull BindingTrace trace, @NotNull FunctionDescriptor functionDescriptor);
@NotNull
public List<JetExpression> getFunctionLiteralArguments() {
return functionLiteralArguments;
}
}
public abstract void reportOverallResolutionError(@NotNull BindingTrace trace, @NotNull String message);
private interface TracingStrategy {
void bindFunctionReference(@NotNull BindingTrace trace, @NotNull FunctionDescriptor functionDescriptor);
public abstract void reportWrongTypeArguments(@NotNull BindingTrace trace, @NotNull String message);
void reportOverallResolutionError(@NotNull BindingTrace trace, @NotNull String message);
public abstract void reportWrongValueArguments(@NotNull BindingTrace trace, @NotNull String message);
void reportWrongTypeArguments(@NotNull BindingTrace trace, @NotNull String message);
public abstract void reportUnresolvedFunctionReference(@NotNull BindingTrace trace);
void reportWrongValueArguments(@NotNull BindingTrace trace, @NotNull String message);
void reportUnresolvedFunctionReference(@NotNull BindingTrace trace);
void reportErrorOnFunctionReference(BindingTrace trace, String message);
}
private final BindingTrace trace;
@@ -87,10 +109,11 @@ public class CallResolver {
@Nullable
public JetType resolveCall(
@NotNull JetScope scope,
@Nullable JetType receiverType,
@NotNull JetCallElement call,
@NotNull JetType expectedType
) {
FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(scope, null, call, expectedType);
FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(scope, receiverType, call, expectedType);
return functionDescriptor == null ? null : functionDescriptor.getReturnType();
}
@@ -100,47 +123,55 @@ public class CallResolver {
@NotNull final Call call,
@NotNull final JetReferenceExpression functionReference,
@NotNull String name,
@Nullable JetExpression receiver,
@Nullable JetType receiverType,
@NotNull JetType expectedType) {
Collection<FunctionDescriptor> candidates;
if (receiver != null) {
JetType type = typeInferrer.getServices(trace).getType(scope, receiver, false, NO_EXPECTED_TYPE);
if (type == null) {
return null; // TODO : check parameter types anyway?
}
// TODO : autocasts
// TODO : nullability
candidates = type.getMemberScope().getFunctionGroup(name).getFunctionDescriptors();
}
else {
candidates = scope.getFunctionGroup(name).getFunctionDescriptors();
}
return resolveCallToFunctionDescriptor(scope, receiver, call, functionReference.getNode(), expectedType, candidates, functionReference);
// TODO : autocasts
// TODO : nullability
List<ResolutionTask> tasks = computePrioritizedTasks(scope, receiverType, call, name);
return resolveCallToFunctionDescriptor(scope, call, functionReference.getNode(), expectedType, tasks, functionReference);
}
@Nullable
public FunctionDescriptor resolveSimpleCallToFunctionDescriptor(
@NotNull JetScope scope,
@Nullable JetExpression receiver,
@Nullable JetType receiverType,
@NotNull final JetCallElement call,
@NotNull JetType expectedType
) {
List<ResolutionTask> prioritizedTasks;
JetExpression calleeExpression = call.getCalleeExpression();
Collection<FunctionDescriptor> candidates;
final JetReferenceExpression functionReference;
if (calleeExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression expression = (JetSimpleNameExpression) calleeExpression;
functionReference = expression;
candidates = scope.getFunctionGroup(expression.getReferencedName()).getFunctionDescriptors();
String name = expression.getReferencedName();
if (name == null) return null;
prioritizedTasks = computePrioritizedTasks(scope, receiverType, call, name);
}
else if (calleeExpression instanceof JetConstructorCalleeExpression) {
assert receiverType == null;
prioritizedTasks = Lists.newArrayList();
JetConstructorCalleeExpression expression = (JetConstructorCalleeExpression) calleeExpression;
functionReference = expression.getConstructorReferenceExpression();
JetType constructedType = typeResolver.resolveType(scope, expression.getTypeReference());
if (functionReference == null) {
return null; // No type there
}
JetTypeReference typeReference = expression.getTypeReference();
JetType constructedType = typeResolver.resolveType(scope, typeReference);
DeclarationDescriptor declarationDescriptor = constructedType.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
candidates = classDescriptor.getConstructors().getFunctionDescriptors();
Set<FunctionDescriptor> members = classDescriptor.getConstructors().getFunctionDescriptors();
if (members.isEmpty()) {
trace.getErrorHandler().genericError(call.getValueArgumentList().getNode(), "This class does not have a constructor");
return null;
}
addTask(prioritizedTasks, null, call, members);
}
else {
trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class");
@@ -148,22 +179,76 @@ public class CallResolver {
}
}
else {
throw new UnsupportedOperationException("Type argument inference not implemented");
throw new UnsupportedOperationException("Type argument inference not implemented for " + call);
}
return resolveCallToFunctionDescriptor(scope, receiver, call, call.getNode(), expectedType, candidates, functionReference);
return resolveCallToFunctionDescriptor(scope, call, call.getNode(), expectedType, prioritizedTasks, functionReference);
}
private List<ResolutionTask> computePrioritizedTasks(JetScope scope, JetType receiverType, Call call, String name) {
List<ResolutionTask> result = Lists.newArrayList();
if (receiverType != null) {
Collection<FunctionDescriptor> extensionFunctions = Sets.newLinkedHashSet(scope.getFunctionGroup(name).getFunctionDescriptors());
for (Iterator<FunctionDescriptor> iterator = extensionFunctions.iterator(); iterator.hasNext(); ) {
FunctionDescriptor functionDescriptor = iterator.next();
if (functionDescriptor.getReceiverType() == null) {
iterator.remove();
}
}
List<FunctionDescriptor> nonlocals = Lists.newArrayList();
List<FunctionDescriptor> locals = Lists.newArrayList();
splitLexicallyLocalDescriptors(extensionFunctions, scope.getContainingDeclaration(), locals, nonlocals);
Set<FunctionDescriptor> members = Sets.newHashSet(receiverType.getMemberScope().getFunctionGroup(name).getFunctionDescriptors());
addConstrtuctors(receiverType.getMemberScope(), name, members);
addTask(result, receiverType, call, locals);
addTask(result, null, call, members);
addTask(result, receiverType, call, nonlocals);
}
else {
Collection<FunctionDescriptor> functions = Sets.newLinkedHashSet(scope.getFunctionGroup(name).getFunctionDescriptors());
for (Iterator<FunctionDescriptor> iterator = functions.iterator(); iterator.hasNext(); ) {
FunctionDescriptor functionDescriptor = iterator.next();
if (functionDescriptor.getReceiverType() != null) {
iterator.remove();
}
}
addConstrtuctors(scope, name, functions);
List<FunctionDescriptor> nonlocals = Lists.newArrayList();
List<FunctionDescriptor> locals = Lists.newArrayList();
splitLexicallyLocalDescriptors(functions, scope.getContainingDeclaration(), locals, nonlocals);
addTask(result, receiverType, call, locals);
addTask(result, receiverType, call, nonlocals);
}
return result;
}
private void addTask(List<ResolutionTask> result, JetType receiverType, Call call, Collection<FunctionDescriptor> candidates) {
if (candidates.isEmpty()) return;
result.add(new ResolutionTask(candidates, receiverType, call));
}
private void addConstrtuctors(JetScope scope, String name, Collection<FunctionDescriptor> functions) {
ClassifierDescriptor classifier = scope.getClassifier(name);
if (classifier instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
functions.addAll(classDescriptor.getConstructors().getFunctionDescriptors());
}
}
private FunctionDescriptor resolveCallToFunctionDescriptor(
JetScope scope,
final JetExpression receiver,
final Call call,
final ASTNode callNode,
JetType expectedType,
final Collection<FunctionDescriptor> candidates,
final JetReferenceExpression functionReference) {
ResolutionTask task = new ResolutionTask(candidates, receiver, call.getTypeArguments(), call.getValueArguments()) {
@NotNull JetScope scope,
@NotNull final Call call,
@NotNull final ASTNode callNode,
@NotNull JetType expectedType,
@NotNull final List<ResolutionTask> prioritizedTasks, // high to low priority
@NotNull final JetReferenceExpression functionReference) {
TemporaryBindingTrace traceForFirstNonemptyCandidateSet = null;
TracingStrategy tracing = new TracingStrategy() {
@Override
public void bindFunctionReference(@NotNull BindingTrace trace, @NotNull FunctionDescriptor functionDescriptor) {
trace.record(BindingContext.REFERENCE_TARGET, functionReference, functionDescriptor);
@@ -207,14 +292,38 @@ public class CallResolver {
public void reportUnresolvedFunctionReference(@NotNull BindingTrace trace) {
trace.getErrorHandler().unresolvedReference(functionReference);
}
@Override
public void reportErrorOnFunctionReference(BindingTrace trace, String message) {
trace.getErrorHandler().genericError(functionReference.getNode(), message);
}
};
return performResolution(scope, expectedType, task);
for (ResolutionTask task : prioritizedTasks) {
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace);
FunctionDescriptor functionDescriptor = performResolution(temporaryTrace, scope, expectedType, task, tracing);
if (functionDescriptor != null) {
temporaryTrace.commit();
return functionDescriptor;
}
if (traceForFirstNonemptyCandidateSet == null && !task.getCandidates().isEmpty()) {
traceForFirstNonemptyCandidateSet = temporaryTrace;
}
}
if (traceForFirstNonemptyCandidateSet != null) {
traceForFirstNonemptyCandidateSet.commit();
}
else {
trace.getErrorHandler().unresolvedReference(functionReference);
}
return null;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private boolean mapValueArgumentsToParameters(
@NotNull ResolutionTask task,
@NotNull TracingStrategy tracing,
@NotNull FunctionDescriptor candidate,
@NotNull BindingTrace temporaryTrace,
@NotNull Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters
@@ -222,6 +331,7 @@ public class CallResolver {
Set<ValueParameterDescriptor> usedParameters = Sets.newHashSet();
List<ValueParameterDescriptor> valueParameters = candidate.getValueParameters();
Map<String, ValueParameterDescriptor> parameterByName = Maps.newHashMap();
for (ValueParameterDescriptor valueParameter : valueParameters) {
parameterByName.put(valueParameter.getName(), valueParameter);
@@ -229,22 +339,25 @@ public class CallResolver {
List<? extends ValueArgument> valueArguments = task.getValueArguments();
boolean error = false;
boolean someNamed = false;
boolean somePositioned = false;
boolean error = false;
for (int i = 0; i < valueArguments.size(); i++) {
ValueArgument valueArgument = valueArguments.get(i);
if (valueArgument.isNamed()) {
someNamed = true;
ASTNode nameNode = valueArgument.getArgumentName().getNode();
if (somePositioned) {
temporaryTrace.getErrorHandler().genericError(valueArgument.getArgumentName().getNode(), "Mixing named and positioned arguments in not allowed");
temporaryTrace.getErrorHandler().genericError(nameNode, "Mixing named and positioned arguments in not allowed");
error = true;
}
else {
ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(valueArgument.getArgumentName().getName());
usedParameters.add(valueParameterDescriptor);
if (usedParameters.add(valueParameterDescriptor)) {
temporaryTrace.getErrorHandler().genericError(nameNode, "An argument is already passed for this parameter");
}
if (valueParameterDescriptor == null) {
temporaryTrace.getErrorHandler().genericError(valueArgument.getArgumentName().getNode(), "Cannot find a parameter with this name");
temporaryTrace.getErrorHandler().genericError(nameNode, "Cannot find a parameter with this name");
error = true;
}
else {
@@ -260,13 +373,13 @@ public class CallResolver {
error = true;
}
else {
if (i < valueParameters.size()) {
int parameterCount = valueParameters.size();
if (i < parameterCount) {
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(i);
usedParameters.add(valueParameterDescriptor);
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
}
else if (!valueParameters.isEmpty()) {
ValueParameterDescriptor valueParameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (valueParameterDescriptor.isVararg()) {
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
@@ -285,10 +398,51 @@ public class CallResolver {
}
}
List<JetExpression> functionLiteralArguments = task.getFunctionLiteralArguments();
if (!functionLiteralArguments.isEmpty()) {
JetExpression possiblyLabeledFunctionLiteral = functionLiteralArguments.get(0);
if (valueParameters.isEmpty()) {
temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Too many arguments");
error = true;
} else {
JetFunctionLiteralExpression functionLiteral;
if (possiblyLabeledFunctionLiteral instanceof JetLabelQualifiedExpression) {
JetLabelQualifiedExpression labeledFunctionLiteral = (JetLabelQualifiedExpression) possiblyLabeledFunctionLiteral;
functionLiteral = (JetFunctionLiteralExpression) labeledFunctionLiteral.getLabeledExpression();
}
else {
functionLiteral = (JetFunctionLiteralExpression) possiblyLabeledFunctionLiteral;
}
ValueParameterDescriptor parameterDescriptor = valueParameters.get(valueParameters.size() - 1);
if (parameterDescriptor.isVararg()) {
temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Passing value as a vararg is only allowed inside a parenthesized argument list");
error = true;
}
else {
if (!usedParameters.add(parameterDescriptor)) {
temporaryTrace.getErrorHandler().genericError(possiblyLabeledFunctionLiteral.getNode(), "Too many arguments");
error = true;
}
else {
argumentsToParameters.put(CallMaker.makeValueArgument(functionLiteral), parameterDescriptor);
}
}
}
for (int i = 1; i < functionLiteralArguments.size(); i++) {
JetExpression argument = functionLiteralArguments.get(i);
temporaryTrace.getErrorHandler().genericError(argument.getNode(), "Only one function literal is allowed outside a parenthesized argument list");
error = true;
}
}
for (ValueParameterDescriptor valueParameter : valueParameters) {
if (!usedParameters.contains(valueParameter)) {
if (!valueParameter.hasDefaultValue()) {
task.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName());
tracing.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName());
error = true;
}
}
@@ -297,58 +451,77 @@ public class CallResolver {
}
@Nullable
private FunctionDescriptor performResolution(@NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task) {
Map<FunctionDescriptor, FunctionDescriptor> successfulCandidates = Maps.newHashMap();
Set<FunctionDescriptor> failedCandidates = Sets.newHashSet();
private FunctionDescriptor performResolution(@NotNull BindingTrace trace, @NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task, @NotNull TracingStrategy tracing) {
Map<FunctionDescriptor, FunctionDescriptor> successfulCandidates = Maps.newLinkedHashMap();
Set<FunctionDescriptor> failedCandidates = Sets.newLinkedHashSet();
Map<FunctionDescriptor, ConstraintSystem.Solution> solutions = Maps.newHashMap();
Map<FunctionDescriptor, TemporaryBindingTrace> traces = Maps.newHashMap();
for (FunctionDescriptor candidate : task.getCandidates()) {
TemporaryBindingTrace temporaryTrace = new TemporaryBindingTrace(trace.getBindingContext());
TemporaryBindingTrace temporaryTrace = TemporaryBindingTrace.create(trace);
traces.put(candidate, temporaryTrace);
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace);
task.bindFunctionReference(temporaryTrace, candidate);
tracing.bindFunctionReference(temporaryTrace, candidate);
Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters = Maps.newHashMap();
boolean error = mapValueArgumentsToParameters(task, candidate, temporaryTrace, argumentsToParameters);
boolean error = mapValueArgumentsToParameters(task, tracing, candidate, temporaryTrace, argumentsToParameters);
if (error) continue;
if (task.getTypeArguments().isEmpty()) {
// Type argument inference
ConstraintSystem constraintSystem = new ConstraintSystem();
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
}
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
ValueArgument valueArgument = entry.getKey();
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
JetExpression expression = valueArgument.getArgumentExpression();
// TODO : more attempts, with different expected types
JetType type = temporaryServices.getType(scope, expression, false, NO_EXPECTED_TYPE);
if (type != null) {
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
if (candidate.getTypeParameters().isEmpty()) {
if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, Functions.<ValueParameterDescriptor>identity())
&& checkReceiver(task, tracing, candidate, temporaryTrace)) {
successfulCandidates.put(candidate, candidate);
}
else {
failedCandidates.add(candidate);
}
}
if (expectedType != NO_EXPECTED_TYPE) {
constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType);
}
ConstraintSystem.Solution solution = constraintSystem.solve();
solutions.put(candidate, solution);
if (solution.isSuccessful()) {
FunctionDescriptor substitute = candidate.substitute(solution.getSubstitutor());
assert substitute != null;
successfulCandidates.put(candidate, substitute);
}
else {
task.reportOverallResolutionError(temporaryTrace, "Type inference failed");
failedCandidates.add(candidate);
// Type argument inference
ConstraintSystem constraintSystem = new ConstraintSystem();
for (TypeParameterDescriptor typeParameterDescriptor : candidate.getTypeParameters()) {
constraintSystem.registerTypeVariable(typeParameterDescriptor, Variance.INVARIANT); // TODO
}
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
ValueArgument valueArgument = entry.getKey();
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
JetExpression expression = valueArgument.getArgumentExpression();
// TODO : more attempts, with different expected types
JetType type = temporaryServices.getType(scope, expression, false, NO_EXPECTED_TYPE);
if (type != null) {
constraintSystem.addSubtypingConstraint(type, valueParameterDescriptor.getOutType());
}
}
checkReceiverAbsence(task, tracing, candidate, temporaryTrace);
// Error is already reported if something is missing
JetType receiverType = task.getReceiverType();
JetType candidateReceiverType = candidate.getReceiverType();
if (receiverType != null && candidateReceiverType != null) {
constraintSystem.addSubtypingConstraint(receiverType, candidateReceiverType);
}
if (expectedType != NO_EXPECTED_TYPE) {
constraintSystem.addSubtypingConstraint(candidate.getReturnType(), expectedType);
}
ConstraintSystem.Solution solution = constraintSystem.solve();
solutions.put(candidate, solution);
if (solution.isSuccessful()) {
FunctionDescriptor substitute = candidate.substitute(solution.getSubstitutor());
assert substitute != null;
successfulCandidates.put(candidate, substitute);
}
else {
tracing.reportOverallResolutionError(temporaryTrace, "Type inference failed");
failedCandidates.add(candidate);
}
}
}
else {
@@ -362,57 +535,80 @@ public class CallResolver {
}
}
List<JetType> typeArguments = new ArrayList<JetType>();
for (JetTypeProjection projection : jetTypeArguments) {
// TODO : check that there's no projection
JetTypeReference typeReference = projection.getTypeReference();
if (typeReference != null) {
typeArguments.add(new TypeResolver(semanticServices, temporaryTrace, true).resolveType(scope, typeReference));
if (candidate.getTypeParameters().size() == jetTypeArguments.size()) {
List<JetType> typeArguments = new ArrayList<JetType>();
for (JetTypeProjection projection : jetTypeArguments) {
// TODO : check that there's no projection
JetTypeReference typeReference = projection.getTypeReference();
if (typeReference != null) {
typeArguments.add(new TypeResolver(semanticServices, temporaryTrace, true).resolveType(scope, typeReference));
}
}
}
checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate);
checkGenericBoundsInAFunctionCall(jetTypeArguments, typeArguments, candidate);
int typeArgCount = typeArguments.size();
if (candidate.getTypeParameters().size() == typeArgCount) {
FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, candidate);
assert substitutedFunctionDescriptor != null;
Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
final Map<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap = Maps.newHashMap();
for (ValueParameterDescriptor valueParameterDescriptor : substitutedFunctionDescriptor.getValueParameters()) {
parameterMap.put(valueParameterDescriptor.getOriginal(), valueParameterDescriptor);
}
boolean localError = false;
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
ValueArgument valueArgument = entry.getKey();
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
ValueParameterDescriptor substitutedParameter = parameterMap.get(valueParameterDescriptor.getOriginal());
assert substitutedParameter != null;
JetType parameterType = substitutedParameter.getOutType();
JetType type = temporaryServices.getType(scope, valueArgument.getArgumentExpression(), false, parameterType);
if (type == null) {
localError = true;
Function<ValueParameterDescriptor, ValueParameterDescriptor> mapFunction = new Function<ValueParameterDescriptor, ValueParameterDescriptor>() {
@Override
public ValueParameterDescriptor apply(ValueParameterDescriptor input) {
return parameterMap.get(input.getOriginal());
}
}
if (localError) {
failedCandidates.add(candidate);
}
else {
};
if (checkValueArgumentTypes(scope, temporaryServices, argumentsToParameters, mapFunction)
&& checkReceiver(task, tracing, substitutedFunctionDescriptor, temporaryTrace)) {
successfulCandidates.put(candidate, substitutedFunctionDescriptor);
}
else {
failedCandidates.add(candidate);
}
}
else {
failedCandidates.add(candidate);
task.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate));
tracing.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate));
}
}
}
return computeResultAndReportErrors(trace, tracing, successfulCandidates, failedCandidates, traces);
}
private boolean checkReceiver(ResolutionTask task, TracingStrategy tracing, FunctionDescriptor candidate, TemporaryBindingTrace temporaryTrace) {
if (!checkReceiverAbsence(task, tracing, candidate, temporaryTrace)) return false;
JetType receiverType = task.getReceiverType();
JetType candidateReceiverType = candidate.getReceiverType();
if (receiverType != null
&& candidateReceiverType != null
&& !semanticServices.getTypeChecker().isSubtypeOf(receiverType, candidateReceiverType)) {
tracing.reportErrorOnFunctionReference(temporaryTrace, "This function requires a receiver of type " + candidateReceiverType);
return false;
}
return true;
}
private boolean checkReceiverAbsence(ResolutionTask task, TracingStrategy tracing, FunctionDescriptor candidate, TemporaryBindingTrace temporaryTrace) {
JetType receiverType = task.getReceiverType();
JetType candidateReceiverType = candidate.getReceiverType();
if (receiverType != null) {
if (candidateReceiverType == null) {
tracing.reportErrorOnFunctionReference(temporaryTrace, "This function does not admit a receiver");
return false;
}
}
else if (candidateReceiverType != null) {
tracing.reportErrorOnFunctionReference(temporaryTrace, "Receiver is missing" + candidateReceiverType);
return false;
}
return true;
}
private FunctionDescriptor computeResultAndReportErrors(BindingTrace trace, TracingStrategy tracing, Map<FunctionDescriptor, FunctionDescriptor> successfulCandidates, Set<FunctionDescriptor> failedCandidates, Map<FunctionDescriptor, TemporaryBindingTrace> traces) {
if (successfulCandidates.size() > 0) {
if (successfulCandidates.size() == 1) {
Map.Entry<FunctionDescriptor, FunctionDescriptor> entry = successfulCandidates.entrySet().iterator().next();
@@ -420,25 +616,18 @@ public class CallResolver {
FunctionDescriptor result = entry.getValue();
TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor);
temporaryTrace.addAllMyDataTo(trace);
temporaryTrace.commit();
return result;
}
else {
Map<FunctionDescriptor, TemporaryBindingTrace> maximallySpecific = Maps.newHashMap();
meLoop:
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> myEntry : successfulCandidates.entrySet()) {
FunctionDescriptor me = myEntry.getValue();
TemporaryBindingTrace myTrace = traces.get(myEntry.getKey());
for (FunctionDescriptor other : successfulCandidates.values()) {
if (other == me) continue;
if (!moreSpecific(me, other) || moreSpecific(other, me)) continue meLoop;
}
maximallySpecific.put(me, myTrace);
FunctionDescriptor maximallySpecific = findMaximallySpecific(successfulCandidates, traces, false);
if (maximallySpecific != null) {
return maximallySpecific;
}
if (maximallySpecific.size() == 1) {
Map.Entry<FunctionDescriptor, TemporaryBindingTrace> result = maximallySpecific.entrySet().iterator().next();
result.getValue().addAllMyDataTo(trace);
return result.getKey();
FunctionDescriptor maximallySpecificGenericsDiscriminated = findMaximallySpecific(successfulCandidates, traces, true);
if (maximallySpecificGenericsDiscriminated != null) {
return maximallySpecificGenericsDiscriminated;
}
StringBuilder stringBuilder = new StringBuilder();
@@ -446,14 +635,14 @@ public class CallResolver {
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" ");
}
task.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + stringBuilder);
tracing.reportOverallResolutionError(trace, "Overload resolution ambiguity: " + stringBuilder);
}
}
else if (!failedCandidates.isEmpty()) {
if (failedCandidates.size() == 1) {
FunctionDescriptor functionDescriptor = failedCandidates.iterator().next();
TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor);
temporaryTrace.addAllMyDataTo(trace);
temporaryTrace.commit();
}
else {
StringBuilder stringBuilder = new StringBuilder();
@@ -461,16 +650,65 @@ public class CallResolver {
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" ");
}
task.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " + stringBuilder);
tracing.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " + stringBuilder);
}
}
else {
task.reportUnresolvedFunctionReference(trace);
tracing.reportUnresolvedFunctionReference(trace);
}
return null;
}
private boolean moreSpecific(FunctionDescriptor f, FunctionDescriptor g) {
private boolean checkValueArgumentTypes(JetScope scope, JetTypeInferrer.Services temporaryServices, Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters, Function<ValueParameterDescriptor, ValueParameterDescriptor> parameterMap) {
for (Map.Entry<ValueArgument, ValueParameterDescriptor> entry : argumentsToParameters.entrySet()) {
ValueArgument valueArgument = entry.getKey();
ValueParameterDescriptor valueParameterDescriptor = entry.getValue();
ValueParameterDescriptor substitutedParameter = parameterMap.apply(valueParameterDescriptor);
assert substitutedParameter != null;
JetType parameterType = substitutedParameter.getOutType();
JetType type = temporaryServices.getType(scope, valueArgument.getArgumentExpression(), false, parameterType);
if (type == null || !semanticServices.getTypeChecker().isSubtypeOf(type, parameterType)) {
return false;
}
}
return true;
}
@Nullable
private FunctionDescriptor findMaximallySpecific(Map<FunctionDescriptor, FunctionDescriptor> candidates, Map<FunctionDescriptor, TemporaryBindingTrace> traces, boolean discriminateGenericFunctions) {
Map<FunctionDescriptor, TemporaryBindingTrace> maximallySpecific = Maps.newHashMap();
meLoop:
for (Map.Entry<FunctionDescriptor, FunctionDescriptor> myEntry : candidates.entrySet()) {
FunctionDescriptor me = myEntry.getValue();
TemporaryBindingTrace myTrace = traces.get(myEntry.getKey());
for (FunctionDescriptor other : candidates.values()) {
if (other == me) continue;
if (!moreSpecific(me, other, discriminateGenericFunctions) || moreSpecific(other, me, discriminateGenericFunctions)) continue meLoop;
}
maximallySpecific.put(me, myTrace);
}
if (maximallySpecific.size() == 1) {
Map.Entry<FunctionDescriptor, TemporaryBindingTrace> result = maximallySpecific.entrySet().iterator().next();
result.getValue().commit();
return result.getKey();
}
return null;
}
/**
* Let < mean "more specific"
* Subtype < supertype
* Double < Float
* Int < Long
* Int < Short < Byte
*/
private boolean moreSpecific(FunctionDescriptor f, FunctionDescriptor g, boolean discriminateGenericFunctions) {
if (overrides(f, g)) return true;
if (overrides(g, f)) return false;
List<ValueParameterDescriptor> fParams = f.getValueParameters();
List<ValueParameterDescriptor> gParams = g.getValueParameters();
@@ -480,13 +718,62 @@ public class CallResolver {
JetType fParamType = fParams.get(i).getOutType();
JetType gParamType = gParams.get(i).getOutType();
if (!JetTypeChecker.INSTANCE.isSubtypeOf(fParamType, gParamType)) {
if (!semanticServices.getTypeChecker().isSubtypeOf(fParamType, gParamType)
&& !numericTypeMoreSpecific(fParamType, gParamType)
) {
return false;
}
}
if (discriminateGenericFunctions && isGenericFunction(f)) {
if (!isGenericFunction(g)) {
return false;
}
// g is generic, too
return moreSpecific(FunctionDescriptorUtil.substituteBounds(f), FunctionDescriptorUtil.substituteBounds(g), false);
}
return true;
}
private boolean isGenericFunction(FunctionDescriptor f) {
return !f.getOriginal().getTypeParameters().isEmpty();
}
private boolean numericTypeMoreSpecific(@NotNull JetType specific, @NotNull JetType general) {
JetStandardLibrary standardLibrary = semanticServices.getStandardLibrary();
JetType _double = standardLibrary.getDoubleType();
JetType _float = standardLibrary.getFloatType();
JetType _long = standardLibrary.getLongType();
JetType _int = standardLibrary.getIntType();
JetType _byte = standardLibrary.getByteType();
JetType _short = standardLibrary.getShortType();
if (eq(specific, _double) && eq(general, _float)) return true;
if (eq(specific, _int)) {
if (eq(general, _long)) return true;
if (eq(general, _byte)) return true;
if (eq(general, _short)) return true;
}
if (eq(specific, _short) && eq(general, _byte)) return true;
return false;
}
private boolean eq(@NotNull JetType a, @NotNull JetType b) {
return semanticServices.getTypeChecker().isSubtypeOf(a, b) && semanticServices.getTypeChecker().isSubtypeOf(b, a);
}
private boolean overrides(@NotNull FunctionDescriptor f, @NotNull FunctionDescriptor g) {
Set<? extends FunctionDescriptor> overriddenFunctions = f.getOverriddenFunctions();
FunctionDescriptor originalG = g.getOriginal();
for (FunctionDescriptor overriddenFunction : overriddenFunctions) {
if (originalG.equals(overriddenFunction.getOriginal())) return true;
}
return false;
}
public void checkGenericBoundsInAFunctionCall(List<JetTypeProjection> jetTypeArguments, List<JetType> typeArguments, FunctionDescriptor functionDescriptor) {
Map<TypeConstructor, TypeProjection> context = Maps.newHashMap();
@@ -507,9 +794,126 @@ public class CallResolver {
}
@NotNull
public OverloadResolutionResult resolveExactSignature(@NotNull JetScope scope, @NotNull JetType receiver, @NotNull String name, @NotNull List<JetType> jetTypes) {
// TODO
return OverloadResolutionResult.nameNotFound();
public OverloadResolutionResult resolveExactSignature(@NotNull JetScope scope, @Nullable JetType receiverType, @NotNull String name, @NotNull List<JetType> parameterTypes) {
List<FunctionDescriptor> result = findCandidatesByExactSignature(scope, receiverType, name, parameterTypes);
return listToOverloadResolutionResult(result);
}
private List<FunctionDescriptor> findCandidatesByExactSignature(JetScope scope, JetType receiverType, String name, List<JetType> parameterTypes) {
List<FunctionDescriptor> result = Lists.newArrayList();
if (receiverType != null) {
Set<FunctionDescriptor> extensionFunctionDescriptors = scope.getFunctionGroup(name).getFunctionDescriptors();
List<FunctionDescriptor> nonlocal = Lists.newArrayList();
List<FunctionDescriptor> local = Lists.newArrayList();
splitLexicallyLocalDescriptors(extensionFunctionDescriptors, scope.getContainingDeclaration(), local, nonlocal);
if (findExtensionFunctions(local, receiverType, parameterTypes, result)) {
return result;
}
Set<FunctionDescriptor> functionDescriptors = receiverType.getMemberScope().getFunctionGroup(name).getFunctionDescriptors();
if (lookupExactSignature(functionDescriptors, parameterTypes, result)) {
return result;
}
findExtensionFunctions(nonlocal, receiverType, parameterTypes, result);
return result;
}
else {
lookupExactSignature(scope.getFunctionGroup(name).getFunctionDescriptors(), parameterTypes, result);
return result;
}
}
private boolean lookupExactSignature(Set<FunctionDescriptor> candidates, List<JetType> parameterTypes, List<FunctionDescriptor> result) {
boolean found = false;
for (FunctionDescriptor functionDescriptor : candidates) {
if (functionDescriptor.getReceiverType() != null) continue;
if (!functionDescriptor.getTypeParameters().isEmpty()) continue;
if (!checkValueParameters(functionDescriptor, parameterTypes)) continue;
result.add(functionDescriptor);
found = true;
}
return found;
}
private OverloadResolutionResult listToOverloadResolutionResult(List<FunctionDescriptor> result) {
if (result.isEmpty()) {
return OverloadResolutionResult.nameNotFound();
}
else if (result.size() == 1) {
return OverloadResolutionResult.success(result.get(0));
}
else {
return OverloadResolutionResult.ambiguity(result);
}
}
private boolean findExtensionFunctions(Collection<FunctionDescriptor> candidates, JetType receiverType, List<JetType> parameterTypes, List<FunctionDescriptor> result) {
boolean found = false;
for (FunctionDescriptor functionDescriptor : candidates) {
JetType functionReceiverType = functionDescriptor.getReceiverType();
if (functionReceiverType == null) continue;
if (!functionDescriptor.getTypeParameters().isEmpty()) continue;
if (!semanticServices.getTypeChecker().isSubtypeOf(receiverType, functionReceiverType)) continue;
if (!checkValueParameters(functionDescriptor, parameterTypes))continue;
result.add(functionDescriptor);
found = true;
}
return found;
}
private <T extends DeclarationDescriptor> void splitLexicallyLocalDescriptors(
Collection<? extends T> allDescriptors, DeclarationDescriptor containerOfTheCurrentLocality, List<? super T> local, List<? super T> nonlocal) {
for (T descriptor : allDescriptors) {
if (isLocal(containerOfTheCurrentLocality, descriptor)) {
local.add(descriptor);
}
else {
nonlocal.add(descriptor);
}
}
}
/**
* The primary case for local extensions is the following:
*
* I had a locally declared extension function or a local variable of function type called foo
* And I called it on my x
* Now, someone added function foo() to the class of x
* My code should not change
*
* thus
*
* local extension prevail over members (and members prevail over all non-local extensions)
*/
private boolean isLocal(DeclarationDescriptor containerOfTheCurrentLocality, DeclarationDescriptor candidate) {
DeclarationDescriptor parent = candidate.getContainingDeclaration();
if (!(parent instanceof FunctionDescriptor)) {
return false;
}
FunctionDescriptor functionDescriptor = (FunctionDescriptor) parent;
DeclarationDescriptor current = containerOfTheCurrentLocality;
while (current != null) {
if (current == functionDescriptor) {
return true;
}
current = current.getContainingDeclaration();
}
return false;
}
private boolean checkValueParameters(@NotNull FunctionDescriptor functionDescriptor, @NotNull List<JetType> parameterTypes) {
List<ValueParameterDescriptor> valueParameters = functionDescriptor.getValueParameters();
if (valueParameters.size() != parameterTypes.size()) return false;
for (int i = 0; i < valueParameters.size(); i++) {
ValueParameterDescriptor valueParameter = valueParameters.get(i);
JetType expectedType = parameterTypes.get(i);
if (!eq(expectedType, valueParameter.getOutType())) return false;
}
return true;
}
}
@@ -0,0 +1,59 @@
package org.jetbrains.jet.lang.types;
import com.google.common.collect.Maps;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
public class DescriptorSubstitutor {
@NotNull
public static TypeSubstitutor substituteTypeParameters(
@NotNull List<TypeParameterDescriptor> typeParameters,
@NotNull final TypeSubstitutor originalSubstitutor,
@NotNull DeclarationDescriptor newContainingDeclaration,
@NotNull List<TypeParameterDescriptor> result) {
final Map<TypeConstructor, TypeProjection> mutableSubstitution = Maps.newHashMap();
TypeSubstitutor substitutor = TypeSubstitutor.create(new TypeSubstitutor.TypeSubstitution() {
@Override
public TypeProjection get(TypeConstructor key) {
if (originalSubstitutor.inRange(key)) {
return originalSubstitutor.getSubstitution().get(key);
}
return mutableSubstitution.get(key);
}
@Override
public boolean isEmpty() {
return originalSubstitutor.isEmpty() && mutableSubstitution.isEmpty();
}
});
for (TypeParameterDescriptor descriptor : typeParameters) {
TypeParameterDescriptor substituted = TypeParameterDescriptor.createForFurtherModification(
newContainingDeclaration,
descriptor.getAnnotations(),
descriptor.getVariance(),
descriptor.getName(),
descriptor.getIndex());
mutableSubstitution.put(descriptor.getTypeConstructor(), new TypeProjection(substituted.getDefaultType()));
for (JetType upperBound : descriptor.getUpperBounds()) {
substituted.getUpperBounds().add(substitutor.substitute(upperBound, Variance.INVARIANT));
}
result.add(substituted);
}
return substitutor;
}
}
@@ -4,7 +4,6 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.resolve.JetScope;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import java.util.*;
@@ -79,13 +78,6 @@ public class ErrorUtils {
return "<ERROR FUNCTION>";
}
@NotNull
@Override
public OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
List<TypeParameterDescriptor> typeParameters = Collections.<TypeParameterDescriptor>emptyList();
return OverloadResolutionResult.success(createErrorFunction(typeParameters, positionedValueArgumentTypes));
}
@Override
public boolean isEmpty() {
return false;
@@ -21,10 +21,12 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstantResolver;
import org.jetbrains.jet.lang.resolve.constants.ErrorValue;
import org.jetbrains.jet.lang.resolve.constants.StringValue;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import org.jetbrains.jet.util.WritableSlice;
import java.util.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.resolve.BindingContext.STATEMENT;
/**
@@ -60,6 +62,11 @@ public class JetTypeInferrer {
public List<AnnotationDescriptor> getAnnotations() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public String toString() {
return "FORBIDDEN";
}
};
public static final JetType NO_EXPECTED_TYPE = new JetType() {
@NotNull
@@ -89,6 +96,11 @@ public class JetTypeInferrer {
public List<AnnotationDescriptor> getAnnotations() {
throw new UnsupportedOperationException(); // TODO
}
@Override
public String toString() {
return "NO_EXPECTED_TYPE";
}
};
private static final ImmutableMap<IElementType, String> unaryOperationNames = ImmutableMap.<IElementType, String>builder()
@@ -180,84 +192,6 @@ public class JetTypeInferrer {
return typeInferrerVisitorWithNamespaces.getType(expression, new TypeInferenceContext(trace, scope, preferBlock, DataFlowInfo.getEmpty(), NO_EXPECTED_TYPE, NO_EXPECTED_TYPE));
}
@NotNull
private OverloadResolutionResult resolveNoParametersFunction(@NotNull JetType receiverType, @NotNull JetScope scope, @NotNull String name) {
// OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name);
// No generics. Guaranteed
// return overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.<JetType>emptyList(), Collections.<JetType>emptyList());
return callResolver.resolveExactSignature(scope, receiverType, name, Collections.<JetType>emptyList());
}
// private OverloadDomain getOverloadDomain(
// @Nullable final JetType receiverType,
// @NotNull final JetScope scope,
// @NotNull JetExpression calleeExpression,
// @Nullable PsiElement argumentList
// ) {
// final OverloadDomain[] result = new OverloadDomain[1];
// final JetSimpleNameExpression[] reference = new JetSimpleNameExpression[1];
// calleeExpression.accept(new JetVisitorVoid() {
//
// @Override
// public void visitHashQualifiedExpression(JetHashQualifiedExpression expression) {
// // a#b -- create a domain for all overloads of b in a
// throw new UnsupportedOperationException(); // TODO
// }
//
// @Override
// public void visitPredicateExpression(JetPredicateExpression expression) {
// // overload lookup for checking, but the type is receiver's type + nullable
// throw new UnsupportedOperationException(); // TODO
// }
//
// @Override
// public void visitQualifiedExpression(JetQualifiedExpression expression) {
// trace.getErrorHandler().genericError(expression.getNode(), "Unsupported [JetTypeInferrer]");
//
// // . or ?.
// // JetType receiverType = getType(scope, expression.getReceiverExpression(), false);
// // checkNullSafety(receiverType, expression.getOperationTokenNode());
// //
// // JetExpression selectorExpression = expression.getSelectorExpression();
// // if (selectorExpression instanceof JetSimpleNameExpression) {
// // JetSimpleNameExpression referenceExpression = (JetSimpleNameExpression) selectorExpression;
// // String referencedName = referenceExpression.getReferencedName();
// //
// // if (receiverType != null && referencedName != null) {
// // // No generics. Guaranteed
// // result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referencedName);
// // reference[0] = referenceExpression;
// // }
// // } else {
// // throw new UnsupportedOperationException(); // TODO
// // }
// }
//
// @Override
// public void visitSimpleNameExpression(JetSimpleNameExpression expression) {
// // a -- create a hierarchical lookup domain for this.a
// String referencedName = expression.getReferencedName();
// if (referencedName != null) {
// // No generics. Guaranteed
// result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referencedName);
// reference[0] = expression;
// }
// }
//
// @Override
// public void visitExpression(JetExpression expression) {
// // <e> create a dummy domain for the type of e
// throw new UnsupportedOperationException(expression.getText()); // TODO
// }
//
// @Override
// public void visitJetElement(JetElement element) {
// trace.getErrorHandler().genericError(element.getNode(), "Unsupported in call element"); // TODO : Message
// }
// });
// return wrapForTracing(result[0], reference[0], argumentList, true);
// }
public CallResolver getCallResolver() {
return callResolver;
}
@@ -284,68 +218,6 @@ public class JetTypeInferrer {
}
}
// private OverloadDomain wrapForTracing(
// @NotNull final OverloadDomain overloadDomain,
// @NotNull final JetReferenceExpression referenceExpression,
// @Nullable final PsiElement argumentList,
// final boolean reportErrors) {
// return new OverloadDomain() {
// @NotNull
// @Override
// public OverloadResolutionResult getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) {
// OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArgumentTypes, functionLiteralArgumentType);
// report(resolutionResult);
// return resolutionResult;
// }
//
// @NotNull
// @Override
// public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
// OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes);
// report(resolutionResult);
// return resolutionResult;
// }
//
// private void report(OverloadResolutionResult resolutionResult) {
// if (resolutionResult.isSuccess() || resolutionResult.singleFunction()) {
// trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, resolutionResult.getFunctionDescriptor());
// }
// if (reportErrors) {
// switch (resolutionResult.getResultCode()) {
// case NAME_NOT_FOUND:
// trace.getErrorHandler().unresolvedReference(referenceExpression);
// break;
// case SINGLE_FUNCTION_ARGUMENT_MISMATCH:
// if (argumentList != null) {
// // TODO : More helpful message. NOTE: there's a separate handling for this for constructors
// trace.getErrorHandler().genericError(argumentList.getNode(), "Arguments do not match " + DescriptorRenderer.TEXT.render(resolutionResult.getFunctionDescriptor()));
// }
// else {
// trace.getErrorHandler().unresolvedReference(referenceExpression);
// }
// break;
// case AMBIGUITY:
// if (argumentList != null) {
// // TODO : More helpful message. NOTE: there's a separate handling for this for constructors
// trace.getErrorHandler().genericError(argumentList.getNode(), "Overload ambiguity [TODO : more helpful message]");
// }
// else {
// trace.getErrorHandler().unresolvedReference(referenceExpression);
// }
// break;
// default:
// // Not a success
// }
// }
// }
//
// @Override
// public boolean isEmpty() {
// return overloadDomain.isEmpty();
// }
// };
// }
public void checkFunctionReturnType(@NotNull JetScope outerScope, @NotNull JetDeclarationWithBody function, @NotNull FunctionDescriptor functionDescriptor) {
checkFunctionReturnType(outerScope, function, functionDescriptor, DataFlowInfo.getEmpty());
}
@@ -520,195 +392,6 @@ public class JetTypeInferrer {
return result;
}
// @Nullable
// private JetType resolveCall1(
// @NotNull JetScope scope,
// @NotNull OverloadDomain overloadDomain,
// @NotNull JetCallElement call) {
// // 1) ends with a name -> (scope, name) to look up
// // 2) ends with something else -> just check types
//
// final List<JetTypeProjection> jetTypeArguments = call.getTypeArguments();
//
// for (JetTypeProjection typeArgument : jetTypeArguments) {
// if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) {
// trace.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning
// }
// }
//
// List<JetType> typeArguments = new ArrayList<JetType>();
// for (JetTypeProjection projection : jetTypeArguments) {
// // TODO : check that there's no projection
// JetTypeReference typeReference = projection.getTypeReference();
// if (typeReference != null) {
// typeArguments.add(new TypeResolver(semanticServices, trace, true).resolveType(scope, typeReference));
// }
// }
//
// return resolveCallWithTypeArguments(scope, overloadDomain, call, typeArguments);
// }
// private JetType resolveCallWithTypeArguments(JetScope scope, OverloadDomain overloadDomain, JetCallElement call, List<JetType> typeArguments) {
// final List<JetValueArgument> valueArguments = call.getValueArguments();
//
// boolean someNamed = false;
// for (JetValueArgument argument : valueArguments) {
// if (argument.isNamed()) {
// someNamed = true;
// break;
// }
// }
//
// final List<JetExpression> functionLiteralArguments = call.getFunctionLiteralArguments();
//
// // TODO : must be a check
// assert functionLiteralArguments.size() <= 1;
//
// if (someNamed) {
// // TODO : check that all are named
// trace.getErrorHandler().genericError(call.getNode(), "Named arguments are not supported"); // TODO
//
// } else {
// List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
// for (JetValueArgument argument : valueArguments) {
// JetExpression argumentExpression = argument.getArgumentExpression();
// if (argumentExpression != null) {
// positionedValueArguments.add(argumentExpression);
// }
// }
//
// positionedValueArguments.addAll(functionLiteralArguments);
//
// List<JetType> valueArgumentTypes = new ArrayList<JetType>();
// for (JetExpression valueArgument : positionedValueArguments) {
// valueArgumentTypes.add(safeGetType(scope, valueArgument, false, NO_EXPECTED_TYPE)); // TODO
// }
//
// OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(typeArguments, valueArgumentTypes);
// if (resolutionResult.isSuccess()) {
// final FunctionDescriptor functionDescriptor = resolutionResult.getFunctionDescriptor();
//
// callResolver.checkGenericBoundsInAFunctionCall(call.getTypeArguments(), typeArguments, functionDescriptor);
// return functionDescriptor.getReturnType();
// }
// }
// return null;
// }
// @Nullable
// public JetType checkTypeInitializerCall(JetScope scope, @NotNull JetTypeReference typeReference, @NotNull JetCallElement call) {
// JetTypeElement typeElement = typeReference.getTypeElement();
// if (typeElement instanceof JetUserType) {
// JetUserType userType = (JetUserType) typeElement;
// // TODO : to infer constructor parameters, one will need to
// // 1) resolve a _class_ from the typeReference
// // 2) rely on the overload domain of constructors of this class to infer type arguments
// // For now we assume that the type arguments are provided, and thus the typeReference can be
// // resolved into a valid type
// JetType receiverType = typeResolver.resolveType(scope, typeReference);
// DeclarationDescriptor declarationDescriptor = receiverType.getConstructor().getDeclarationDescriptor();
// if (declarationDescriptor instanceof ClassDescriptor) {
// ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
//
// for (JetTypeProjection typeProjection : userType.getTypeArguments()) {
// switch (typeProjection.getProjectionKind()) {
// case IN:
// case OUT:
// case STAR:
// // TODO : Bug in the editor
// trace.getErrorHandler().genericError(typeProjection.getProjectionNode(), "Projections are not allowed in constructor type arguments");
// break;
// case NONE:
// break;
// }
// }
//
// JetSimpleNameExpression referenceExpression = userType.getReferenceExpression();
// if (referenceExpression != null) {
// return checkClassConstructorCall(scope, referenceExpression, classDescriptor, receiverType, call);
// }
// }
// else {
// trace.getErrorHandler().genericError(((JetElement) call).getNode(), "Calling a constructor is only supported for ordinary classes"); // TODO : review the message
// }
// return null;
// }
// else {
// if (typeElement != null) {
// trace.getErrorHandler().genericError(typeElement.getNode(), "Calling a constructor is only supported for ordinary classes"); // TODO : Better message
// }
// }
// return null;
// }
// @Nullable
// public JetType checkClassConstructorCall(
// @NotNull JetScope scope,
// @NotNull JetReferenceExpression referenceExpression,
// @NotNull ClassDescriptor classDescriptor,
// @NotNull JetType receiverType,
// @NotNull JetCallElement call) {
// // When one writes 'new Array<in T>(...)' this does not make much sense, and an instance
// // of 'Array<T>' must be created anyway.
// // Thus, we should either prohibit projections in type arguments in such contexts,
// // or treat them as an automatic upcast to the desired type, i.e. for the user not
// // to be forced to write
// // val a : Array<in T> = new Array<T>(...)
// // NOTE: Array may be a bad example here, some classes may have substantial functionality
// // not involving their type parameters
// //
// // The code below upcasts the type automatically
//
//
// FunctionGroup constructors = classDescriptor.getConstructors();
//// OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(null, constructors);
//
// JetType constructorReturnedType;
// if (call instanceof JetDelegatorToThisCall) {
// List<TypeProjection> typeArguments = receiverType.getArguments();
//
// List<JetType> projectionsStripped = Lists.newArrayList();
// for (TypeProjection typeArgument : typeArguments) {
// projectionsStripped.add(typeArgument.getType());
// }
//
// constructorReturnedType = resolveCallWithTypeArguments(
// scope,
// wrapForTracing(constructorsOverloadDomain, referenceExpression, call.getValueArgumentList(), false),
// call, projectionsStripped);
// }
// else {
// constructorReturnedType = callResolver.resolveCall(
// scope, call, NO_EXPECTED_TYPE);
//// wrapForTracing(constructorsOverloadDomain, referenceExpression, call.getValueArgumentList(), false),
//// call);
// }
// if (constructorReturnedType == null && !ErrorUtils.isErrorType(receiverType)) {
// DeclarationDescriptor declarationDescriptor = receiverType.getConstructor().getDeclarationDescriptor();
// assert declarationDescriptor != null;
// trace.record(BindingContext.REFERENCE_TARGET, referenceExpression, declarationDescriptor);
// // TODO : more helpful message
// JetValueArgumentList argumentList = call.getValueArgumentList();
// final String errorMessage = "Cannot find a constructor overload for class " + classDescriptor.getName() + " with these arguments";
// if (argumentList != null) {
// trace.getErrorHandler().genericError(argumentList.getNode(), errorMessage);
// }
// else {
// trace.getErrorHandler().genericError(call.getNode(), errorMessage);
// }
// constructorReturnedType = receiverType;
// }
// // If no upcast needed:
// return constructorReturnedType;
//
// // Automatic upcast:
// // result = receiverType;
// }
//TODO
private JetType enrichOutType(JetExpression expression, JetType initialType, @NotNull TypeInferenceContext context) {
if (expression == null) return initialType;
@@ -736,32 +419,31 @@ public class JetTypeInferrer {
return expressionType;
}
VariableDescriptor variableDescriptor = getVariableDescriptorFromSimpleName(expression, context);
if (variableDescriptor == null) return expressionType;
JetType enrichedType = null;
List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor));
Collections.reverse(possibleTypes);
for (JetType possibleType: possibleTypes) {
if (semanticServices.getTypeChecker().isSubtypeOf(possibleType, context.expectedType)) {
enrichedType = possibleType;
break;
boolean appropriateTypeFound = false;
if (variableDescriptor != null) {
List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(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 (enrichedType == null) {
enrichedType = context.dataFlowInfo.getOutType(variableDescriptor);
}
if (enrichedType == null) {
enrichedType = expressionType;
}
if (!semanticServices.getTypeChecker().isSubtypeOf(enrichedType, context.expectedType)) {
if (!appropriateTypeFound) {
context.trace.getErrorHandler().typeMismatch(expression, context.expectedType, expressionType);
} else {
checkAutoCast(expression, context.expectedType, variableDescriptor, context.trace);
return expressionType;
}
return enrichedType;
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");
@@ -793,7 +475,7 @@ public class JetTypeInferrer {
VariableDescriptor variableDescriptor = null;
if (receiverExpression instanceof JetSimpleNameExpression) {
JetSimpleNameExpression nameExpression = (JetSimpleNameExpression) receiverExpression;
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, nameExpression);
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, nameExpression);
if (declarationDescriptor instanceof VariableDescriptor) {
variableDescriptor = (VariableDescriptor) declarationDescriptor;
}
@@ -956,7 +638,7 @@ public class JetTypeInferrer {
context.trace.getErrorHandler().unresolvedReference(expression);
}
else {
context.trace.record(BindingContext.REFERENCE_TARGET, expression, property);
context.trace.record(REFERENCE_TARGET, expression, property);
return context.services.checkEnrichedType(property.getOutType(), expression, context);
}
}
@@ -965,7 +647,7 @@ public class JetTypeInferrer {
if (referencedName != null) {
VariableDescriptor variable = context.scope.getVariable(referencedName);
if (variable != null) {
context.trace.record(BindingContext.REFERENCE_TARGET, expression, variable);
context.trace.record(REFERENCE_TARGET, expression, variable);
JetType result = variable.getOutType();
if (result == null) {
context.trace.getErrorHandler().genericError(expression.getNode(), "This variable is not readable in this context");
@@ -983,7 +665,7 @@ public class JetTypeInferrer {
else {
context.trace.getErrorHandler().genericError(expression.getNode(), "Classifier " + classifier.getName() + " does not have a class object");
}
context.trace.record(BindingContext.REFERENCE_TARGET, expression, classifier);
context.trace.record(REFERENCE_TARGET, expression, classifier);
return context.services.checkEnrichedType(result, expression, context);
}
else {
@@ -1019,7 +701,7 @@ public class JetTypeInferrer {
if (namespace == null) {
return null;
}
context.trace.record(BindingContext.REFERENCE_TARGET, expression, namespace);
context.trace.record(REFERENCE_TARGET, expression, namespace);
return namespace.getNamespaceType();
}
@@ -1077,6 +759,14 @@ public class JetTypeInferrer {
List<JetType> parameterTypes = new ArrayList<JetType>();
List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
List<JetParameter> parameters = functionLiteral.getValueParameters();
JetType expectedType = context.expectedType;
List<ValueParameterDescriptor> valueParameters = null;
boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(expectedType);
if (functionTypeExpected) {
valueParameters = JetStandardClasses.getValueParameters(functionDescriptor, expectedType);
}
for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) {
JetParameter parameter = parameters.get(i);
JetTypeReference typeReference = parameter.getTypeReference();
@@ -1086,15 +776,31 @@ public class JetTypeInferrer {
type = context.typeResolver.resolveType(context.scope, typeReference);
}
else {
context.trace.getErrorHandler().genericError(parameter.getNode(), "Type inference for parameters is not implemented yet");
type = ErrorUtils.createErrorType("Not inferred");
if (valueParameters != null) {
type = valueParameters.get(i).getOutType();
}
else {
context.trace.getErrorHandler().genericError(parameter.getNode(), "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation");
type = ErrorUtils.createErrorType("Cannot be inferred");
}
}
ValueParameterDescriptor valueParameterDescriptor = context.classDescriptorResolver.resolveValueParameterDescriptor(functionDescriptor, parameter, i, type);
parameterTypes.add(valueParameterDescriptor.getOutType());
valueParameterDescriptors.add(valueParameterDescriptor);
}
JetType effectiveReceiverType = receiverTypeRef == null ? null : receiverType;
JetType effectiveReceiverType;
if (receiverTypeRef == null) {
if (functionTypeExpected) {
effectiveReceiverType = JetStandardClasses.getReceiverType(expectedType);
}
else {
effectiveReceiverType = null;
}
}
else {
effectiveReceiverType = receiverType;
}
functionDescriptor.initialize(effectiveReceiverType, Collections.<TypeParameterDescriptor>emptyList(), valueParameterDescriptors, null);
context.trace.record(BindingContext.FUNCTION, expression, functionDescriptor);
@@ -1106,15 +812,17 @@ public class JetTypeInferrer {
context.services.checkFunctionReturnType(functionInnerScope, expression, returnType, context.dataFlowInfo);
}
else {
if (context.expectedType != NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(context.expectedType)) {
returnType = JetStandardClasses.getReturnType(context.expectedType);
if (functionTypeExpected) {
returnType = JetStandardClasses.getReturnType(expectedType);
}
returnType = getBlockReturnedType(functionInnerScope, functionLiteral.getBodyExpression(), context.replaceExpectedType(returnType));
}
JetType safeReturnType = returnType == null ? ErrorUtils.createErrorType("<return type>") : returnType;
functionDescriptor.setReturnType(safeReturnType);
if (functionTypeExpected) {
}
return context.services.checkType(JetStandardClasses.getFunctionType(Collections.<AnnotationDescriptor>emptyList(), effectiveReceiverType, parameterTypes, safeReturnType), expression, context);
}
@@ -1293,8 +1001,8 @@ public class JetTypeInferrer {
else {
throw new UnsupportedOperationException(); // TODO
}
context.trace.record(BindingContext.REFERENCE_TARGET, targetLabel, declarationDescriptor);
context.trace.record(BindingContext.REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
}
else if (size == 0) {
// This uses the info written by the control flow processor
@@ -1307,8 +1015,8 @@ public class JetTypeInferrer {
thisType = JetStandardClasses.getNothingType();
}
else {
context.trace.record(BindingContext.REFERENCE_TARGET, targetLabel, declarationDescriptor);
context.trace.record(BindingContext.REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
context.trace.record(REFERENCE_TARGET, targetLabel, declarationDescriptor);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptor);
}
}
else {
@@ -1328,7 +1036,7 @@ public class JetTypeInferrer {
DeclarationDescriptor declarationDescriptorForUnqualifiedThis = context.scope.getDeclarationDescriptorForUnqualifiedThis();
if (declarationDescriptorForUnqualifiedThis != null) {
context.trace.record(BindingContext.REFERENCE_TARGET, expression.getThisReference(), declarationDescriptorForUnqualifiedThis);
context.trace.record(REFERENCE_TARGET, expression.getThisReference(), declarationDescriptorForUnqualifiedThis);
}
}
@@ -1445,9 +1153,10 @@ public class JetTypeInferrer {
@Override
public void visitWhenConditionCall(JetWhenConditionCall condition) {
JetExpression callSuffixExpression = condition.getCallSuffixExpression();
JetScope compositeScope = new ScopeWithReceiver(context.scope, subjectType, semanticServices.getTypeChecker());
// JetScope compositeScope = new ScopeWithReceiver(context.scope, subjectType, semanticServices.getTypeChecker());
if (callSuffixExpression != null) {
JetType selectorReturnType = getType(compositeScope, callSuffixExpression, false, context);
// JetType selectorReturnType = getType(compositeScope, callSuffixExpression, false, context);
JetType selectorReturnType = getSelectorReturnType(subjectType, callSuffixExpression, context);//getType(compositeScope, callSuffixExpression, false, context);
ensureBooleanResultWithCustomSubject(callSuffixExpression, selectorReturnType, "This expression", context);
context.services.checkNullSafety(subjectType, condition.getOperationTokenNode(), getCalleeFunctionDescriptor(callSuffixExpression, context));
}
@@ -1923,7 +1632,7 @@ public class JetTypeInferrer {
@Nullable
private JetType checkIterableConvention(@NotNull JetType type, @NotNull ASTNode reportErrorsOn, TypeInferenceContext context) {
OverloadResolutionResult iteratorResolutionResult = context.services.resolveNoParametersFunction(type, context.scope, "iterator");
OverloadResolutionResult iteratorResolutionResult = context.services.callResolver.resolveExactSignature(context.scope, type, "iterator", Collections.<JetType>emptyList());
if (iteratorResolutionResult.isSuccess()) {
JetType iteratorType = iteratorResolutionResult.getFunctionDescriptor().getReturnType();
boolean hasNextFunctionSupported = checkHasNextFunctionSupport(reportErrorsOn, iteratorType, context);
@@ -1936,7 +1645,7 @@ public class JetTypeInferrer {
context.trace.getErrorHandler().genericError(reportErrorsOn, "Loop range must have an 'iterator().hasNext()' function or an 'iterator().hasNext' property");
}
OverloadResolutionResult nextResolutionResult = context.services.resolveNoParametersFunction(iteratorType, context.scope, "next");
OverloadResolutionResult nextResolutionResult = context.services.callResolver.resolveExactSignature(context.scope, iteratorType, "next", Collections.<JetType>emptyList());
if (nextResolutionResult.isAmbiguity()) {
context.trace.getErrorHandler().genericError(reportErrorsOn, "Method 'iterator().next()' is ambiguous for this expression");
} else if (nextResolutionResult.isNothing()) {
@@ -1956,7 +1665,7 @@ public class JetTypeInferrer {
}
private boolean checkHasNextFunctionSupport(@NotNull ASTNode reportErrorsOn, @NotNull JetType iteratorType, TypeInferenceContext context) {
OverloadResolutionResult hasNextResolutionResult = context.services.resolveNoParametersFunction(iteratorType, context.scope, "hasNext");
OverloadResolutionResult hasNextResolutionResult = context.services.callResolver.resolveExactSignature(context.scope, iteratorType, "hasNext", Collections.<JetType>emptyList());
if (hasNextResolutionResult.isAmbiguity()) {
context.trace.getErrorHandler().genericError(reportErrorsOn, "Method 'iterator().hasNext()' is ambiguous for this expression");
} else if (hasNextResolutionResult.isNothing()) {
@@ -1988,89 +1697,6 @@ public class JetTypeInferrer {
return true;
}
// @Override
// public void visitNewExpression(JetNewExpression expression) {
// // TODO : type argument inference
// JetTypeReference typeReference = expression.getTypeReference();
// if (typeReference != null) {
// result = checkTypeInitializerCall(scope, typeReference, expression);
// }
// }
// private void resolveCallWithExplicitName(@NotNull JetScope scope, JetExpression receiver, String functionName, List<JetType> resolvedTypeArguments, List<ValueArgumentPsi> valueArguments) {
//
// boolean someNamed = false;
// boolean allNamed = true;
// for (ValueArgumentPsi valueArgument : valueArguments) {
// if (valueArgument.isNamed()) {
// context.trace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Named arguments are not supported");
// someNamed = true;
// }
// else {
// allNamed = false;
// }
// }
// if (someNamed) {
// return; // TODO
// }
// if (someNamed && !allNamed) {
// // TODO function literals outside parentheses
// }
//
// ErrorHandlerWithRegions errorHandler = context.trace.getErrorHandler();
//
// // 1. resolve 'receiver' in 'scope' with expected type 'NO_EXPECTED_TYPE'
// errorHandler.openRegion();
// JetType receiverType = JetTypeInferrer.this.getType(scope, receiver, false, NO_EXPECTED_TYPE);
// // for each applicable function in 'receiverType'
// Set<FunctionDescriptor> allFunctions = receiverType.getMemberScope().getFunctionGroup(functionName).getFunctionDescriptors();
// Map<FunctionDescriptor, List<JetType>> applicableFunctions = Maps.newHashMap();
// int typeArgCount = resolvedTypeArguments.size();
// int valueArgCount = valueArguments.size();
// for (FunctionDescriptor functionDescriptor : allFunctions) {
// if (typeArgCount == 0 || functionDescriptor.getTypeParameters().size() == typeArgCount) {
// if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount &&
// valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) {
// // get expected types for value parameters
// if (typeArgCount > 0) {
// FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(resolvedTypeArguments, functionDescriptor);
// }
// else {
// FunctionDescriptor substitutedFunctionDescriptor = FunctionDescriptorUtil.substituteFunctionDescriptor(TypeUtils.getDefaultTypes(functionDescriptor.getTypeParameters()), functionDescriptor);
// List<JetType> valueArgumentTypes = getArgumentTypes(substitutedFunctionDescriptor, valueArguments);
// if (valueArgumentTypes == null) {
// Map<TypeConstructor, TypeProjection> noExpectedTypes = Maps.newHashMap();
// for (TypeParameterDescriptor typeParameterDescriptor : functionDescriptor.getTypeParameters()) {
// noExpectedTypes.put(typeParameterDescriptor.getTypeConstructor(), new TypeProjection(NO_EXPECTED_TYPE));
// }
// substitutedFunctionDescriptor = functionDescriptor.substitute(TypeSubstitutor.create(noExpectedTypes));
// valueArgumentTypes = getArgumentTypes(substitutedFunctionDescriptor, valueArguments);
// }
// if (valueArgumentTypes != null) {
// List<JetType> typeArguments = solveConstraintSystem(functionDescriptor, valueArgumentTypes, expectedReturnType);
// if (typeArguments != null) {
// applicableFunctions.put(functionDescriptor, typeArguments);
// }
// }
// }
// // type-check the parameters
// // if something was found (one or many options
// errorHandler.closeAndCommitCurrentRegion();
// // otherwise
// errorHandler.closeAndReturnCurrentRegion();
//
// }
// }
// }
// // get expected types for value parameters
// // type-check the parameters
// // if something was found (one or many options
// errorHandler.closeAndCommitCurrentRegion();
// // otherwise
// errorHandler.closeAndReturnCurrentRegion();
//
// }
@Override
public JetType visitHashQualifiedExpression(JetHashQualifiedExpression expression, TypeInferenceContext context) {
context.trace.getErrorHandler().genericError(expression.getOperationTokenNode(), "Unsupported");
@@ -2087,10 +1713,8 @@ public class JetTypeInferrer {
if (receiverType == null) return null;
// Clean resolution: no autocasts
TemporaryBindingTrace cleanResolutionTrace = new TemporaryBindingTrace(context.trace.getBindingContext());
TemporaryBindingTrace cleanResolutionTrace = TemporaryBindingTrace.create(context.trace);
TypeInferenceContext cleanResolutionContext = context.replaceBindingTrace(cleanResolutionTrace);
// ErrorHandler errorHandler = context.trace.getErrorHandler();
// errorHandler.openRegion();
JetType selectorReturnType = getSelectorReturnType(receiverType, selectorExpression, cleanResolutionContext);
//TODO move further
@@ -2109,24 +1733,24 @@ public class JetTypeInferrer {
List<JetType> possibleTypes = Lists.newArrayList(context.dataFlowInfo.getPossibleTypes(variableDescriptor));
Collections.reverse(possibleTypes);
TemporaryBindingTrace autocastResolutionTrace = new TemporaryBindingTrace(context.trace.getBindingContext());
TemporaryBindingTrace autocastResolutionTrace = TemporaryBindingTrace.create(context.trace);
TypeInferenceContext autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace);
for (JetType possibleType : possibleTypes) {
selectorReturnType = getSelectorReturnType(possibleType, selectorExpression, autocastResolutionContext);
if (selectorReturnType != null) {
context.services.checkAutoCast(receiverExpression, possibleType, variableDescriptor, autocastResolutionTrace);
autocastResolutionTrace.addAllMyDataTo(context.trace);
autocastResolutionTrace.commit();
somethingFound = true;
break;
}
else {
autocastResolutionTrace = new TemporaryBindingTrace(context.trace.getBindingContext());
autocastResolutionTrace = TemporaryBindingTrace.create(context.trace);
autocastResolutionContext = context.replaceBindingTrace(autocastResolutionTrace);
}
}
}
if (!somethingFound) {
cleanResolutionTrace.addAllMyDataTo(context.trace);
cleanResolutionTrace.commit();
}
}
@@ -2170,7 +1794,7 @@ public class JetTypeInferrer {
@Override
public void visitReferenceExpression(JetReferenceExpression referenceExpression) {
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(BindingContext.REFERENCE_TARGET, referenceExpression);
DeclarationDescriptor declarationDescriptor = context.trace.getBindingContext().get(REFERENCE_TARGET, referenceExpression);
if (declarationDescriptor instanceof FunctionDescriptor) {
result[0] = (FunctionDescriptor) declarationDescriptor;
}
@@ -2202,24 +1826,15 @@ public class JetTypeInferrer {
return result[0];
}
private JetType getCallExpressionType(@Nullable JetType receiverType, @NotNull JetCallExpression callExpression, TypeInferenceContext context) {
// JetExpression calleeExpression = callExpression.getCalleeExpression();
// if (calleeExpression == null) {
// return null;
// }
// OverloadDomain overloadDomain = context.services.getOverloadDomain(receiverType, context.scope, calleeExpression, callExpression.getValueArgumentList());
JetScope scope = receiverType == null ? context.scope : new ScopeWithReceiver(context.scope, receiverType, JetTypeChecker.INSTANCE);
return context.services.callResolver.resolveCall(scope, callExpression, context.expectedType);
// return context.services.resolveCall(context.scope, overloadDomain, callExpression);
}
private JetType getSelectorReturnType(JetType receiverType, JetExpression selectorExpression, TypeInferenceContext context) {
@Nullable
private JetType getSelectorReturnType(@Nullable JetType receiverType, @NotNull JetExpression selectorExpression, @NotNull TypeInferenceContext context) {
if (selectorExpression instanceof JetCallExpression) {
return getCallExpressionType(receiverType, (JetCallExpression) selectorExpression, context);
return context.services.callResolver.resolveCall(context.scope, receiverType, (JetCallExpression) selectorExpression, context.expectedType);
}
else if (selectorExpression instanceof JetSimpleNameExpression) {
JetScope compositeScope = new ScopeWithReceiver(context.scope, receiverType, semanticServices.getTypeChecker());
return getType(compositeScope, selectorExpression, false, context);
// JetScope compositeScope = new ScopeWithReceiver(context.scope, receiverType, semanticServices.getTypeChecker());
JetScope scope = receiverType != null ? receiverType.getMemberScope() : context.scope;
return getType(scope, selectorExpression, false, context);
}
else if (selectorExpression != null) {
// TODO : not a simple name -> resolve in scope, expect property type or a function type
@@ -2230,8 +1845,8 @@ public class JetTypeInferrer {
@Override
public JetType visitCallExpression(JetCallExpression expression, TypeInferenceContext context) {
// return context.services.checkType(context.services.resolveCall(context.scope, expression, context.expectedType), expression, context);
return context.services.checkType(getCallExpressionType(null, expression, context), expression, context);
JetType expressionType = context.services.callResolver.resolveCall(context.scope, null, expression, context.expectedType);
return context.services.checkType(expressionType, expression, context);
}
@Override
@@ -2271,7 +1886,7 @@ public class JetTypeInferrer {
CallMaker.makeCall(expression),
expression.getOperationSign(),
name,
baseExpression,
receiverType,
context.expectedType);
if (functionDescriptor == null) return null;
@@ -2346,21 +1961,24 @@ public class JetTypeInferrer {
OverloadResolutionResult resolutionResult = context.services.callResolver.resolveExactSignature(
context.scope, leftType, "equals",
Collections.singletonList(JetStandardClasses.getNullableAnyType()));
FunctionDescriptor equals;
if (resolutionResult.isSuccess()) {
equals = resolutionResult.getFunctionDescriptor();
}
else {
// TODO : Report ambiguous equals
equals = null;
}
if (equals != null) {
FunctionDescriptor equals = resolutionResult.getFunctionDescriptor();
context.trace.record(REFERENCE_TARGET, operationSign, equals);
if (ensureBooleanResult(operationSign, name, equals.getReturnType(), context)) {
ensureNonemptyIntersectionOfOperandTypes(expression, context);
}
}
else {
context.trace.getErrorHandler().genericError(operationSign.getNode(), "No method 'equals(Any?) : Boolean' available");
if (resolutionResult.isAmbiguity()) {
StringBuilder stringBuilder = new StringBuilder();
for (FunctionDescriptor functionDescriptor : resolutionResult.getFunctionDescriptors()) {
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" ");
}
context.trace.getErrorHandler().genericError(operationSign.getNode(), "Ambiguous function: " + stringBuilder);
}
else {
context.trace.getErrorHandler().genericError(operationSign.getNode(), "No method 'equals(Any?) : Boolean' available");
}
}
}
}
@@ -2416,11 +2034,12 @@ public class JetTypeInferrer {
private void checkInExpression(JetSimpleNameExpression operationSign, JetExpression left, JetExpression right, TypeInferenceContext context) {
String name = "contains";
JetType receiverType = context.services.safeGetType(context.scope, right, false, NO_EXPECTED_TYPE);
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
context.scope,
CallMaker.makeCall(operationSign, Collections.singletonList(left)),
operationSign,
name, right, context.expectedType);
name, receiverType, context.expectedType);
JetType containsType = functionDescriptor != null ? functionDescriptor.getReturnType() : null;
ensureBooleanResult(operationSign, name, containsType, context);
}
@@ -2496,9 +2115,6 @@ public class JetTypeInferrer {
TypeInferenceContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
JetExpression arrayExpression = expression.getArrayExpression();
JetType receiverType = getType(context.scope, arrayExpression, false, context);
// List<JetValueArgument> indexArguments = expression.getIndexArguments();
// List<JetType> argumentTypes = getTypes(context.scope, indexArguments, context);
// if (argumentTypes == null) return null;
if (receiverType != null) {
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
@@ -2506,10 +2122,9 @@ public class JetTypeInferrer {
CallMaker.makeCall(expression, expression.getIndexExpressions()),
expression,
"get",
arrayExpression,
receiverType,
context.expectedType);
if (functionDescriptor != null) {
// checkNullSafety(receiverType, expression.getIndexArguments().get(0).getNode(), functionDescriptor);
return context.services.checkType(functionDescriptor.getReturnType(), expression, contextWithExpectedType);
}
}
@@ -2518,17 +2133,13 @@ public class JetTypeInferrer {
@Nullable
protected JetType getTypeForBinaryCall(JetScope scope, String name, TypeInferenceContext context, JetBinaryExpression binaryExpression) {
// JetType leftType = getType(scope, left, false, context);
// JetType rightType = getType(scope, right, false, context);
// if (leftType == null || rightType == null) {
// return null;
// }
JetType leftType = getType(scope, binaryExpression.getLeft(), false, context);
FunctionDescriptor functionDescriptor = context.services.callResolver.resolveCallWithGivenName(
scope,
CallMaker.makeCall(binaryExpression),
binaryExpression.getOperationReference(),
name,
binaryExpression.getLeft(),
leftType,
context.expectedType);
if (functionDescriptor != null) {
// if (leftType.isNullable()) {
@@ -2636,12 +2247,6 @@ public class JetTypeInferrer {
public TypeInferrerVisitorWithWritableScope(@NotNull WritableScope scope) {
this.scope = scope;
}
// public TypeInferrerVisitorWithWritableScope(@NotNull BindingTrace trace, @NotNull JetScope scope) {
// super(trace);
// this.scope = newWritableScopeImpl(scope, trace).setDebugName("Block scope");
// }
@Override
public JetType visitObjectDeclaration(JetObjectDeclaration declaration, TypeInferenceContext context) {
@@ -2715,7 +2320,9 @@ public class JetTypeInferrer {
protected JetType visitAssignmentOperation(JetBinaryExpression expression, TypeInferenceContext context) {
IElementType operationType = expression.getOperationReference().getReferencedNameElementType();
String name = assignmentOperationNames.get(operationType);
JetType assignmentOperationType = getTypeForBinaryCall(scope, name, context, expression);
TemporaryBindingTrace temporaryBindingTrace = TemporaryBindingTrace.create(context.trace);
JetType assignmentOperationType = getTypeForBinaryCall(scope, name, context.replaceBindingTrace(temporaryBindingTrace), expression);
if (assignmentOperationType == null) {
String counterpartName = binaryOperationNames.get(assignmentOperationCounterparts.get(operationType));
@@ -2725,6 +2332,9 @@ public class JetTypeInferrer {
context.trace.record(BindingContext.VARIABLE_REASSIGNMENT, expression);
}
}
else {
temporaryBindingTrace.commit();
}
return null;
}
@@ -2750,15 +2360,8 @@ public class JetTypeInferrer {
}
private JetType resolveArrayAccessToLValue(JetArrayAccessExpression arrayAccessExpression, JetExpression rightHandSide, JetSimpleNameExpression operationSign, TypeInferenceContext context) {
// TypeInferenceContext context = contextWithExpectedType.replaceExpectedType(NO_EXPECTED_TYPE);
// List<JetType> argumentTypes = getTypes(scope, arrayAccessExpression.getIndexExpressions(), context);
// if (argumentTypes == null) return null;
// JetType rhsType = getType(scope, rightHandSide, false, context);
// if (rhsType == null) return null;
// argumentTypes.add(rhsType);
//
// JetType receiverType = getType(scope, arrayAccessExpression.getArrayExpression(), false, context);
// if (receiverType == null) return null;
JetType receiverType = getType(scope, arrayAccessExpression.getArrayExpression(), false, context);
if (receiverType == null) return null;
//
Call call = CallMaker.makeCall(arrayAccessExpression, rightHandSide);
// // TODO : nasty hack: effort is duplicated
@@ -2771,7 +2374,7 @@ public class JetTypeInferrer {
scope,
call,
operationSign,
"set", arrayAccessExpression.getArrayExpression(), NO_EXPECTED_TYPE);
"set", receiverType, NO_EXPECTED_TYPE);
if (functionDescriptor == null) return null;
return context.services.checkType(functionDescriptor.getReturnType(), arrayAccessExpression, context);
}
@@ -6,7 +6,6 @@ import org.jetbrains.jet.lang.descriptors.TypeParameterDescriptor;
import org.jetbrains.jet.lang.resolve.SubstitutingScope;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -16,6 +15,18 @@ import java.util.Map;
public class TypeSubstitutor {
public interface TypeSubstitution {
TypeSubstitution EMPTY = new TypeSubstitution() {
@Override
public TypeProjection get(TypeConstructor key) {
return null;
}
@Override
public boolean isEmpty() {
return true;
}
};
@Nullable
TypeProjection get(TypeConstructor key);
boolean isEmpty();
@@ -39,7 +50,7 @@ public class TypeSubstitutor {
}
}
public static final TypeSubstitutor EMPTY = create(Collections.<TypeConstructor, TypeProjection>emptyMap());
public static final TypeSubstitutor EMPTY = create(TypeSubstitution.EMPTY);
public static final class SubstitutionException extends Exception {
public SubstitutionException(String message) {
@@ -61,14 +72,23 @@ public class TypeSubstitutor {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private final @NotNull TypeSubstitution substitutionContext;
private final @NotNull TypeSubstitution substitution;
private TypeSubstitutor(@NotNull TypeSubstitution substitutionContext) {
this.substitutionContext = substitutionContext;
protected TypeSubstitutor(@NotNull TypeSubstitution substitution) {
this.substitution = substitution;
}
public boolean inRange(@NotNull TypeConstructor typeConstructor) {
return substitution.get(typeConstructor) != null;
}
public boolean isEmpty() {
return substitutionContext.isEmpty();
return substitution.isEmpty();
}
@NotNull
public TypeSubstitution getSubstitution() {
return substitution;
}
@NotNull
@@ -100,7 +120,7 @@ public class TypeSubstitutor {
@NotNull
private JetType unsafeSubstitute(@NotNull JetType type, @NotNull Variance howThisTypeIsUsed) throws SubstitutionException {
TypeConstructor constructor = type.getConstructor();
TypeProjection value = substitutionContext.get(constructor);
TypeProjection value = substitution.get(constructor);
if (value != null) {
assert constructor.getDeclarationDescriptor() instanceof TypeParameterDescriptor;
@@ -122,7 +142,7 @@ public class TypeSubstitutor {
TypeProjection argument = arguments.get(i);
TypeParameterDescriptor parameterDescriptor = subjectType.getConstructor().getParameters().get(i);
newArguments.add(substituteInProjection(
substitutionContext,
substitution,
argument,
parameterDescriptor,
callSiteVariance));
@@ -102,7 +102,7 @@ public class ConstraintSystem {
}
}
System.out.println("minimal solution from lowerbounds for " + this + " is " + commonSupertype);
println("minimal solution from lowerbounds for " + this + " is " + commonSupertype);
value = new KnownType(commonSupertype);
}
else {
@@ -121,7 +121,7 @@ public class ConstraintSystem {
return value;
}
private Set<JetType> getTypes(Set<TypeValue> lowerBounds) {
Set<JetType> types = Sets.newHashSet();
for (TypeValue lowerBound : lowerBounds) {
@@ -206,7 +206,7 @@ public class ConstraintSystem {
}
private void addSubtypingConstraintOnTypeValues(TypeValue typeValueForLower, TypeValue typeValueForUpper) {
System.out.println(typeValueForLower + " :< " + typeValueForUpper);
println(typeValueForLower + " :< " + typeValueForUpper);
typeValueForLower.getUpperBounds().add(typeValueForUpper);
typeValueForUpper.getLowerBounds().add(typeValueForLower);
}
@@ -271,14 +271,14 @@ public class ConstraintSystem {
JetType boundingType = solution.getSubstitutor().substitute(upperBound.getValue().getType(), Variance.INVARIANT);
if (!typeChecker.isSubtypeOf(type, boundingType)) { // TODO
solution.registerError();
System.out.println("Constraint violation: " + type + " :< " + boundingType);
println("Constraint violation: " + type + " :< " + boundingType);
}
}
for (TypeValue lowerBound : typeValue.getLowerBounds()) {
JetType boundingType = solution.getSubstitutor().substitute(lowerBound.getValue().getType(), Variance.INVARIANT);
if (!typeChecker.isSubtypeOf(boundingType, type)) {
solution.registerError();
System.out.println("Constraint violation: " + boundingType + " :< " + type);
println("Constraint violation: " + boundingType + " :< " + type);
}
}
}
@@ -309,7 +309,7 @@ public class ConstraintSystem {
DeclarationDescriptor declarationDescriptor = key.getDeclarationDescriptor();
if (declarationDescriptor instanceof TypeParameterDescriptor) {
TypeParameterDescriptor descriptor = (TypeParameterDescriptor) declarationDescriptor;
System.out.println(descriptor + " |-> " + getValue(descriptor));
println(descriptor + " |-> " + getValue(descriptor));
return new TypeProjection(getValue(descriptor));
}
return null;
@@ -368,12 +368,6 @@ public class ConstraintSystem {
addSubtypingConstraintOnTypeValues(subtypeValue, supertypeValue);
}
return StatusAction.PROCEED;
// // both types are known
// if (typeChecker.isSubtypeOf(subtype, supertype)) {
// return StatusAction.PROCEED;
// }
// return fail();
}
private boolean someUnknown(TypeValue subtypeValue, TypeValue supertypeValue) {
@@ -412,4 +406,8 @@ public class ConstraintSystem {
}
}
private static void println(String message) {
// System.out.println(message);
}
}
@@ -183,8 +183,7 @@ public class DescriptorRenderer {
@Override
public Void visitFunctionDescriptor(FunctionDescriptor descriptor, StringBuilder builder) {
builder.append(renderKeyword("fun")).append(" ");
List<TypeParameterDescriptor> typeParameters = descriptor.getTypeParameters();
renderTypeParameters(typeParameters, builder);
renderTypeParameters(descriptor.getTypeParameters(), builder);
JetType receiverType = descriptor.getReceiverType();
if (receiverType != null) {
@@ -192,6 +191,12 @@ public class DescriptorRenderer {
}
renderName(descriptor, builder);
renderValueParameters(descriptor, builder);
builder.append(" : ").append(escape(renderType(descriptor.getReturnType())));
return super.visitFunctionDescriptor(descriptor, builder);
}
private void renderValueParameters(FunctionDescriptor descriptor, StringBuilder builder) {
builder.append("(");
for (Iterator<ValueParameterDescriptor> iterator = descriptor.getValueParameters().iterator(); iterator.hasNext(); ) {
ValueParameterDescriptor parameterDescriptor = iterator.next();
@@ -200,8 +205,19 @@ public class DescriptorRenderer {
builder.append(", ");
}
}
builder.append(") : ").append(escape(renderType(descriptor.getReturnType())));
return super.visitFunctionDescriptor(descriptor, builder);
builder.append(")");
}
@Override
public Void visitConstructorDescriptor(ConstructorDescriptor constructorDescriptor, StringBuilder builder) {
builder.append(renderKeyword("ctor")).append(" ");
ClassDescriptor classDescriptor = constructorDescriptor.getContainingDeclaration();
builder.append(classDescriptor.getName());
renderTypeParameters(classDescriptor.getTypeConstructor().getParameters(), builder);
renderValueParameters(constructorDescriptor, builder);
return null;
}
private void renderTypeParameters(List<TypeParameterDescriptor> typeParameters, StringBuilder builder) {
+2 -2
View File
@@ -19,7 +19,7 @@ fun test(l : java.util.List<Int>) {
Collections.<error>emptyList</error>
Collections.emptyList<Int>
Collections.emptyList<Int>()
Collections.emptyList<error>()</error>
Collections.emptyList()
Collections.singleton<Int>(1) : Set<Int>?
Collections.singleton<Int><error>(1.0)</error>
@@ -43,7 +43,7 @@ fun test(l : java.util.List<Int>) {
c : java.lang.Comparable<Int>?
// Collections.sort<Integer>(ArrayList<Integer>())
xxx.Class<error>()</error>
xxx.<error>Class</error>()
}
@@ -0,0 +1,12 @@
// One of the two passes is making a scope and turning vals into functions
// See KT-76
namespace x
val b : Foo
val a1 = b.compareTo(2)
class Foo() {
fun compareTo(other : Byte) : Int
fun compareTo(other : Char) : Int
}
+1 -1
View File
@@ -298,7 +298,7 @@ JetFile: FunctionLiterals_ERR.jet
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('T')
PsiElement(DOT)('.')
PsiErrorElement:To specify a receiver type, use the full notation: {ReceiverType.(parameters) [: ReturnType] => ...}
PsiErrorElement:To specify a receiverType type, use the full notation: {ReceiverType.(parameters) [: ReturnType] => ...}
PsiElement(IDENTIFIER)('a')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
+1 -1
View File
@@ -3,7 +3,7 @@ JetFile: Properties_ERR.jet
PROPERTY
PsiElement(var)('var')
PsiWhiteSpace(' ')
PsiErrorElement:Expecting property name or receiver type
PsiErrorElement:Expecting property name or receiverType type
PsiElement(MINUS)('-')
PsiWhiteSpace(' ')
PsiErrorElement:Property getter or setter expected
+2 -2
View File
@@ -23,7 +23,7 @@ JetFile: With.jet
VALUE_PARAMETER_LIST
PsiElement(LPAR)('(')
VALUE_PARAMETER
PsiElement(IDENTIFIER)('receiver')
PsiElement(IDENTIFIER)('receiverType')
PsiWhiteSpace(' ')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
@@ -63,7 +63,7 @@ JetFile: With.jet
PsiWhiteSpace(' ')
DOT_QUALIFIED_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('receiver')
PsiElement(IDENTIFIER)('receiverType')
PsiElement(DOT)('.')
CALL_EXPRESSION
REFERENCE_EXPRESSION
@@ -11,7 +11,10 @@ import com.intellij.psi.search.GlobalSearchScope;
import junit.framework.Test;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.JetTestCaseBase;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
import org.jetbrains.jet.lang.resolve.OverloadResolutionResult;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.parsing.JetParsingTest;
@@ -100,9 +103,10 @@ public class JetResolveTest extends ExtensibleResolveTestCase {
@NotNull
private FunctionDescriptor standardFunction(ClassDescriptor classDescriptor, List<TypeProjection> typeArguments, String name, JetType... parameterType) {
FunctionGroup functionGroup = classDescriptor.getMemberScope(typeArguments).getFunctionGroup(name);
List<JetType> parameterTypeList = Arrays.asList(parameterType);
OverloadResolutionResult functions = functionGroup.getPossiblyApplicableFunctions(Collections.<JetType>emptyList(), parameterTypeList);
JetTypeInferrer.Services typeInferrerServices = JetSemanticServices.createSemanticServices(getProject()).getTypeInferrerServices(new BindingTraceContext(), JetFlowInformationProvider.NONE);
OverloadResolutionResult functions = typeInferrerServices.getCallResolver().resolveExactSignature(classDescriptor.getMemberScope(typeArguments), null, name, parameterTypeList);
for (FunctionDescriptor function : functions.getFunctionDescriptors()) {
List<ValueParameterDescriptor> unsubstitutedValueParameters = function.getValueParameters();
for (int i = 0, unsubstitutedValueParametersSize = unsubstitutedValueParameters.size(); i < unsubstitutedValueParametersSize; i++) {
@@ -606,14 +606,15 @@ public class JetTypeCheckerTest extends LightDaemonAnalyzerTestCase {
@NotNull
@Override
public FunctionGroup getFunctionGroup(@NotNull String name) {
ClassifierDescriptor classifier = getClassifier(name);
if (classifier instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
return classDescriptor.getConstructors();
}
WritableFunctionGroup writableFunctionGroup = new WritableFunctionGroup(name);
// ClassifierDescriptor classifier = getClassifier(name);
// if (classifier instanceof ClassDescriptor) {
// ClassDescriptor classDescriptor = (ClassDescriptor) classifier;
// writableFunctionGroup.addAllFunctions(classDescriptor.getConstructors());
// }
ModuleDescriptor module = new ModuleDescriptor("TypeCheckerTest");
for (String funDecl : FUNCTION_DECLARATIONS) {
FunctionDescriptor functionDescriptor = classDescriptorResolver.resolveFunctionDescriptor(JetStandardClasses.getAny(), this, JetChangeUtil.createFunction(getProject(), funDecl));
FunctionDescriptor functionDescriptor = classDescriptorResolver.resolveFunctionDescriptor(module, this, JetChangeUtil.createFunction(getProject(), funDecl));
if (name.equals(functionDescriptor.getName())) {
writableFunctionGroup.addFunction(functionDescriptor);
}