JET-49 Resolve extension functions with generic receivers
+ Error report fixed for 'new java.util.List<Int>'
This commit is contained in:
@@ -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
|
||||||
@@ -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>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user