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 @NotNull
List<JetExpression> getFunctionLiteralArguments(); List<JetExpression> getFunctionLiteralArguments();
@NotNull
JetElement asElement();
} }
@@ -45,6 +45,12 @@ public class JetCallExpression extends JetExpression implements JetCall {
return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL); return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL);
} }
@NotNull
@Override
public JetElement asElement() {
return this;
}
@Override @Override
@NotNull @NotNull
public List<JetArgument> getValueArguments() { public List<JetArgument> getValueArguments() {
@@ -37,4 +37,10 @@ public class JetDelegatorToSuperCall extends JetDelegationSpecifier implements J
public List<JetExpression> getFunctionLiteralArguments() { public List<JetExpression> getFunctionLiteralArguments() {
return Collections.emptyList(); return Collections.emptyList();
} }
@NotNull
@Override
public JetElement asElement() {
return this;
}
} }
@@ -39,6 +39,12 @@ public class JetDelegatorToThisCall extends JetDelegationSpecifier implements Je
return Collections.emptyList(); return Collections.emptyList();
} }
@NotNull
@Override
public JetElement asElement() {
return this;
}
public JetReferenceExpression getThisReference() { public JetReferenceExpression getThisReference() {
return findChildByClass(JetThisReferenceExpression.class); return findChildByClass(JetThisReferenceExpression.class);
} }
@@ -45,4 +45,10 @@ public class JetNewExpression extends JetExpression implements JetCall {
return findChildrenByType(JetNodeTypes.FUNCTION_LITERAL); 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.FunctionDescriptor;
import org.jetbrains.jet.lang.descriptors.FunctionGroup; import org.jetbrains.jet.lang.descriptors.FunctionGroup;
import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; 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 * @author abreslav
@@ -21,17 +25,17 @@ public class OverloadResolver {
} }
@NotNull @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 // TODO : extension lookup
JetScope scope = receiverType == null ? outerScope : new ScopeWithReceiver(outerScope, receiverType, typeChecker); JetScope scope = receiverType == null ? outerScope : new ScopeWithReceiver(outerScope, receiverType, typeChecker);
final FunctionGroup functionGroup = scope.getFunctionGroup(name); final FunctionGroup functionGroup = scope.getFunctionGroup(name);
return getOverloadDomain(functionGroup); return getOverloadDomain(receiverType, functionGroup);
} }
@NotNull @NotNull
public OverloadDomain getOverloadDomain(@NotNull final FunctionGroup functionGroup) { public OverloadDomain getOverloadDomain(@Nullable final JetType receiverType, @NotNull final FunctionGroup functionGroup) {
if (functionGroup.isEmpty()) { if (functionGroup.isEmpty()) {
return OverloadDomain.EMPTY; return OverloadDomain.EMPTY;
} }
@@ -56,6 +60,21 @@ public class OverloadResolver {
// ASSERT: type arguments are figured out and substituted by this time!!! // ASSERT: type arguments are figured out and substituted by this time!!!
assert descriptor.getTypeParameters().isEmpty(); 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(); List<ValueParameterDescriptor> parameters = descriptor.getUnsubstitutedValueParameters();
if (parameters.size() >= positionedValueArgumentTypes.size()) { if (parameters.size() >= positionedValueArgumentTypes.size()) {
// possibly, some default values // possibly, some default values
@@ -1,8 +1,6 @@
package org.jetbrains.jet.lang.resolve; package org.jetbrains.jet.lang.resolve;
import com.google.common.base.Function;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import org.jetbrains.jet.lang.types.JetTypeChecker; import org.jetbrains.jet.lang.types.JetTypeChecker;
@@ -27,19 +25,20 @@ public class ScopeWithReceiver extends JetScopeImpl {
public FunctionGroup getFunctionGroup(@NotNull String name) { public FunctionGroup getFunctionGroup(@NotNull String name) {
FunctionGroup functionGroup = receiverType.getMemberScope().getFunctionGroup(name); FunctionGroup functionGroup = receiverType.getMemberScope().getFunctionGroup(name);
if (functionGroup.isEmpty()) { if (functionGroup.isEmpty()) {
return FunctionDescriptorUtil.filteredFunctionGroup(outerScope.getFunctionGroup(name), return outerScope.getFunctionGroup(name);
new Function<FunctionDescriptor, Boolean>() { // return FunctionDescriptorUtil.filteredFunctionGroup(outerScope.getFunctionGroup(name),
@Override // new Function<FunctionDescriptor, Boolean>() {
public Boolean apply(@Nullable FunctionDescriptor functionDescriptor) { // @Override
if (functionDescriptor == null) return false; // public Boolean apply(@Nullable FunctionDescriptor functionDescriptor) {
JetType functionReceiverType = functionDescriptor.getReceiverType(); // if (functionDescriptor == null) return false;
if (functionReceiverType == null) { // JetType functionReceiverType = functionDescriptor.getReceiverType();
return false; // if (functionReceiverType == null) {
} // return false;
// TODO : in case of inferred type arguments, substitute the receiver type first // }
return typeChecker.isSubtypeOf(receiverType, functionReceiverType); // // TODO : in case of inferred type arguments, substitute the receiver type first
} // return typeChecker.isSubtypeOf(receiverType, functionReceiverType);
}); // }
// });
} }
return functionGroup; // TODO return functionGroup; // TODO
} }
@@ -128,6 +128,7 @@ public class JetTypeInferrer {
} }
private OverloadDomain getOverloadDomain( private OverloadDomain getOverloadDomain(
@Nullable final JetType receiverType,
@NotNull final JetScope scope, @NotNull final JetScope scope,
@NotNull JetExpression calleeExpression, @NotNull JetExpression calleeExpression,
@Nullable PsiElement argumentList @Nullable PsiElement argumentList
@@ -150,6 +151,8 @@ public class JetTypeInferrer {
@Override @Override
public void visitQualifiedExpression(JetQualifiedExpression expression) { public void visitQualifiedExpression(JetQualifiedExpression expression) {
trace.getErrorHandler().genericError(expression.getNode(), "Unsupported [JetTypeInferrer]");
// . or ?. // . or ?.
JetType receiverType = getType(scope, expression.getReceiverExpression(), false); JetType receiverType = getType(scope, expression.getReceiverExpression(), false);
checkNullSafety(receiverType, expression.getOperationTokenNode()); checkNullSafety(receiverType, expression.getOperationTokenNode());
@@ -173,7 +176,7 @@ public class JetTypeInferrer {
// a -- create a hierarchical lookup domain for this.a // a -- create a hierarchical lookup domain for this.a
String referencedName = expression.getReferencedName(); String referencedName = expression.getReferencedName();
if (referencedName != null) { if (referencedName != null) {
result[0] = semanticServices.getOverloadResolver().getOverloadDomain(null, scope, referencedName); result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referencedName);
reference[0] = expression; reference[0] = expression;
} }
} }
@@ -539,7 +542,7 @@ public class JetTypeInferrer {
} }
FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped); FunctionGroup constructors = classDescriptor.getConstructors(projectionsStripped);
OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(constructors); OverloadDomain constructorsOverloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(null, constructors);
JetType constructorReturnedType = resolveOverloads( JetType constructorReturnedType = resolveOverloads(
scope, scope,
wrapForTracing(constructorsOverloadDomain, referenceExpression, call.getValueArgumentList(), false), wrapForTracing(constructorsOverloadDomain, referenceExpression, call.getValueArgumentList(), false),
@@ -555,6 +558,9 @@ public class JetTypeInferrer {
if (argumentList != null) { if (argumentList != null) {
trace.getErrorHandler().genericError(argumentList.getNode(), "Cannot find an overload for these arguments"); 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; constructorReturnedType = receiverType;
} }
// If no upcast needed: // If no upcast needed:
@@ -1391,7 +1397,7 @@ public class JetTypeInferrer {
JetScope compositeScope = new ScopeWithReceiver(scope, receiverType, semanticServices.getTypeChecker()); JetScope compositeScope = new ScopeWithReceiver(scope, receiverType, semanticServices.getTypeChecker());
if (selectorExpression instanceof JetCallExpression) { if (selectorExpression instanceof JetCallExpression) {
JetCallExpression callExpression = (JetCallExpression) selectorExpression; 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); return resolveOverloads(scope, callExpression, overloadDomain);
} }
else if (selectorExpression instanceof JetSimpleNameExpression) { else if (selectorExpression instanceof JetSimpleNameExpression) {
@@ -1407,7 +1413,7 @@ public class JetTypeInferrer {
@Override @Override
public void visitCallExpression(JetCallExpression expression) { public void visitCallExpression(JetCallExpression expression) {
JetExpression calleeExpression = expression.getCalleeExpression(); JetExpression calleeExpression = expression.getCalleeExpression();
OverloadDomain overloadDomain = getOverloadDomain(scope, calleeExpression, expression.getValueArgumentList()); OverloadDomain overloadDomain = getOverloadDomain(null, scope, calleeExpression, expression.getValueArgumentList());
result = resolveOverloads(scope, expression, overloadDomain); result = resolveOverloads(scope, expression, overloadDomain);
} }
@@ -37,6 +37,11 @@ public class DescriptorRenderer {
public String renderKeyword(String keyword) { public String renderKeyword(String keyword) {
return "<b>" + keyword + "</b>"; 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> rootVisitor = new RenderDeclarationDescriptorVisitor();
private final DeclarationDescriptorVisitor<Void, StringBuilder> subVisitor = new RenderDeclarationDescriptorVisitor() { private final DeclarationDescriptorVisitor<Void, StringBuilder> subVisitor = new RenderDeclarationDescriptorVisitor() {
@Override
protected void renderName(DeclarationDescriptor descriptor, StringBuilder stringBuilder) {
stringBuilder.append(descriptor.getName());
}
@Override @Override
public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, StringBuilder builder) { public Void visitTypeParameterDescriptor(TypeParameterDescriptor descriptor, StringBuilder builder) {
renderTypeParameter(descriptor, builder); renderTypeParameter(descriptor, builder);
@@ -80,10 +80,30 @@ public class DescriptorRenderer {
if (declarationDescriptor == null) return lt() + "null>"; if (declarationDescriptor == null) return lt() + "null>";
StringBuilder stringBuilder = new StringBuilder(); StringBuilder stringBuilder = new StringBuilder();
declarationDescriptor.accept(rootVisitor, stringBuilder); declarationDescriptor.accept(rootVisitor, stringBuilder);
stringBuilder.append(" " + renderMessage("defined in") + " ");
final DeclarationDescriptor containingDeclaration = declarationDescriptor.getContainingDeclaration();
if (containingDeclaration != null) {
renderFullyQualifiedName(containingDeclaration, stringBuilder);
}
return stringBuilder.toString(); 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> { private class RenderDeclarationDescriptorVisitor extends DeclarationDescriptorVisitor<Void, StringBuilder> {
@Override @Override
public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) { public Void visitValueParameterDescriptor(ValueParameterDescriptor descriptor, StringBuilder builder) {
builder.append(renderKeyword("value-parameter")).append(" "); builder.append(renderKeyword("value-parameter")).append(" ");
@@ -217,11 +237,6 @@ public class DescriptorRenderer {
} }
protected void renderName(DeclarationDescriptor descriptor, StringBuilder stringBuilder) { protected void renderName(DeclarationDescriptor descriptor, StringBuilder stringBuilder) {
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
if (containingDeclaration != null) {
renderName(containingDeclaration, stringBuilder);
stringBuilder.append("::");
}
stringBuilder.append(escape(descriptor.getName())); stringBuilder.append(escape(descriptor.getName()));
} }
@@ -1,2 +1,38 @@
fun Int?.optint() : Unit 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>(1) : Set<Int>?
Collections.singleton<Int><error>(1.0)</error> 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 `+`plus 1
y `+1`+ 1.0 y `+1`+ 1.0
this?.minus<T>(this) this?.`-`minus<T>(this)
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~fun `A`A.plus(a : Any) {
1.`foo`foo() 1.`foo`foo()
true.`!`foo() true.`foo`foo()
1 1
} }