JET-49 Resolve extension functions with generic receivers

+
Error report fixed for 'new java.util.List<Int>'
This commit is contained in:
Andrey Breslav
2011-05-24 19:07:53 +04:00
parent 7e5021d746
commit 1d948b0153
12 changed files with 141 additions and 37 deletions
@@ -17,4 +17,7 @@ public interface JetCall {
@NotNull
List<JetExpression> getFunctionLiteralArguments();
@NotNull
JetElement asElement();
}
@@ -45,6 +45,12 @@ public class JetCallExpression extends JetExpression implements JetCall {
return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL);
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
@Override
@NotNull
public List<JetArgument> getValueArguments() {
@@ -37,4 +37,10 @@ public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements J
public List<JetExpression> getFunctionLiteralArguments() {
return Collections.emptyList();
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
}
@@ -39,6 +39,12 @@ public class JetDelegatorToThisCall extends JetDelegationSpecifier implements Je
return Collections.emptyList();
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
public JetReferenceExpression getThisReference() {
return findChildByClass(JetThisReferenceExpression.class);
}
@@ -45,4 +45,10 @@ public class JetNewExpression extends JetExpression implements JetCall {
return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL);
}
@NotNull
@Override
public JetElement asElement() {
return this;
}
}
@@ -5,9 +5,13 @@ 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.*;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
/**
* @author abreslav
@@ -21,17 +25,17 @@ public class OverloadResolver {
}
@NotNull
public OverloadDomain getOverloadDomain(JetType receiverType, @NotNull JetScope outerScope, @NotNull String name) {
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(functionGroup);
return getOverloadDomain(receiverType, functionGroup);
}
@NotNull
public OverloadDomain getOverloadDomain(@NotNull final FunctionGroup functionGroup) {
public OverloadDomain getOverloadDomain(@Nullable final JetType receiverType, @NotNull final FunctionGroup functionGroup) {
if (functionGroup.isEmpty()) {
return OverloadDomain.EMPTY;
}
@@ -56,6 +60,21 @@ public class OverloadResolver {
// 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
final JetType functionReceiverType = descriptor.getReceiverType();
// final ClassDescriptor containingDeclaration = (ClassDescriptor) descriptor.getContainingDeclaration();
// assert functionReceiverType != null || containingDeclaration != null &&
// containingDeclaration.getTypeConstructor().equals(receiverType.getConstructor());
if (functionReceiverType != null && !typeChecker.isSubtypeOf(receiverType, functionReceiverType)) {
continue;
}
}
else if (descriptor.getReceiverType() != null) {
continue;
}
List<ValueParameterDescriptor> parameters = descriptor.getUnsubstitutedValueParameters();
if (parameters.size() >= positionedValueArgumentTypes.size()) {
// possibly, some default values
@@ -1,8 +1,6 @@
package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker;
@@ -27,19 +25,20 @@ public class ScopeWithReceiver extends JetScopeImpl {
public FunctionGroup getFunctionGroup(@NotNull String name) {
FunctionGroup functionGroup = receiverType.getMemberScope().getFunctionGroup(name);
if (functionGroup.isEmpty()) {
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.isSubtypeOf(receiverType, functionReceiverType);
}
});
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.isSubtypeOf(receiverType, functionReceiverType);
// }
// });
}
return functionGroup; // TODO
}
@@ -128,6 +128,7 @@ public class JetTypeInferrer {
}
private OverloadDomain getOverloadDomain(
@Nullable final JetType receiverType,
@NotNull final JetScope scope,
@NotNull JetExpression calleeExpression,
@Nullable PsiElement argumentList
@@ -150,6 +151,8 @@ public class JetTypeInferrer {
@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());
@@ -173,7 +176,7 @@ public class JetTypeInferrer {
// a -- create a hierarchical lookup domain for this.a
String referencedName = expression.getReferencedName();
if (referencedName != null) {
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(null, scope, referencedName);
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referencedName);
reference[0] = expression;
}
}
@@ -539,7 +542,7 @@ public class JetTypeInferrer {
}
FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped);
OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors);
OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(null, constructors);
JetType constructorReturnedType = resolveOverloads(
scope,
wrapForTracing(constructorsOverloadDomain, referenceExpression, call.getValueArgumentList(), false),
@@ -555,6 +558,9 @@ public class JetTypeInferrer {
if (argumentList != null) {
trace.getErrorHandler().genericError(argumentList.getNode(), "Cannot find an overload for these arguments");
}
else {
trace.getErrorHandler().genericError(call.asElement().getNode(), "Cannot find an overload for these arguments");
}
constructorReturnedType = receiverType;
}
// If no upcast needed:
@@ -1391,7 +1397,7 @@ public class JetTypeInferrer {
JetScope compositeScope = new ScopeWithReceiver(scope, receiverType, semanticServices.getTypeChecker());
if (selectorExpression instanceof JetCallExpression) {
JetCallExpression callExpression = (JetCallExpression) selectorExpression;
OverloadDomain overloadDomain = getOverloadDomain(compositeScope, callExpression.getCalleeExpression(), callExpression.getValueArgumentList());
OverloadDomain overloadDomain = getOverloadDomain(receiverType, compositeScope, callExpression.getCalleeExpression(), callExpression.getValueArgumentList());
return resolveOverloads(scope, callExpression, overloadDomain);
}
else if (selectorExpression instanceof JetSimpleNameExpression) {
@@ -1407,7 +1413,7 @@ public class JetTypeInferrer {
@Override
public void visitCallExpression(JetCallExpression expression) {
JetExpression calleeExpression = expression.getCalleeExpression();
OverloadDomain overloadDomain = getOverloadDomain(scope, calleeExpression, expression.getValueArgumentList());
OverloadDomain overloadDomain = getOverloadDomain(null, scope, calleeExpression, expression.getValueArgumentList());
result = resolveOverloads(scope, expression, overloadDomain);
}
@@ -37,6 +37,11 @@ public class DescriptorRenderer {
public String renderKeyword(String keyword) {
return "<b>" + keyword + "</b>";
}
@Override
public String renderMessage(String s) {
return "<i>" + s + "</i>";
}
};
@@ -45,11 +50,6 @@ public class DescriptorRenderer {
private final DeclarationDescriptorVisitor<Void, StringBuilder> rootVisitor = new RenderDeclarationDescriptorVisitor();
private final DeclarationDescriptorVisitor<Void, StringBuilder> subVisitor = new RenderDeclarationDescriptorVisitor() {
@Override
protected void renderName(DeclarationDescriptor descriptor, StringBuilder stringBuilder) {
stringBuilder.append(descriptor.getName());
}
@Override
public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, StringBuilder builder) {
renderTypeParameter(descriptor, builder);
@@ -80,10 +80,30 @@ public class DescriptorRenderer {
if (declarationDescriptor == null) return lt() + "null>";
StringBuilder stringBuilder = new StringBuilder();
declarationDescriptor.accept(rootVisitor, stringBuilder);
stringBuilder.append(" " + renderMessage("defined in") + " ");
final DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration();
if (containingDeclaration != null) {
renderFullyQualifiedName(containingDeclaration, stringBuilder);
}
return stringBuilder.toString();
}
public String renderMessage(String s) {
return s;
}
private void renderFullyQualifiedName(DeclarationDescriptor descriptor, StringBuilder stringBuilder) {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration != null) {
renderFullyQualifiedName(containingDeclaration, stringBuilder);
stringBuilder.append(".");
}
stringBuilder.append(escape(descriptor.getName()));
}
private class RenderDeclarationDescriptorVisitor extends DeclarationDescriptorVisitor<Void, StringBuilder> {
@Override
public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) {
builder.append(renderKeyword("value-parameter")).append(" ");
@@ -217,11 +237,6 @@ public class DescriptorRenderer {
}
protected void renderName(DeclarationDescriptor descriptor, StringBuilder stringBuilder) {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration != null) {
renderName(containingDeclaration, stringBuilder);
stringBuilder.append("::");
}
stringBuilder.append(escape(descriptor.getName()));
}
+37 -1
View File
@@ -1,2 +1,38 @@
fun Int?.optint() : Unit
val Int?.optval : Unit
val Int?.optval : Unit
fun <T, E> T.foo(x : E, y : A) : T {
y.plus(1)
y plus 1
y + 1.0
this?.minus<T>(this)
this
}
class A
fun A.plus(a : Any) {
1.foo()
true.foo<error>()</error>
1
}
fun A.plus(a : Int) {
1
}
fun <T> T.minus(t : T) : Int = 1
fun test() {
val y = 1.abs
}
val Int.abs : Int
get() = if (this > 0) this else -this;
val <T> T.foo : T
fun Int.foo() = this
+2
View File
@@ -20,4 +20,6 @@ fun test(l : java.util.List<Int>) {
Collections.singleton<Int>(1) : Set<Int>?
Collections.singleton<Int><error>(1.0)</error>
<error>new List<Int></error>
}
+2 -2
View File
@@ -3,7 +3,7 @@ fun <~T~T, ~E~E> `T`T.foo(x : `E`E, y : `A`A) : `T`T {
y `+`plus 1
y `+1`+ 1.0
this?.minus<T>(this)
this?.`-`minus<T>(this)
this
}
@@ -13,7 +13,7 @@ fun <~T~T, ~E~E> `T`T.foo(x : `E`E, y : `A`A) : `T`T {
~+1~fun `A`A.plus(a : Any) {
1.`foo`foo()
true.`!`foo()
true.`foo`foo()
1
}