Overload resolution is factored out as an independent module CallResolver.java

This commit is contained in:
Andrey Breslav
2011-08-24 17:09:51 +04:00
parent 6efc241523
commit 4710835bd4
26 changed files with 1416 additions and 1003 deletions
+2 -2
View File
@@ -117,10 +117,10 @@ public interface JetNodeTypes {
JetNodeType CALL_EXPRESSION = new JetNodeType("CALL_EXPRESSION", JetCallExpression.class);
JetNodeType ARRAY_ACCESS_EXPRESSION = new JetNodeType("ARRAY_ACCESS_EXPRESSION", JetArrayAccessExpression.class);
JetNodeType INDICES = new JetNodeType("INDICES", JetContainerNode.class);
JetNodeType DOT_QUALIFIED_EXPRESSION = new JetNodeType("DOT_QUALIFIED_EXPRESSION", JetDotQualifiedExpression.class);
JetNodeType DOT_QUALIFIED_EXPRESSION = new JetNodeType("DOT_QUALIFIED_EXPRESSION", JetDotQualifiedExpression.class);
JetNodeType HASH_QUALIFIED_EXPRESSION = new JetNodeType("HASH_QUALIFIED_EXPRESSION", JetHashQualifiedExpression.class);
JetNodeType SAFE_ACCESS_EXPRESSION = new JetNodeType("SAFE_ACCESS_EXPRESSION", JetSafeQualifiedExpression.class);
JetNodeType PREDICATE_EXPRESSION = new JetNodeType("PREDICATE_EXPRESSION", JetPredicateExpression.class);
JetNodeType PREDICATE_EXPRESSION = new JetNodeType("PREDICATE_EXPRESSION", JetPredicateExpression.class);
JetNodeType OBJECT_LITERAL = new JetNodeType("OBJECT_LITERAL", JetObjectLiteralExpression.class);
JetNodeType ROOT_NAMESPACE = new JetNodeType("ROOT_NAMESPACE", JetRootNamespaceExpression.class);
@@ -828,7 +828,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
else {
IntrinsicMethod intrinsic = (IntrinsicMethod) callable;
List<JetExpression> args = new ArrayList<JetExpression>();
for (JetValueArgument argument : expression.getValueArguments()) {
for (ValueArgument argument : expression.getValueArguments()) {
args.add(argument.getArgumentExpression());
}
return intrinsic.generate(this, v, expressionType(expression), expression, args, receiver);
@@ -876,11 +876,11 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return funDescriptor;
}
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCall expression) {
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCallElement expression) {
invokeMethodWithArguments(callableMethod, expression, StackValue.none());
}
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCall expression, StackValue receiver) {
public void invokeMethodWithArguments(CallableMethod callableMethod, JetCallElement expression, StackValue receiver) {
final Type calleeType = callableMethod.getGenerateCalleeType();
if (calleeType != null && expression instanceof JetCallExpression) {
gen(expression.getCalleeExpression(), calleeType);
@@ -901,7 +901,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
callableMethod.invoke(v);
}
private void setOwnerFromCall(CallableMethod callableMethod, JetCall expression) {
private void setOwnerFromCall(CallableMethod callableMethod, JetCallElement expression) {
if (expression.getParent() instanceof JetQualifiedExpression) {
final JetExpression receiver = ((JetQualifiedExpression) expression.getParent()).getReceiverExpression();
JetType expressionType = bindingContext.get(BindingContext.EXPRESSION_TYPE, receiver);
@@ -993,10 +993,10 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return false;
}
private void pushMethodArguments(JetCall expression, List<Type> valueParameterTypes) {
List<JetValueArgument> args = expression.getValueArguments();
private void pushMethodArguments(JetCallElement expression, List<Type> valueParameterTypes) {
List<? extends ValueArgument> args = expression.getValueArguments();
for (int i = 0, argsSize = args.size(); i < argsSize; i++) {
JetValueArgument arg = args.get(i);
ValueArgument arg = args.get(i);
gen(arg.getArgumentExpression(), valueParameterTypes.get(i));
}
}
@@ -1430,7 +1430,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
return StackValue.onStack(type);
}
private void pushTypeArguments(JetCall expression) {
private void pushTypeArguments(JetCallElement expression) {
for (JetTypeProjection jetTypeArgument : expression.getTypeArguments()) {
pushTypeArgument(jetTypeArgument);
}
@@ -1458,7 +1458,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> {
}
private void generateNewArray(JetCallExpression expression, Type type) {
List<JetValueArgument> args = expression.getValueArguments();
List<? extends ValueArgument> args = expression.getValueArguments();
if (args.size() != 1) {
throw new CompilationException("array constructor requires one value argument");
}
@@ -294,7 +294,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
return outerDescriptor instanceof ClassDescriptor ? (ClassDescriptor) outerDescriptor : null;
}
private void generateDelegatorToConstructorCall(InstructionAdapter iv, ExpressionCodegen codegen, JetCall constructorCall,
private void generateDelegatorToConstructorCall(InstructionAdapter iv, ExpressionCodegen codegen, JetCallElement constructorCall,
ConstructorDescriptor constructorDescriptor, boolean isJavaSuperclass,
ConstructorFrameMap frameMap) {
ClassDescriptor classDecl = constructorDescriptor.getContainingDeclaration();
@@ -25,13 +25,11 @@ public class JetSemanticServices {
private final JetStandardLibrary standardLibrary;
private final JetTypeChecker typeChecker;
private final OverloadResolver overloadResolver;
private final JetControlFlowDataTraceFactory flowDataTraceFactory;
private JetSemanticServices(JetStandardLibrary standardLibrary, JetControlFlowDataTraceFactory flowDataTraceFactory) {
this.standardLibrary = standardLibrary;
this.typeChecker = new JetTypeChecker(standardLibrary);
this.overloadResolver = new OverloadResolver(typeChecker);
this.flowDataTraceFactory = flowDataTraceFactory;
}
@@ -54,10 +52,4 @@ public class JetSemanticServices {
public JetTypeChecker getTypeChecker() {
return typeChecker;
}
@NotNull
public OverloadResolver getOverloadResolver() {
return overloadResolver;
}
}
@@ -530,8 +530,8 @@ public class JetControlFlowProcessor {
builder.read(expression);
}
private void visitCall(JetCall call) {
for (JetValueArgument argument : call.getValueArguments()) {
private void visitCall(JetCallElement call) {
for (ValueArgument argument : call.getValueArguments()) {
JetExpression argumentExpression = argument.getArgumentExpression();
if (argumentExpression != null) {
value(argumentExpression, false, false);
@@ -73,13 +73,10 @@ public class FunctionDescriptorUtil {
if (substitutedType == null) return null;
result.add(new ValueParameterDescriptorImpl(
substitutedDescriptor,
i,
unsubstitutedValueParameter,
unsubstitutedValueParameter.getAnnotations(),
unsubstitutedValueParameter.getName(),
unsubstitutedValueParameter.getInType() == null ? null : substitutedType,
substitutedType,
unsubstitutedValueParameter.hasDefaultValue(),
unsubstitutedValueParameter.isVararg()
substitutedType
));
}
return result;
@@ -64,9 +64,17 @@ public class LazySubstitutingFunctionGroup implements FunctionGroup {
@Override
public Set<FunctionDescriptor> getFunctionDescriptors() {
if (functionDescriptors == null) {
functionDescriptors = Sets.newHashSet();
for (FunctionDescriptor descriptor : functionGroup.getFunctionDescriptors()) {
functionDescriptors.add(descriptor.substitute(substitutor));
if (substitutor.isEmpty()) {
functionDescriptors = functionGroup.getFunctionDescriptors();
}
else {
functionDescriptors = Sets.newHashSet();
for (FunctionDescriptor descriptor : functionGroup.getFunctionDescriptors()) {
FunctionDescriptor substitute = descriptor.substitute(substitutor);
if (substitute != null) {
functionDescriptors.add(substitute);
}
}
}
}
return functionDescriptors;
@@ -16,6 +16,7 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
private final boolean isVararg;
private final boolean isVar;
private final int index;
private final ValueParameterDescriptor original;
public ValueParameterDescriptorImpl(
@NotNull DeclarationDescriptor containingDeclaration,
@@ -27,6 +28,7 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
boolean hasDefaultValue,
boolean isVararg) {
super(containingDeclaration, annotations, name, inType, outType);
this.original = this;
this.index = index;
this.hasDefaultValue = hasDefaultValue;
this.isVararg = isVararg;
@@ -35,17 +37,17 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
public ValueParameterDescriptorImpl(
@NotNull DeclarationDescriptor containingDeclaration,
int index,
@NotNull ValueParameterDescriptor original,
@NotNull List<AnnotationDescriptor> annotations,
@NotNull String name,
boolean isVar,
boolean hasDefaultValue,
boolean isVararg) {
super(containingDeclaration, annotations, name, null, null);
this.index = index;
this.hasDefaultValue = hasDefaultValue;
this.isVararg = isVararg;
this.isVar = isVar;
@Nullable JetType inType,
@NotNull JetType outType
) {
super(containingDeclaration, annotations, original.getName(), inType, outType);
this.original = original;
this.index = original.getIndex();
this.hasDefaultValue = original.hasDefaultValue();
this.isVararg = original.isVararg();
this.isVar = inType != null;
}
@Override
@@ -61,12 +63,6 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@Override
public int getIndex() {
return index;
// final JetDeclaration element = getPsiElement();
// final PsiElement parent = element.getParent();
// if (parent instanceof JetParameterList) {
// return ((JetParameterList) parent).getParameters().indexOf(element);
// }
// throw new IllegalStateException("couldn't find index for parameter");
}
@Override
@@ -86,7 +82,13 @@ public class ValueParameterDescriptorImpl extends VariableDescriptorImpl impleme
@NotNull
@Override
public VariableDescriptor substitute(TypeSubstitutor substitutor) {
public ValueParameterDescriptor getOriginal() {
return original == this ? this : original.getOriginal();
}
@NotNull
@Override
public ValueParameterDescriptor substitute(TypeSubstitutor substitutor) {
throw new UnsupportedOperationException(); // TODO
}
@@ -1,6 +1,5 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -9,7 +8,7 @@ import java.util.List;
/**
* @author abreslav
*/
public interface JetCall extends PsiElement {
public interface Call {
@Nullable
JetExpression getCalleeExpression();
@@ -17,7 +16,7 @@ public interface JetCall extends PsiElement {
JetValueArgumentList getValueArgumentList();
@NotNull
List<JetValueArgument> getValueArguments();
List<? extends ValueArgument> getValueArguments();
@NotNull
List<JetExpression> getFunctionLiteralArguments();
@@ -25,6 +24,6 @@ public interface JetCall extends PsiElement {
@NotNull
List<JetTypeProjection> getTypeArguments();
@NotNull
JetElement asElement();
@Nullable
JetTypeArgumentList getTypeArgumentList();
}
@@ -11,7 +11,7 @@ import java.util.List;
/**
* @author max
*/
public class JetAnnotationEntry extends JetElement implements JetCall {
public class JetAnnotationEntry extends JetElement implements JetCallElement {
public JetAnnotationEntry(@NotNull ASTNode node) {
super(node);
}
@@ -48,7 +48,7 @@ public class JetAnnotationEntry extends JetElement implements JetCall {
@NotNull
@Override
public List<JetValueArgument> getValueArguments() {
public List<? extends ValueArgument> getValueArguments() {
JetValueArgumentList list = getValueArgumentList();
return list != null ? list.getArguments() : Collections.<JetValueArgument>emptyList();
}
@@ -62,20 +62,25 @@ public class JetAnnotationEntry extends JetElement implements JetCall {
@NotNull
@Override
public List<JetTypeProjection> getTypeArguments() {
JetTypeReference typeReference = getTypeReference();
if (typeReference != null) {
JetTypeElement typeElement = typeReference.getTypeElement();
if (typeElement instanceof JetUserType) {
JetUserType userType = (JetUserType) typeElement;
return userType.getTypeArguments();
}
JetTypeArgumentList typeArgumentList = getTypeArgumentList();
if (typeArgumentList == null) {
return Collections.emptyList();
}
return Collections.emptyList();
return typeArgumentList.getArguments();
}
@NotNull
@Override
public JetElement asElement() {
return this;
public JetTypeArgumentList getTypeArgumentList() {
JetTypeReference typeReference = getTypeReference();
if (typeReference == null) {
return null;
}
JetTypeElement typeElement = typeReference.getTypeElement();
if (typeElement instanceof JetUserType) {
JetUserType userType = (JetUserType) typeElement;
return userType.getTypeArgumentList();
}
return null;
}
}
@@ -54,5 +54,4 @@ public class JetBinaryExpression extends JetExpression {
public IElementType getOperationToken() {
return getOperationReference().getReferencedNameElementType();
}
}
@@ -0,0 +1,14 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
/**
* @author abreslav
*/
public interface JetCallElement extends PsiElement, Call {
}
@@ -11,7 +11,7 @@ import java.util.List;
/**
* @author max
*/
public class JetCallExpression extends JetExpression implements JetCall {
public class JetCallExpression extends JetExpression implements JetCallElement {
public JetCallExpression(@NotNull ASTNode node) {
super(node);
}
@@ -49,15 +49,9 @@ public class JetCallExpression extends JetExpression implements JetCall {
return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL_EXPRESSION);
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
@Override
@NotNull
public List<JetValueArgument> getValueArguments() {
public List<? extends ValueArgument> getValueArguments() {
JetValueArgumentList list = getValueArgumentList();
return list != null ? list.getArguments() : Collections.<JetValueArgument>emptyList();
}
@@ -11,7 +11,7 @@ import java.util.List;
/**
* @author max
*/
public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements JetCall {
public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements JetCallElement {
public JetDelegatorToSuperCall(@NotNull ASTNode node) {
super(node);
}
@@ -38,7 +38,7 @@ public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements J
}
@NotNull
public List<JetValueArgument> getValueArguments() {
public List<? extends ValueArgument> getValueArguments() {
JetValueArgumentList list = getValueArgumentList();
return list != null ? list.getArguments() : Collections.<JetValueArgument>emptyList();
}
@@ -57,20 +57,25 @@ public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements J
@NotNull
@Override
public List<JetTypeProjection> getTypeArguments() {
JetTypeReference typeReference = getTypeReference();
if (typeReference != null) {
JetTypeElement typeElement = typeReference.getTypeElement();
if (typeElement instanceof JetUserType) {
JetUserType userType = (JetUserType) typeElement;
return userType.getTypeArguments();
}
JetTypeArgumentList typeArgumentList = getTypeArgumentList();
if (typeArgumentList == null) {
return Collections.emptyList();
}
return Collections.emptyList();
return typeArgumentList.getArguments();
}
@NotNull
@Override
public JetElement asElement() {
return this;
public JetTypeArgumentList getTypeArgumentList() {
JetTypeReference typeReference = getTypeReference();
if (typeReference == null) {
return null;
}
JetTypeElement typeElement = typeReference.getTypeElement();
if (typeElement instanceof JetUserType) {
JetUserType userType = (JetUserType) typeElement;
return userType.getTypeArgumentList();
}
return null;
}
}
@@ -11,7 +11,7 @@ import java.util.List;
/**
* @author max
*/
public class JetDelegatorToThisCall extends JetDelegationSpecifier implements JetCall {
public class JetDelegatorToThisCall extends JetDelegationSpecifier implements JetCallElement {
public JetDelegatorToThisCall(@NotNull ASTNode node) {
super(node);
@@ -38,7 +38,7 @@ public class JetDelegatorToThisCall extends JetDelegationSpecifier implements Je
}
@NotNull
public List<JetValueArgument> getValueArguments() {
public List<? extends ValueArgument> getValueArguments() {
JetValueArgumentList list = getValueArgumentList();
return list != null ? list.getArguments() : Collections.<JetValueArgument>emptyList();
}
@@ -49,18 +49,17 @@ public class JetDelegatorToThisCall extends JetDelegationSpecifier implements Je
return Collections.emptyList();
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
@NotNull
@Override
public List<JetTypeProjection> getTypeArguments() {
return Collections.emptyList();
}
@Override
public JetTypeArgumentList getTypeArgumentList() {
return null;
}
public JetReferenceExpression getThisReference() {
return findChildByClass(JetThisReferenceExpression.class);
}
@@ -3,7 +3,7 @@ package org.jetbrains.jet.lang.psi;
/**
* @author max
*/
//public class JetNewExpression extends JetExpression implements JetCall {
//public class JetNewExpression extends JetExpression implements JetCallElement {
// public JetNewExpression(@NotNull ASTNode node) {
// super(node);
// }
@@ -1,6 +1,7 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes;
@@ -9,7 +10,7 @@ import org.jetbrains.jet.lexer.JetTokens;
/**
* @author max
*/
public class JetValueArgument extends JetElement {
public class JetValueArgument extends JetElement implements ValueArgument {
public JetValueArgument(@NotNull ASTNode node) {
super(node);
}
@@ -23,25 +24,36 @@ public class JetValueArgument extends JetElement {
return visitor.visitArgument(this, data);
}
@Override
@Nullable @IfNotParsed
public JetExpression getArgumentExpression() {
return findChildByClass(JetExpression.class);
}
@Override
@Nullable
public JetValueArgumentName getArgumentName() {
return (JetValueArgumentName) findChildByType(JetNodeTypes.VALUE_ARGUMENT_NAME);
}
@Override
public boolean isNamed() {
return getArgumentName() != null;
}
@Override
public boolean isOut() {
return findChildByType(JetTokens.OUT_KEYWORD) != null;
}
@Override
public boolean isRef() {
return findChildByType(JetTokens.REF_KEYWORD) != null;
}
@NotNull
@Override
public PsiElement asElement() {
return this;
}
}
@@ -0,0 +1,27 @@
package org.jetbrains.jet.lang.psi;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* @author abreslav
*/
public interface ValueArgument {
@Nullable
@JetElement.IfNotParsed
JetExpression getArgumentExpression();
@Nullable
JetValueArgumentName getArgumentName();
boolean isNamed();
boolean isOut();
boolean isRef();
@NotNull
PsiElement asElement();
}
@@ -1,55 +1,48 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.JetType;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
public interface OverloadDomain {
OverloadDomain EMPTY = new OverloadDomain() {
@NotNull
@Override
public OverloadResolutionResult getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) {
return OverloadResolutionResult.nameNotFound();
}
@NotNull
@Override
public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
return OverloadResolutionResult.nameNotFound();
}
@Override
public boolean isEmpty() {
return true;
}
};
/**
* @return A function descriptor with NO type parameters (they are already substituted) wrapped together with a result code
*/
@NotNull
OverloadResolutionResult getFunctionDescriptorForNamedArguments(
@NotNull List<JetType> typeArguments,
@NotNull Map<String, JetType> valueArgumentTypes,
@Nullable JetType functionLiteralArgumentType);
/**
* @return A function descriptor with NO type parameters (they are already substituted) wrapped together with a result code
*/
@NotNull
OverloadResolutionResult getFunctionDescriptorForPositionedArguments(
@NotNull List<JetType> typeArguments,
@NotNull List<JetType> positionedValueArgumentTypes);
/**
* @return true if the domain is empty
*/
boolean isEmpty();
}
//public interface OverloadDomain {
//
// OverloadDomain EMPTY = new OverloadDomain() {
// @NotNull
// @Override
// public OverloadResolutionResult getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) {
// return OverloadResolutionResult.nameNotFound();
// }
//
// @NotNull
// @Override
// public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
// return OverloadResolutionResult.nameNotFound();
// }
//
// @Override
// public boolean isEmpty() {
// return true;
// }
// };
//
// /**
// * @return A function descriptor with NO type parameters (they are already substituted) wrapped together with a result code
// */
// @NotNull
// OverloadResolutionResult getFunctionDescriptorForNamedArguments(
// @NotNull List<JetType> typeArguments,
// @NotNull Map<String, JetType> valueArgumentTypes,
// @Nullable JetType functionLiteralArgumentType);
//
// /**
// * @return A function descriptor with NO type parameters (they are already substituted) wrapped together with a result code
// */
// @NotNull
// OverloadResolutionResult getFunctionDescriptorForPositionedArguments(
// @NotNull List<JetType> typeArguments,
// @NotNull List<JetType> positionedValueArgumentTypes);
//
// /**
// * @return true if the domain is empty
// */
// boolean isEmpty();
//}
@@ -1,173 +1,159 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionGroup;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import org.jetbrains.jet.lang.types.TypeUtils;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
*/
public class OverloadResolver {
private final JetTypeChecker typeChecker;
public OverloadResolver(JetTypeChecker typeChecker) {
this.typeChecker = typeChecker;
}
@NotNull
public OverloadDomain getOverloadDomain(@Nullable JetType receiverType, @NotNull JetScope outerScope, @NotNull String name) {
// TODO : extension lookup
JetScope scope = receiverType == null ? outerScope : new ScopeWithReceiver(outerScope, receiverType, typeChecker);
final FunctionGroup functionGroup = scope.getFunctionGroup(name);
return getOverloadDomain(receiverType, functionGroup);
}
@NotNull
public OverloadDomain getOverloadDomain(@Nullable final JetType receiverType, @NotNull final FunctionGroup functionGroup) {
if (functionGroup.isEmpty()) {
return OverloadDomain.EMPTY;
}
return new OverloadDomain() {
@NotNull
@Override
public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull final List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
OverloadResolutionResult resolutionResult = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
if (!resolutionResult.isAmbiguity() && !resolutionResult.isSuccess()) return resolutionResult;
Collection<FunctionDescriptor> possiblyApplicableFunctions = resolutionResult.getFunctionDescriptors();
if (possiblyApplicableFunctions.isEmpty()) {
return OverloadResolutionResult.nameNotFound(); // TODO : it may be found, only the number of params did not match
}
List<FunctionDescriptor> applicable = new ArrayList<FunctionDescriptor>();
descLoop:
for (FunctionDescriptor descriptor : possiblyApplicableFunctions) {
// ASSERT: type arguments are figured out and substituted by this time!!!
assert descriptor.getTypeParameters().isEmpty();
if (receiverType != null) {
// ASSERT : either the receiver in not present or we are in a scope with no top-level functions
JetType functionReceiverType = descriptor.getReceiverType();
if (functionReceiverType != null) {
functionReceiverType = TypeUtils.makeNullable(functionReceiverType); // Too look things up in T for T?, and later check receiver's nullability
if (!typeChecker.isSubtypeOf(receiverType, functionReceiverType)) {
continue;
}
}
}
else if (descriptor.getReceiverType() != null) {
continue;
}
List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
if (parameters.size() >= positionedValueArgumentTypes.size()) {
// possibly, some default values
// possibly, nothing passed to a vararg
// possibly, a single value passed to a vararg
// possibly an array/list/etc passed as a whole vararg
for (int i = 0, positionedValueArgumentTypesSize = positionedValueArgumentTypes.size(); i < positionedValueArgumentTypesSize; i++) {
JetType argumentType = positionedValueArgumentTypes.get(i);
JetType parameterType = parameters.get(i).getOutType();
// TODO : handle vararg cases here
if (!typeChecker.isConvertibleTo(argumentType, parameterType)) {
continue descLoop;
}
}
} else {
// vararg
int nonVarargs = parameters.size() - 1;
for (int i = 0; i < nonVarargs; i++) {
JetType argumentType = positionedValueArgumentTypes.get(i);
JetType parameterType = parameters.get(i).getOutType();
if (!typeChecker.isConvertibleTo(argumentType, parameterType)) {
continue descLoop;
}
}
JetType varArgType = parameters.get(nonVarargs).getOutType();
for (int i = nonVarargs, args = positionedValueArgumentTypes.size(); i < args; i++) {
JetType argumentType = positionedValueArgumentTypes.get(i);
if (!typeChecker.isConvertibleTo(argumentType, varArgType)) {
continue descLoop;
}
}
}
applicable.add(descriptor);
}
if (applicable.size() == 0) {
if (resolutionResult.singleFunction()) {
return OverloadResolutionResult.singleFunctionArgumentMismatch(resolutionResult.getFunctionDescriptor());
}
return OverloadResolutionResult.nameNotFound();
} else if (applicable.size() == 1) {
return OverloadResolutionResult.success(applicable.get(0));
} else {
// TODO : varargs
List<FunctionDescriptor> maximallySpecific = new ArrayList<FunctionDescriptor>();
meLoop:
for (FunctionDescriptor me : applicable) {
for (FunctionDescriptor other : applicable) {
if (other == me) continue;
if (!moreSpecific(me, other) || moreSpecific(other, me)) continue meLoop;
}
maximallySpecific.add(me);
}
if (maximallySpecific.isEmpty()) {
return OverloadResolutionResult.ambiguity(applicable);
}
if (maximallySpecific.size() == 1) {
return OverloadResolutionResult.success(maximallySpecific.get(0));
}
throw new UnsupportedOperationException();
}
}
@Override
public boolean isEmpty() {
return functionGroup.isEmpty();
}
@NotNull
@Override
public OverloadResolutionResult getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) {
throw new UnsupportedOperationException(); // TODO
}
};
}
private boolean moreSpecific(FunctionDescriptor f, FunctionDescriptor g) {
List<ValueParameterDescriptor> fParams = f.getValueParameters();
List<ValueParameterDescriptor> gParams = g.getValueParameters();
int fSize = fParams.size();
if (fSize != gParams.size()) return false;
for (int i = 0; i < fSize; i++) {
JetType fParamType = fParams.get(i).getOutType();
JetType gParamType = gParams.get(i).getOutType();
// TODO : maybe isSubtypeOf is sufficient?
if (!typeChecker.isConvertibleTo(fParamType, gParamType)) {
return false;
}
}
return true;
}
}
//public class OverloadResolver {
//
// private final JetTypeChecker typeChecker;
//
// public OverloadResolver(JetTypeChecker typeChecker) {
// this.typeChecker = typeChecker;
// }
//
// @NotNull
// public OverloadDomain getOverloadDomain(@Nullable JetType receiverType, @NotNull JetScope outerScope, @NotNull String name) {
// // TODO : extension lookup
// JetScope scope = receiverType == null ? outerScope : new ScopeWithReceiver(outerScope, receiverType, typeChecker);
//
// final FunctionGroup functionGroup = scope.getFunctionGroup(name);
//
// return getOverloadDomain(receiverType, functionGroup);
// }
//
// @NotNull
// public OverloadDomain getOverloadDomain(@Nullable final JetType receiverType, @NotNull final FunctionGroup functionGroup) {
// if (functionGroup.isEmpty()) {
// return OverloadDomain.EMPTY;
// }
//
// return new OverloadDomain() {
// @NotNull
// @Override
// public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull final List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
// OverloadResolutionResult resolutionResult = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
// if (!resolutionResult.isAmbiguity() && !resolutionResult.isSuccess()) return resolutionResult;
//
// Collection<FunctionDescriptor> possiblyApplicableFunctions = resolutionResult.getFunctionDescriptors();
//
// if (possiblyApplicableFunctions.isEmpty()) {
// return OverloadResolutionResult.nameNotFound(); // TODO : it may be found, only the number of params did not match
// }
//
// List<FunctionDescriptor> applicable = new ArrayList<FunctionDescriptor>();
//
// descLoop:
// for (FunctionDescriptor descriptor : possiblyApplicableFunctions) {
// // ASSERT: type arguments are figured out and substituted by this time!!!
// assert descriptor.getTypeParameters().isEmpty();
//
// if (receiverType != null) {
// // ASSERT : either the receiver in not present or we are in a scope with no top-level functions
// JetType functionReceiverType = descriptor.getReceiverType();
// if (functionReceiverType != null) {
// functionReceiverType = TypeUtils.makeNullable(functionReceiverType); // Too look things up in T for T?, and later check receiver's nullability
// if (!typeChecker.isSubtypeOf(receiverType, functionReceiverType)) {
// continue;
// }
// }
// }
// else if (descriptor.getReceiverType() != null) {
// continue;
// }
//
// List<ValueParameterDescriptor> parameters = descriptor.getValueParameters();
// if (parameters.size() >= positionedValueArgumentTypes.size()) {
// // possibly, some default values
// // possibly, nothing passed to a vararg
// // possibly, a single value passed to a vararg
// // possibly an array/list/etc passed as a whole vararg
// for (int i = 0, positionedValueArgumentTypesSize = positionedValueArgumentTypes.size(); i < positionedValueArgumentTypesSize; i++) {
// JetType argumentType = positionedValueArgumentTypes.get(i);
// JetType parameterType = parameters.get(i).getOutType();
// // TODO : handle vararg cases here
// if (!typeChecker.isConvertibleTo(argumentType, parameterType)) {
// continue descLoop;
// }
// }
// } else {
// // vararg
// int nonVarargs = parameters.size() - 1;
// for (int i = 0; i < nonVarargs; i++) {
// JetType argumentType = positionedValueArgumentTypes.get(i);
// JetType parameterType = parameters.get(i).getOutType();
// if (!typeChecker.isConvertibleTo(argumentType, parameterType)) {
// continue descLoop;
// }
// }
// JetType varArgType = parameters.get(nonVarargs).getOutType();
// for (int i = nonVarargs, args = positionedValueArgumentTypes.size(); i < args; i++) {
// JetType argumentType = positionedValueArgumentTypes.get(i);
// if (!typeChecker.isConvertibleTo(argumentType, varArgType)) {
// continue descLoop;
// }
// }
// }
// applicable.add(descriptor);
// }
//
// if (applicable.size() == 0) {
// if (resolutionResult.singleFunction()) {
// return OverloadResolutionResult.singleFunctionArgumentMismatch(resolutionResult.getFunctionDescriptor());
// }
// return OverloadResolutionResult.nameNotFound();
// } else if (applicable.size() == 1) {
// return OverloadResolutionResult.success(applicable.get(0));
// } else {
// // TODO : varargs
//
// List<FunctionDescriptor> maximallySpecific = new ArrayList<FunctionDescriptor>();
// meLoop:
// for (FunctionDescriptor me : applicable) {
// for (FunctionDescriptor other : applicable) {
// if (other == me) continue;
// if (!moreSpecific(me, other) || moreSpecific(other, me)) continue meLoop;
// }
// maximallySpecific.add(me);
// }
// if (maximallySpecific.isEmpty()) {
// return OverloadResolutionResult.ambiguity(applicable);
// }
// if (maximallySpecific.size() == 1) {
// return OverloadResolutionResult.success(maximallySpecific.get(0));
// }
// throw new UnsupportedOperationException();
// }
// }
//
// @Override
// public boolean isEmpty() {
// return functionGroup.isEmpty();
// }
//
// @NotNull
// @Override
// public OverloadResolutionResult getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) {
// throw new UnsupportedOperationException(); // TODO
// }
// };
// }
//
// private boolean moreSpecific(FunctionDescriptor f, FunctionDescriptor g) {
// List<ValueParameterDescriptor> fParams = f.getValueParameters();
// List<ValueParameterDescriptor> gParams = g.getValueParameters();
//
// int fSize = fParams.size();
// if (fSize != gParams.size()) return false;
// for (int i = 0; i < fSize; i++) {
// JetType fParamType = fParams.get(i).getOutType();
// JetType gParamType = gParams.get(i).getOutType();
//
// // TODO : maybe isSubtypeOf is sufficient?
// if (!typeChecker.isConvertibleTo(fParamType, gParamType)) {
// return false;
// }
// }
// return true;
// }
//
//}
@@ -94,7 +94,9 @@ public class SubstitutingScope implements JetScope {
if (allDescriptors == null) {
allDescriptors = Sets.newHashSet();
for (DeclarationDescriptor descriptor : workerScope.getAllDescriptors()) {
allDescriptors.add(descriptor.substitute(substitutor));
DeclarationDescriptor substitute = descriptor.substitute(substitutor);
assert substitute != null;
allDescriptors.add(substitute);
}
}
return allDescriptors;
@@ -11,15 +11,14 @@ import org.jetbrains.jet.lang.cfg.JetFlowInformationProvider;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.types.ErrorUtils;
import org.jetbrains.jet.lang.types.JetStandardClasses;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeInferrer;
import org.jetbrains.jet.lang.types.*;
import org.jetbrains.jet.lexer.JetTokens;
import org.jetbrains.jet.util.WritableSlice;
import java.util.*;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
/**
* @author abreslav
*/
@@ -568,7 +567,7 @@ public class TopDownAnalyzer {
JetExpression delegateExpression = specifier.getDelegateExpression();
if (delegateExpression != null) {
JetScope scope = scopeForConstructor == null ? descriptor.getScopeForMemberResolution() : scopeForConstructor;
JetType type = typeInferrer.getType(scope, delegateExpression, false, JetTypeInferrer.NO_EXPECTED_TYPE);
JetType type = typeInferrer.getType(scope, delegateExpression, false, NO_EXPECTED_TYPE);
JetType supertype = trace.getBindingContext().get(BindingContext.TYPE, specifier.getTypeReference());
if (type != null && !semanticServices.getTypeChecker().isSubtypeOf(type, supertype)) { // TODO : Convertible?
trace.getErrorHandler().typeMismatch(delegateExpression, supertype, type);
@@ -581,7 +580,7 @@ public class TopDownAnalyzer {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
if (descriptor.getUnsubstitutedPrimaryConstructor() != null) {
typeInferrer.checkTypeInitializerCall(scopeForConstructor, typeReference, call);
typeInferrer.getCallResolver().resolveCall(scopeForConstructor, call, NO_EXPECTED_TYPE);
}
else {
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
@@ -644,7 +643,7 @@ public class TopDownAnalyzer {
final JetScope scopeForConstructor = getInnerScopeForConstructor(primaryConstructor, classDescriptor.getScopeForMemberResolution(), true);
JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, JetFlowInformationProvider.NONE); // TODO : flow
for (JetClassInitializer anonymousInitializer : anonymousInitializers) {
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), true, JetTypeInferrer.NO_EXPECTED_TYPE);
typeInferrer.getType(scopeForConstructor, anonymousInitializer.getBody(), true, NO_EXPECTED_TYPE);
}
}
else {
@@ -686,7 +685,7 @@ public class TopDownAnalyzer {
public void visitDelegationToSuperCallSpecifier(JetDelegatorToSuperCall call) {
JetTypeReference typeReference = call.getTypeReference();
if (typeReference != null) {
typeInferrerForInitializers.checkTypeInitializerCall(functionInnerScope, typeReference, call);
typeInferrerForInitializers.getCallResolver().resolveCall(functionInnerScope, call, NO_EXPECTED_TYPE);
}
}
@@ -694,13 +693,14 @@ public class TopDownAnalyzer {
public void visitDelegationToThisCall(JetDelegatorToThisCall call) {
// TODO : check that there's no recursion in this() calls
// TODO : check: if a this() call is present, no other initializers are allowed
ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
typeInferrerForInitializers.checkClassConstructorCall(
functionInnerScope,
call.getThisReference(),
classDescriptor,
classDescriptor.getDefaultType(),
call);
// ClassDescriptor classDescriptor = descriptor.getContainingDeclaration();
// typeInferrerForInitializers.checkClassConstructorCall(
// functionInnerScope,
// call.getThisReference(),
// classDescriptor,
// classDescriptor.getDefaultType(),
// call);
trace.getErrorHandler().genericError(call.getNode(), "this-calls are not supported");
}
@Override
@@ -859,7 +859,7 @@ public class TopDownAnalyzer {
private void resolvePropertyInitializer(JetProperty property, PropertyDescriptor propertyDescriptor, JetExpression initializer, JetScope scope) {
JetFlowInformationProvider flowInformationProvider = classDescriptorResolver.computeFlowData(property, initializer); // TODO : flow JET-15
JetTypeInferrer.Services typeInferrer = semanticServices.getTypeInferrerServices(traceForConstructors, flowInformationProvider);
JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, false, JetTypeInferrer.NO_EXPECTED_TYPE);
JetType type = typeInferrer.getType(getPropertyDeclarationInnerScope(scope, propertyDescriptor), initializer, false, NO_EXPECTED_TYPE);
JetType expectedType;
PropertySetterDescriptor setter = propertyDescriptor.getSetter();
@@ -0,0 +1,117 @@
package org.jetbrains.jet.lang.types;
import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.psi.*;
import java.util.Collections;
import java.util.List;
/**
* @author abreslav
*/
public class CallMaker {
private static class ExpressionValueArgument implements ValueArgument {
private final JetExpression expression;
private ExpressionValueArgument(JetExpression expression) {
this.expression = expression;
}
@Override
public JetExpression getArgumentExpression() {
return expression;
}
@Override
public JetValueArgumentName getArgumentName() {
return null;
}
@Override
public boolean isNamed() {
return false;
}
@Override
public boolean isOut() {
return false;
}
@Override
public boolean isRef() {
return false;
}
@NotNull
@Override
public PsiElement asElement() {
return expression;
}
}
private static abstract class CallStub implements Call {
@Override
public JetValueArgumentList getValueArgumentList() {
return null;
}
@NotNull
@Override
public List<JetExpression> getFunctionLiteralArguments() {
return Collections.emptyList();
}
@NotNull
@Override
public List<JetTypeProjection> getTypeArguments() {
return Collections.emptyList();
}
@Override
public JetTypeArgumentList getTypeArgumentList() {
return null;
}
}
public static Call makeCallWithArguments(final JetExpression calleeExpression, final List<? extends ValueArgument> valueArguments) {
return new CallStub() {
@Override
public JetExpression getCalleeExpression() {
return calleeExpression;
}
@NotNull
@Override
public List<? extends ValueArgument> getValueArguments() {
return valueArguments;
}
};
}
public static Call makeCall(final JetExpression calleeExpression, final List<JetExpression> argumentExpressions) {
List<ExpressionValueArgument> arguments = Lists.newArrayList();
for (JetExpression argumentExpression : argumentExpressions) {
arguments.add(new ExpressionValueArgument(argumentExpression));
}
return makeCallWithArguments(calleeExpression, arguments);
}
public static Call makeCall(final JetBinaryExpression expression) {
return makeCall(expression.getOperationReference(), Collections.singletonList(expression.getRight()));
}
public static Call makeCall(final JetUnaryExpression expression) {
return makeCallWithArguments(expression.getOperationSign(), Collections.<ValueArgument>emptyList());
}
public static Call makeCall(final JetArrayAccessExpression arrayAccessExpression, final JetExpression rightHandSide) {
List<JetExpression> arguments = Lists.newArrayList(arrayAccessExpression.getIndexExpressions());
arguments.add(rightHandSide);
return makeCall(arrayAccessExpression, arguments);
}
}
@@ -0,0 +1,515 @@
package org.jetbrains.jet.lang.types;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.JetSemanticServices;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.*;
import org.jetbrains.jet.lang.types.inference.ConstraintSystem;
import org.jetbrains.jet.resolve.DescriptorRenderer;
import java.util.*;
import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET;
import static org.jetbrains.jet.lang.types.JetTypeInferrer.NO_EXPECTED_TYPE;
/**
* @author abreslav
*/
public class CallResolver {
private static abstract class ResolutionTask {
private final Collection<FunctionDescriptor> candidates;
private final JetExpression receiver;
private final List<JetTypeProjection> typeArguments;
private final List<? extends ValueArgument> valueArguments;
protected ResolutionTask(
@NotNull Collection<FunctionDescriptor> candidates,
@Nullable JetExpression receiver,
@NotNull List<JetTypeProjection> typeArguments,
@NotNull List<? extends ValueArgument> valueArguments) {
this.candidates = candidates;
this.receiver = receiver;
this.typeArguments = typeArguments;
this.valueArguments = valueArguments;
}
@NotNull
public Collection<FunctionDescriptor> getCandidates() {
return candidates;
}
@Nullable
public JetExpression getReceiver() {
return receiver;
}
@NotNull
public List<JetTypeProjection> getTypeArguments() {
return typeArguments;
}
@NotNull
public List<? extends ValueArgument> getValueArguments() {
return valueArguments;
}
public abstract void bindFunctionReference(@NotNull BindingTrace trace, @NotNull FunctionDescriptor functionDescriptor);
public abstract void reportOverallResolutionError(@NotNull BindingTrace trace, @NotNull String message);
public abstract void reportWrongTypeArguments(@NotNull BindingTrace trace, @NotNull String message);
public abstract void reportWrongValueArguments(@NotNull BindingTrace trace, @NotNull String message);
public abstract void reportUnresolvedFunctionReference(@NotNull BindingTrace trace);
}
private final BindingTrace trace;
private final TypeResolver typeResolver;
private final JetTypeInferrer typeInferrer;
private final JetSemanticServices semanticServices;
private final ClassDescriptorResolver classDescriptorResolver;
public CallResolver(JetSemanticServices semanticServices, BindingTrace trace, JetTypeInferrer typeInferrer) {
this.trace = trace;
this.typeInferrer = typeInferrer;
this.typeResolver = new TypeResolver(semanticServices, trace, true);
this.classDescriptorResolver = semanticServices.getClassDescriptorResolver(trace);
this.semanticServices = semanticServices;
}
@Nullable
public JetType resolveCall(
@NotNull JetScope scope,
@NotNull JetCallElement call,
@NotNull JetType expectedType
) {
FunctionDescriptor functionDescriptor = resolveSimpleCallToFunctionDescriptor(scope, null, call, expectedType);
return functionDescriptor == null ? null : functionDescriptor.getReturnType();
}
@Nullable
public FunctionDescriptor resolveCallWithGivenName(
@NotNull JetScope scope,
@NotNull final Call call,
@NotNull final JetReferenceExpression functionReference,
@NotNull String name,
@Nullable JetExpression receiver,
@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);
}
@Nullable
public FunctionDescriptor resolveSimpleCallToFunctionDescriptor(
@NotNull JetScope scope,
@Nullable JetExpression receiver,
@NotNull final JetCallElement call,
@NotNull JetType expectedType
) {
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();
}
else if (calleeExpression instanceof JetConstructorCalleeExpression) {
JetConstructorCalleeExpression expression = (JetConstructorCalleeExpression) calleeExpression;
functionReference = expression.getConstructorReferenceExpression();
JetType constructedType = typeResolver.resolveType(scope, expression.getTypeReference());
DeclarationDescriptor declarationDescriptor = constructedType.getConstructor().getDeclarationDescriptor();
if (declarationDescriptor instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) declarationDescriptor;
candidates = classDescriptor.getConstructors().getFunctionDescriptors();
}
else {
trace.getErrorHandler().genericError(calleeExpression.getNode(), "Not a class");
return null;
}
}
else {
throw new UnsupportedOperationException("Type argument inference not implemented");
}
return resolveCallToFunctionDescriptor(scope, receiver, call, call.getNode(), expectedType, candidates, functionReference);
}
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()) {
@Override
public void bindFunctionReference(@NotNull BindingTrace trace, @NotNull FunctionDescriptor functionDescriptor) {
trace.record(BindingContext.REFERENCE_TARGET, functionReference, functionDescriptor);
}
@Override
public void reportOverallResolutionError(@NotNull BindingTrace trace, @NotNull String message) {
trace.getErrorHandler().genericError(callNode, message);
}
@Override
public void reportWrongTypeArguments(@NotNull BindingTrace trace, @NotNull String message) {
JetTypeArgumentList typeArgumentList = call.getTypeArgumentList();
if (typeArgumentList != null) {
trace.getErrorHandler().genericError(typeArgumentList.getNode(), message);
}
else {
reportOverallResolutionError(trace, message);
}
}
@Override
public void reportWrongValueArguments(@NotNull BindingTrace trace, @NotNull String message) {
ASTNode node;
JetValueArgumentList valueArgumentList = call.getValueArgumentList();
if (valueArgumentList != null) {
node = valueArgumentList.getNode();
}
else if (!call.getFunctionLiteralArguments().isEmpty()) {
node = call.getFunctionLiteralArguments().get(0).getNode();
}
else {
node = callNode;
}
trace.getErrorHandler().genericError(node, message);
}
@Override
public void reportUnresolvedFunctionReference(@NotNull BindingTrace trace) {
trace.getErrorHandler().unresolvedReference(functionReference);
}
};
return performResolution(scope, expectedType, task);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private boolean mapValueArgumentsToParameters(
@NotNull ResolutionTask task,
@NotNull FunctionDescriptor candidate,
@NotNull BindingTrace temporaryTrace,
@NotNull Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters
) {
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);
}
List<? extends ValueArgument> valueArguments = task.getValueArguments();
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;
if (somePositioned) {
temporaryTrace.getErrorHandler().genericError(valueArgument.getArgumentName().getNode(), "Mixing named and positioned arguments in not allowed");
error = true;
}
else {
ValueParameterDescriptor valueParameterDescriptor = parameterByName.get(valueArgument.getArgumentName().getName());
usedParameters.add(valueParameterDescriptor);
if (valueParameterDescriptor == null) {
temporaryTrace.getErrorHandler().genericError(valueArgument.getArgumentName().getNode(), "Cannot find a parameter with this name");
error = true;
}
else {
temporaryTrace.record(REFERENCE_TARGET, valueArgument.getArgumentName().getReferenceExpression(), valueParameterDescriptor);
argumentsToParameters.put(valueArgument, valueParameterDescriptor);
}
}
}
else {
somePositioned = true;
if (someNamed) {
temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Mixing named and positioned arguments in not allowed");
error = true;
}
else {
if (i < valueParameters.size()) {
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);
usedParameters.add(valueParameterDescriptor);
}
else {
temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Too many arguments");
error = true;
}
}
else {
temporaryTrace.getErrorHandler().genericError(valueArgument.asElement().getNode(), "Too many arguments");
error = true;
}
}
}
}
for (ValueParameterDescriptor valueParameter : valueParameters) {
if (!usedParameters.contains(valueParameter)) {
if (!valueParameter.hasDefaultValue()) {
task.reportWrongValueArguments(temporaryTrace, "No value passed for parameter " + valueParameter.getName());
error = true;
}
}
}
return error;
}
@Nullable
private FunctionDescriptor performResolution(@NotNull JetScope scope, @NotNull JetType expectedType, @NotNull ResolutionTask task) {
Map<FunctionDescriptor, FunctionDescriptor> successfulCandidates = Maps.newHashMap();
Set<FunctionDescriptor> failedCandidates = Sets.newHashSet();
Map<FunctionDescriptor, ConstraintSystem.Solution> solutions = Maps.newHashMap();
Map<FunctionDescriptor, TemporaryBindingTrace> traces = Maps.newHashMap();
for (FunctionDescriptor candidate : task.getCandidates()) {
TemporaryBindingTrace temporaryTrace = new TemporaryBindingTrace(trace.getBindingContext());
traces.put(candidate, temporaryTrace);
JetTypeInferrer.Services temporaryServices = typeInferrer.getServices(temporaryTrace);
task.bindFunctionReference(temporaryTrace, candidate);
Map<ValueArgument, ValueParameterDescriptor> argumentsToParameters = Maps.newHashMap();
boolean error = mapValueArgumentsToParameters(task, 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 (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);
}
}
else {
// Explicit type arguments passed
final List<JetTypeProjection> jetTypeArguments = task.getTypeArguments();
for (JetTypeProjection typeArgument : jetTypeArguments) {
if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) {
temporaryTrace.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, temporaryTrace, true).resolveType(scope, typeReference));
}
}
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();
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;
}
}
if (localError) {
failedCandidates.add(candidate);
}
else {
successfulCandidates.put(candidate, substitutedFunctionDescriptor);
}
}
else {
failedCandidates.add(candidate);
task.reportWrongTypeArguments(temporaryTrace, "Number of type arguments does not match " + DescriptorRenderer.TEXT.render(candidate));
}
}
}
if (successfulCandidates.size() > 0) {
if (successfulCandidates.size() == 1) {
Map.Entry<FunctionDescriptor, FunctionDescriptor> entry = successfulCandidates.entrySet().iterator().next();
FunctionDescriptor functionDescriptor = entry.getKey();
FunctionDescriptor result = entry.getValue();
TemporaryBindingTrace temporaryTrace = traces.get(functionDescriptor);
temporaryTrace.addAllMyDataTo(trace);
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);
}
if (maximallySpecific.size() == 1) {
Map.Entry<FunctionDescriptor, TemporaryBindingTrace> result = maximallySpecific.entrySet().iterator().next();
result.getValue().addAllMyDataTo(trace);
return result.getKey();
}
StringBuilder stringBuilder = new StringBuilder();
for (FunctionDescriptor functionDescriptor : successfulCandidates.keySet()) {
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" ");
}
task.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);
}
else {
StringBuilder stringBuilder = new StringBuilder();
for (FunctionDescriptor functionDescriptor : failedCandidates) {
stringBuilder.append(DescriptorRenderer.TEXT.render(functionDescriptor)).append(" ");
}
task.reportOverallResolutionError(trace, "None of the following functions can be called with the arguments supplied: " + stringBuilder);
}
}
else {
task.reportUnresolvedFunctionReference(trace);
}
return null;
}
private boolean moreSpecific(FunctionDescriptor f, FunctionDescriptor g) {
List<ValueParameterDescriptor> fParams = f.getValueParameters();
List<ValueParameterDescriptor> gParams = g.getValueParameters();
int fSize = fParams.size();
if (fSize != gParams.size()) return false;
for (int i = 0; i < fSize; i++) {
JetType fParamType = fParams.get(i).getOutType();
JetType gParamType = gParams.get(i).getOutType();
if (!JetTypeChecker.INSTANCE.isSubtypeOf(fParamType, gParamType)) {
return false;
}
}
return true;
}
public void checkGenericBoundsInAFunctionCall(List<JetTypeProjection> jetTypeArguments, List<JetType> typeArguments, FunctionDescriptor functionDescriptor) {
Map<TypeConstructor, TypeProjection> context = Maps.newHashMap();
List<TypeParameterDescriptor> typeParameters = functionDescriptor.getOriginal().getTypeParameters();
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
TypeParameterDescriptor typeParameter = typeParameters.get(i);
JetType typeArgument = typeArguments.get(i);
context.put(typeParameter.getTypeConstructor(), new TypeProjection(typeArgument));
}
TypeSubstitutor substitutor = TypeSubstitutor.create(context);
for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) {
TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i);
JetType typeArgument = typeArguments.get(i);
JetTypeReference typeReference = jetTypeArguments.get(i).getTypeReference();
assert typeReference != null;
classDescriptorResolver.checkBounds(typeReference, typeArgument, typeParameterDescriptor, substitutor);
}
}
@NotNull
public OverloadResolutionResult resolveExactSignature(@NotNull JetScope scope, @NotNull JetType receiver, @NotNull String name, @NotNull List<JetType> jetTypes) {
// TODO
return OverloadResolutionResult.nameNotFound();
}
}
File diff suppressed because it is too large Load Diff
@@ -194,12 +194,12 @@ public class ConstraintSystem {
private UnknownType getTypeVariable(TypeParameterDescriptor typeParameterDescriptor) {
UnknownType unknownType = unknownTypes.get(typeParameterDescriptor);
if (unknownType == null) {
throw new IllegalArgumentException("This type parameter is not an unknown in this constraint system");
throw new IllegalArgumentException("This type parameter is not an unknown in this constraint system: " + typeParameterDescriptor);
}
return unknownType;
}
public void addSubtypingConstraint(JetType lower, JetType upper) {
public void addSubtypingConstraint(@NotNull JetType lower, @NotNull JetType upper) {
TypeValue typeValueForLower = getTypeValueFor(lower);
TypeValue typeValueForUpper = getTypeValueFor(upper);
addSubtypingConstraintOnTypeValues(typeValueForLower, typeValueForUpper);