Working on error messages for overload resolution

This commit is contained in:
Andrey Breslav
2011-03-21 20:12:53 +03:00
parent fe84695b85
commit 7601e71571
16 changed files with 216 additions and 84 deletions
+1
View File
@@ -12,6 +12,7 @@ Foo<Bar<X>, T, Object> // user type
type type
: attributes typeDescriptor : attributes typeDescriptor
// IF YOU CHANGE THIS, please, update TYPE_FIRST in JetParsing
typeDescriptor typeDescriptor
: selfType : selfType
: functionType : functionType
@@ -31,7 +31,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
COLON COLON
); );
private static final TokenSet EXPRESSION_FIRST = TokenSet.orSet(TokenSet.create( /*package*/ static final TokenSet EXPRESSION_FIRST = TokenSet.orSet(TokenSet.create(
// Prefix // Prefix
MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL, LBRACKET, LABEL_IDENTIFIER, AT, ATAT, MINUS, PLUS, MINUSMINUS, PLUSPLUS, EXCL, LBRACKET, LABEL_IDENTIFIER, AT, ATAT,
// Atomic // Atomic
@@ -82,7 +82,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
NAMESPACE_KEYWORD // for absolute qualified names NAMESPACE_KEYWORD // for absolute qualified names
), MODIFIER_KEYWORDS); ), MODIFIER_KEYWORDS);
private static final TokenSet EXPRESSION_FOLLOW = TokenSet.create( /*package*/ static final TokenSet EXPRESSION_FOLLOW = TokenSet.create(
SEMICOLON, DOUBLE_ARROW, COMMA, RBRACE, RPAR, RBRACKET SEMICOLON, DOUBLE_ARROW, COMMA, RBRACE, RPAR, RBRACKET
); );
@@ -533,7 +533,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
} }
else if (!parseLiteralConstant()) { else if (!parseLiteralConstant()) {
// TODO: better recovery if FIRST(expression) did not match // TODO: better recovery if FIRST(expression) did not match
errorAndAdvance("Expecting an expression"); errorWithRecovery("Expecting an expression", EXPRESSION_FOLLOW);
} }
} }
@@ -1494,7 +1494,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
PsiBuilder.Marker list = mark(); PsiBuilder.Marker list = mark();
myBuilder.disableNewlines(); myBuilder.disableNewlines();
expect(LPAR, "Expecting an argument list", TokenSet.create(RPAR)); expect(LPAR, "Expecting an argument list", EXPRESSION_FOLLOW);
if (!at(RPAR)) { if (!at(RPAR)) {
while (true) { while (true) {
@@ -1509,7 +1509,7 @@ public class JetExpressionParsing extends AbstractJetParsing {
} }
} }
expect(RPAR, "Expecting ')'"); expect(RPAR, "Expecting ')'", EXPRESSION_FOLLOW);
myBuilder.restoreNewlinesState(); myBuilder.restoreNewlinesState();
list.done(VALUE_ARGUMENT_LIST); list.done(VALUE_ARGUMENT_LIST);
@@ -37,7 +37,7 @@ public class JetParsing extends AbstractJetParsing {
private static final TokenSet TYPE_PARAMETER_GT_RECOVERY_SET = TokenSet.create(WHERE_KEYWORD, WRAPS_KEYWORD, LPAR, COLON, LBRACE, GT); private static final TokenSet TYPE_PARAMETER_GT_RECOVERY_SET = TokenSet.create(WHERE_KEYWORD, WRAPS_KEYWORD, LPAR, COLON, LBRACE, GT);
private static final TokenSet PARAMETER_NAME_RECOVERY_SET = TokenSet.create(COLON, EQ, COMMA, RPAR); private static final TokenSet PARAMETER_NAME_RECOVERY_SET = TokenSet.create(COLON, EQ, COMMA, RPAR);
private static final TokenSet NAMESPACE_NAME_RECOVERY_SET = TokenSet.create(DOT, EOL_OR_SEMICOLON); private static final TokenSet NAMESPACE_NAME_RECOVERY_SET = TokenSet.create(DOT, EOL_OR_SEMICOLON);
/*package*/ static final TokenSet TYPE_REF_FIRST = TokenSet.create(LBRACKET, IDENTIFIER, LBRACE, LPAR); /*package*/ static final TokenSet TYPE_REF_FIRST = TokenSet.create(LBRACKET, IDENTIFIER, LBRACE, LPAR, CAPITALIZED_THIS_KEYWORD);
public static JetParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) { public static JetParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) {
builder.setDebugMode(true); builder.setDebugMode(true);
@@ -835,10 +835,17 @@ public class JetParsing extends AbstractJetParsing {
advance(); // FUN_KEYWORD advance(); // FUN_KEYWORD
// Recovery for the case of class A { fun| }
if (at(RBRACE)) {
error("Function body expected");
return FUN;
}
if (at(LT)) { if (at(LT)) {
parseTypeParameterList(TokenSet.create(LBRACKET, LBRACE, LPAR)); parseTypeParameterList(TokenSet.create(LBRACKET, LBRACE, LPAR));
} }
int lastDot = findLastBefore(TokenSet.create(DOT), TokenSet.create(LPAR), true); int lastDot = findLastBefore(TokenSet.create(DOT), TokenSet.create(LPAR), true);
if (lastDot == -1) { // There's no explicit receiver type specified if (lastDot == -1) { // There's no explicit receiver type specified
@@ -1246,7 +1253,7 @@ public class JetParsing extends AbstractJetParsing {
PsiBuilder.Marker reference = mark(); PsiBuilder.Marker reference = mark();
while (true) { while (true) {
expect(IDENTIFIER, "Type name expected", TokenSet.create(LT)); expect(IDENTIFIER, "Type name expected", TokenSet.orSet(JetExpressionParsing.EXPRESSION_FIRST, JetExpressionParsing.EXPRESSION_FOLLOW));
reference.done(REFERENCE_EXPRESSION); reference.done(REFERENCE_EXPRESSION);
parseTypeArgumentList(); parseTypeArgumentList();
@@ -13,7 +13,7 @@ public class JetArgument extends JetElement {
super(node); super(node);
} }
public void accept(JetVisitor visitor) { public void accept(@NotNull JetVisitor visitor) {
visitor.visitArgument(this); visitor.visitArgument(this);
} }
@@ -25,6 +25,9 @@ public class JetArgument extends JetElement {
@Nullable @Nullable
public String getArgumentName() { public String getArgumentName() {
ASTNode firstChildNode = getNode().getFirstChildNode(); ASTNode firstChildNode = getNode().getFirstChildNode();
if (firstChildNode == null) {
return null;
}
return firstChildNode.getElementType() == JetTokens.IDENTIFIER ? firstChildNode.getText() : null; return firstChildNode.getElementType() == JetTokens.IDENTIFIER ? firstChildNode.getText() : null;
} }
@@ -2,6 +2,7 @@ package org.jetbrains.jet.lang.psi;
import com.intellij.lang.ASTNode; import com.intellij.lang.ASTNode;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.JetNodeTypes; import org.jetbrains.jet.JetNodeTypes;
import java.util.ArrayList; import java.util.ArrayList;
@@ -25,6 +26,7 @@ public class JetTypeReference extends JetElement {
return findChildrenByType(JetNodeTypes.ATTRIBUTE_ANNOTATION); return findChildrenByType(JetNodeTypes.ATTRIBUTE_ANNOTATION);
} }
@Nullable
public JetTypeElement getTypeElement() { public JetTypeElement getTypeElement() {
return findChildByClass(JetTypeElement.class); return findChildByClass(JetTypeElement.class);
} }
@@ -329,7 +329,7 @@ public class ClassDescriptorResolver {
} }
@Nullable @Nullable
private ConstructorDescriptor resolvePrimaryConstructor(@NotNull JetScope scope, @NotNull ClassDescriptor classDescriptor, @NotNull JetClass classElement) { public ConstructorDescriptor resolvePrimaryConstructor(@NotNull JetScope scope, @NotNull ClassDescriptor classDescriptor, @NotNull JetClass classElement) {
JetParameterList primaryConstructorParameterList = classElement.getPrimaryConstructorParameterList(); JetParameterList primaryConstructorParameterList = classElement.getPrimaryConstructorParameterList();
if (primaryConstructorParameterList != null) { if (primaryConstructorParameterList != null) {
return createConstructorDescriptor( return createConstructorDescriptor(
@@ -13,14 +13,12 @@ import java.util.Map;
public class MutableClassDescriptor extends MutableDeclarationDescriptor implements ClassDescriptor { public class MutableClassDescriptor extends MutableDeclarationDescriptor implements ClassDescriptor {
private final WritableScope unsubstitutedMemberScope; private final WritableScope unsubstitutedMemberScope;
private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>"); private final WritableFunctionGroup constructors = new WritableFunctionGroup("<init>");
private final JetSemanticServices semanticServices;
private TypeConstructor typeConstructor; private TypeConstructor typeConstructor;
public MutableClassDescriptor(@NotNull JetSemanticServices semanticServices, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope outerScope) { public MutableClassDescriptor(@NotNull JetSemanticServices semanticServices, @NotNull DeclarationDescriptor containingDeclaration, @NotNull JetScope outerScope) {
super(containingDeclaration); super(containingDeclaration);
this.unsubstitutedMemberScope = semanticServices.createWritableScope(outerScope, this); this.unsubstitutedMemberScope = semanticServices.createWritableScope(outerScope, this);
this.semanticServices = semanticServices;
} }
@NotNull @NotNull
@@ -2,7 +2,6 @@ package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.jet.lang.types.FunctionDescriptor;
import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.JetType;
import java.util.List; import java.util.List;
@@ -12,17 +11,18 @@ import java.util.Map;
* @author abreslav * @author abreslav
*/ */
public interface OverloadDomain { public interface OverloadDomain {
OverloadDomain EMPTY = new OverloadDomain() { OverloadDomain EMPTY = new OverloadDomain() {
@Nullable @NotNull
@Override @Override
public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) { public OverloadResolutionResult getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) {
return null; return OverloadResolutionResult.nameNotFound();
} }
@Nullable @NotNull
@Override @Override
public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) { public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
return null; return OverloadResolutionResult.nameNotFound();
} }
@Override @Override
@@ -32,24 +32,19 @@ public interface OverloadDomain {
}; };
/** /**
* @param typeArguments * @return A function descriptor with NO type parameters (they are already substituted) wrapped together with a result code
* @param valueArgumentTypes
* @param functionLiteralArgumentType
* @return A function descriptor with NO type parameters (they are already substituted), or null
*/ */
@Nullable @NotNull
FunctionDescriptor getFunctionDescriptorForNamedArguments( OverloadResolutionResult getFunctionDescriptorForNamedArguments(
@NotNull List<JetType> typeArguments, @NotNull List<JetType> typeArguments,
@NotNull Map<String, JetType> valueArgumentTypes, @NotNull Map<String, JetType> valueArgumentTypes,
@Nullable JetType functionLiteralArgumentType); @Nullable JetType functionLiteralArgumentType);
/** /**
* @param typeArguments * @return A function descriptor with NO type parameters (they are already substituted) wrapped together with a result code
* @param positionedValueArgumentTypes
* @return A function descriptor with NO type parameters (they are already substituted), or null
*/ */
@Nullable @NotNull
FunctionDescriptor getFunctionDescriptorForPositionedArguments( OverloadResolutionResult getFunctionDescriptorForPositionedArguments(
@NotNull List<JetType> typeArguments, @NotNull List<JetType> typeArguments,
@NotNull List<JetType> positionedValueArgumentTypes); @NotNull List<JetType> positionedValueArgumentTypes);
@@ -0,0 +1,75 @@
package org.jetbrains.jet.lang.resolve;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.lang.types.FunctionDescriptor;
import java.util.Collection;
/**
* @author abreslav
*/
public class OverloadResolutionResult {
public enum Code {
SUCCESS(true),
NAME_NOT_FOUND(false),
SINGLE_FUNCTION_ARGUMENT_MISMATCH(false),
AMBIGUITY(false);
private final boolean success;
Code(boolean success) {
this.success = success;
}
boolean isSuccess() {
return success;
}
}
public static OverloadResolutionResult success(@NotNull FunctionDescriptor functionDescriptor) {
return new OverloadResolutionResult(Code.SUCCESS, functionDescriptor);
}
public static OverloadResolutionResult nameNotFound() {
return new OverloadResolutionResult(Code.NAME_NOT_FOUND, null);
}
public static OverloadResolutionResult singleFunctionArgumentMismatch(FunctionDescriptor functionDescriptor) {
return new OverloadResolutionResult(Code.SINGLE_FUNCTION_ARGUMENT_MISMATCH, functionDescriptor);
}
public static OverloadResolutionResult ambiguity(Collection<FunctionDescriptor> functionDescriptors) {
return new OverloadResolutionResult(Code.AMBIGUITY, null); // TODO
}
private final FunctionDescriptor functionDescriptor;
private final Code resultCode;
public OverloadResolutionResult(@NotNull Code resultCode, FunctionDescriptor functionDescriptor) {
this.functionDescriptor = functionDescriptor;
this.resultCode = resultCode;
}
@NotNull // This is done on purpose, despite the fact that errors may not carry a descriptor:
// one should not call this method at all in that case
public FunctionDescriptor getFunctionDescriptor() {
assert functionDescriptor != null;
return functionDescriptor;
}
@NotNull
public Code getResultCode() {
return resultCode;
}
public boolean isSuccess() {
return resultCode.isSuccess();
}
public boolean singleFunction() {
return isSuccess() || resultCode == Code.SINGLE_FUNCTION_ARGUMENT_MISMATCH;
}
}
@@ -34,11 +34,12 @@ public class OverloadResolver {
} }
return new OverloadDomain() { return new OverloadDomain() {
@NotNull
@Override @Override
public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull final List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) { public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull final List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
Collection<FunctionDescriptor> possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes); Collection<FunctionDescriptor> possiblyApplicableFunctions = functionGroup.getPossiblyApplicableFunctions(typeArguments, positionedValueArgumentTypes);
if (possiblyApplicableFunctions.isEmpty()) { if (possiblyApplicableFunctions.isEmpty()) {
return null; return OverloadResolutionResult.nameNotFound(); // TODO : it may be found, only the number of params did not match
} }
List<FunctionDescriptor> applicable = new ArrayList<FunctionDescriptor>(); List<FunctionDescriptor> applicable = new ArrayList<FunctionDescriptor>();
@@ -84,9 +85,9 @@ public class OverloadResolver {
} }
if (applicable.size() == 0) { if (applicable.size() == 0) {
return null; return OverloadResolutionResult.nameNotFound();
} else if (applicable.size() == 1) { } else if (applicable.size() == 1) {
return applicable.get(0); return OverloadResolutionResult.success(applicable.get(0));
} else { } else {
// TODO : varargs // TODO : varargs
@@ -100,10 +101,10 @@ public class OverloadResolver {
maximallySpecific.add(me); maximallySpecific.add(me);
} }
if (maximallySpecific.isEmpty()) { if (maximallySpecific.isEmpty()) {
return null; return OverloadResolutionResult.ambiguity(applicable);
} }
if (maximallySpecific.size() == 1) { if (maximallySpecific.size() == 1) {
return maximallySpecific.get(0); return OverloadResolutionResult.success(maximallySpecific.get(0));
} }
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@@ -114,8 +115,9 @@ public class OverloadResolver {
return functionGroup.isEmpty(); return functionGroup.isEmpty();
} }
@NotNull
@Override @Override
public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) { public OverloadResolutionResult getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(); // TODO
} }
}; };
@@ -36,7 +36,7 @@ public class TopDownAnalyzer {
trace.setToplevelScope(toplevelScope); // TODO : this is a hack trace.setToplevelScope(toplevelScope); // TODO : this is a hack
collectTypeDeclarators(toplevelScope, declarations); collectTypeDeclarators(toplevelScope, declarations);
resolveTypeDeclarations(); resolveTypeDeclarations();
collectBehaviorDeclarators(toplevelScope, declarations); processBehaviorDeclarators(toplevelScope, declarations);
resolveBehaviorDeclarationBodies(); resolveBehaviorDeclarationBodies();
} }
@@ -136,24 +136,26 @@ public class TopDownAnalyzer {
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
private void collectBehaviorDeclarators(@NotNull final WritableScope declaringScope, List<JetDeclaration> declarations) { private void processBehaviorDeclarators(@NotNull final WritableScope declaringScope, List<JetDeclaration> declarations) {
for (JetDeclaration declaration : declarations) { for (JetDeclaration declaration : declarations) {
declaration.accept(new JetVisitor() { declaration.accept(new JetVisitor() {
@Override @Override
public void visitClass(JetClass klass) { public void visitClass(JetClass klass) {
collectBehaviorDeclarators(classes.get(klass).getUnsubstitutedMemberScope(), klass.getDeclarations()); MutableClassDescriptor mutableClassDescriptor = classes.get(klass);
processBehaviorDeclarators(mutableClassDescriptor.getUnsubstitutedMemberScope(), klass.getDeclarations());
processPrimaryConstructor(mutableClassDescriptor, klass);
} }
@Override @Override
public void visitClassObject(JetClassObject classObject) { public void visitClassObject(JetClassObject classObject) {
processClassObject(classObject); processClassObject(classObject);
collectBehaviorDeclarators(declaringScope, classObject.getObject().getDeclarations()); processBehaviorDeclarators(declaringScope, classObject.getObject().getDeclarations());
} }
@Override @Override
public void visitNamespace(JetNamespace namespace) { public void visitNamespace(JetNamespace namespace) {
WritableScope namespaceScope = namespaceScopes.get(namespace); WritableScope namespaceScope = namespaceScopes.get(namespace);
collectBehaviorDeclarators(namespaceScope, namespace.getDeclarations()); processBehaviorDeclarators(namespaceScope, namespace.getDeclarations());
} }
@Override @Override
@@ -179,13 +181,20 @@ public class TopDownAnalyzer {
@Override @Override
public void visitDeclaration(JetDeclaration dcl) { public void visitDeclaration(JetDeclaration dcl) {
throw new UnsupportedOperationException(); // TODO throw new UnsupportedOperationException(dcl.getText() + " " + dcl.getClass().getCanonicalName()); // TODO
} }
}); });
} }
} }
private void processPrimaryConstructor(MutableClassDescriptor classDescriptor, JetClass klass) {
ConstructorDescriptor constructorDescriptor = classDescriptorResolver.resolvePrimaryConstructor(classDescriptor.getUnsubstitutedMemberScope(), classDescriptor, klass);
if (constructorDescriptor != null) {
classDescriptor.addConstructor(constructorDescriptor);
}
}
private void processConstructor(MutableClassDescriptor classDescriptor, JetConstructor constructor) { private void processConstructor(MutableClassDescriptor classDescriptor, JetConstructor constructor) {
classDescriptor.addConstructor(classDescriptorResolver.resolveConstructorDescriptor(classDescriptor.getUnsubstitutedMemberScope(), classDescriptor, constructor, false)); classDescriptor.addConstructor(classDescriptorResolver.resolveConstructorDescriptor(classDescriptor.getUnsubstitutedMemberScope(), classDescriptor, constructor, false));
} }
@@ -41,9 +41,14 @@ public class TypeResolver {
typeElement.accept(new JetVisitor() { typeElement.accept(new JetVisitor() {
@Override @Override
public void visitUserType(JetUserType type) { public void visitUserType(JetUserType type) {
JetSimpleNameExpression referenceExpression = type.getReferenceExpression();
String referencedName = type.getReferencedName();
if (referenceExpression == null || referencedName == null) {
return;
}
ClassDescriptor classDescriptor = resolveClass(scope, type); ClassDescriptor classDescriptor = resolveClass(scope, type);
if (classDescriptor != null) { if (classDescriptor != null) {
trace.recordReferenceResolution(type.getReferenceExpression(), classDescriptor); trace.recordReferenceResolution(referenceExpression, classDescriptor);
TypeConstructor typeConstructor = classDescriptor.getTypeConstructor(); TypeConstructor typeConstructor = classDescriptor.getTypeConstructor();
List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments()); List<TypeProjection> arguments = resolveTypeProjections(scope, typeConstructor, type.getTypeArguments());
if (arguments.size() != typeConstructor.getParameters().size()) { if (arguments.size() != typeConstructor.getParameters().size()) {
@@ -59,9 +64,9 @@ public class TypeResolver {
} }
} }
else if (type.getTypeArguments().isEmpty()) { else if (type.getTypeArguments().isEmpty()) {
TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameter(type.getReferencedName()); TypeParameterDescriptor typeParameterDescriptor = scope.getTypeParameter(referencedName);
if (typeParameterDescriptor != null) { if (typeParameterDescriptor != null) {
trace.recordReferenceResolution(type.getReferenceExpression(), typeParameterDescriptor); trace.recordReferenceResolution(referenceExpression, typeParameterDescriptor);
result[0] = new JetTypeImpl( result[0] = new JetTypeImpl(
attributes, attributes,
typeParameterDescriptor.getTypeConstructor(), typeParameterDescriptor.getTypeConstructor(),
@@ -71,11 +76,11 @@ public class TypeResolver {
JetStandardClasses.STUB JetStandardClasses.STUB
); );
} else { } else {
semanticServices.getErrorHandler().unresolvedReference(type.getReferenceExpression()); semanticServices.getErrorHandler().unresolvedReference(referenceExpression);
} }
} }
else { else {
semanticServices.getErrorHandler().unresolvedReference(type.getReferenceExpression()); semanticServices.getErrorHandler().unresolvedReference(referenceExpression);
} }
} }
@@ -171,14 +176,21 @@ public class TypeResolver {
@Nullable @Nullable
public ClassDescriptor resolveClass(JetScope scope, JetUserType userType) { public ClassDescriptor resolveClass(JetScope scope, JetUserType userType) {
JetSimpleNameExpression expression = userType.getReferenceExpression(); JetSimpleNameExpression expression = userType.getReferenceExpression();
if (expression == null) {
return null;
}
String referencedName = expression.getReferencedName();
if (referencedName == null) {
return null;
}
if (userType.isAbsoluteInRootNamespace()) { if (userType.isAbsoluteInRootNamespace()) {
return JetModuleUtil.getRootNamespaceScope(userType).getClass(expression.getReferencedName()); return JetModuleUtil.getRootNamespaceScope(userType).getClass(referencedName);
} }
JetUserType qualifier = userType.getQualifier(); JetUserType qualifier = userType.getQualifier();
if (qualifier != null) { if (qualifier != null) {
scope = resolveClassLookupScope(scope, qualifier); scope = resolveClassLookupScope(scope, qualifier);
} }
return scope.getClass(expression.getReferencedName()); return scope.getClass(referencedName);
} }
private JetScope resolveClassLookupScope(JetScope scope, JetUserType userType) { private JetScope resolveClassLookupScope(JetScope scope, JetUserType userType) {
@@ -18,6 +18,7 @@ public class WritableFunctionGroup implements FunctionGroup {
this.name = name; this.name = name;
} }
@NotNull
@Override @Override
public String getName() { public String getName() {
return name; return name;
@@ -51,7 +52,8 @@ public class WritableFunctionGroup implements FunctionGroup {
for (FunctionDescriptor functionDescriptor : getFunctionDescriptors()) { for (FunctionDescriptor functionDescriptor : getFunctionDescriptors()) {
// TODO : type argument inference breaks this logic // TODO : type argument inference breaks this logic
if (functionDescriptor.getTypeParameters().size() == typeArgCount) { if (functionDescriptor.getTypeParameters().size() == typeArgCount) {
if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount && valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) { if (FunctionDescriptorUtil.getMinimumArity(functionDescriptor) <= valueArgCount &&
valueArgCount <= FunctionDescriptorUtil.getMaximumArity(functionDescriptor)) {
result.add(FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor)); result.add(FunctionDescriptorUtil.substituteFunctionDescriptor(typeArguments, functionDescriptor));
} }
} }
@@ -11,6 +11,7 @@ import java.util.List;
*/ */
public interface FunctionGroup extends Named { public interface FunctionGroup extends Named {
FunctionGroup EMPTY = new FunctionGroup() { FunctionGroup EMPTY = new FunctionGroup() {
@NotNull
@Override @Override
public String getName() { public String getName() {
return "<empty>"; return "<empty>";
@@ -19,7 +20,8 @@ public interface FunctionGroup extends Named {
@NotNull @NotNull
@Override @Override
public Collection<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) { public Collection<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
return Collections.emptySet(); return Collections.emptyList();
// return OverloadResolutionResult.nameNotFound();
} }
@Override @Override
@@ -35,6 +37,8 @@ public interface FunctionGroup extends Named {
@NotNull @NotNull
Collection<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes); Collection<FunctionDescriptor> getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes);
// @NotNull
// OverloadResolutionResult getPossiblyApplicableFunctions(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes);
boolean isEmpty(); boolean isEmpty();
} }
@@ -122,7 +122,8 @@ public class JetTypeInferrer {
boolean reportUnresolved) { boolean reportUnresolved) {
OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name); OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name);
overloadDomain = wrapForTracing(overloadDomain, reference, null, reportUnresolved); overloadDomain = wrapForTracing(overloadDomain, reference, null, reportUnresolved);
return overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.<JetType>emptyList(), argumentTypes); OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.<JetType>emptyList(), argumentTypes);
return resolutionResult.isSuccess() ? resolutionResult.getFunctionDescriptor() : null;
} }
@@ -209,41 +210,54 @@ public class JetTypeInferrer {
@Nullable final OverloadDomain overloadDomain, @Nullable final OverloadDomain overloadDomain,
@NotNull final JetReferenceExpression referenceExpression, @NotNull final JetReferenceExpression referenceExpression,
@Nullable final PsiElement argumentList, @Nullable final PsiElement argumentList,
final boolean reportUnresolved) { final boolean reportErrors) {
if (overloadDomain == null) return OverloadDomain.EMPTY; if (overloadDomain == null) return OverloadDomain.EMPTY;
return new OverloadDomain() { return new OverloadDomain() {
@NotNull
@Override @Override
public FunctionDescriptor getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) { public OverloadResolutionResult getFunctionDescriptorForNamedArguments(@NotNull List<JetType> typeArguments, @NotNull Map<String, JetType> valueArgumentTypes, @Nullable JetType functionLiteralArgumentType) {
FunctionDescriptor descriptor = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArgumentTypes, functionLiteralArgumentType); OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArgumentTypes, functionLiteralArgumentType);
if (descriptor != null) { report(resolutionResult);
trace.recordReferenceResolution(referenceExpression, descriptor); return resolutionResult;
}
else {
reportError();
}
return descriptor;
} }
@NotNull
@Override @Override
public FunctionDescriptor getFunctionDescriptorForPositionedArguments(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) { public OverloadResolutionResult getFunctionDescriptorForPositionedArguments(@NotNull List<JetType> typeArguments, @NotNull List<JetType> positionedValueArgumentTypes) {
FunctionDescriptor descriptor = overloadDomain.getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes); OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(typeArguments, positionedValueArgumentTypes);
if (descriptor != null) { report(resolutionResult);
trace.recordReferenceResolution(referenceExpression, descriptor); return resolutionResult;
}
else {
reportError();
}
return descriptor;
} }
private void reportError() { private void report(OverloadResolutionResult resolutionResult) {
if (reportUnresolved) { if (resolutionResult.isSuccess() || resolutionResult.singleFunction()) {
if (overloadDomain.isEmpty() || argumentList == null) { trace.recordReferenceResolution(referenceExpression, resolutionResult.getFunctionDescriptor());
semanticServices.getErrorHandler().unresolvedReference(referenceExpression); }
} if (reportErrors) {
else { switch (resolutionResult.getResultCode()) {
// TODO : More helpful message. NOTE: there's a separate handling for this for constructors case NAME_NOT_FOUND:
semanticServices.getErrorHandler().genericError(argumentList.getNode(), "No overload found for these arguments"); semanticServices.getErrorHandler().unresolvedReference(referenceExpression);
break;
case SINGLE_FUNCTION_ARGUMENT_MISMATCH:
if (argumentList != null) {
// TODO : More helpful message. NOTE: there's a separate handling for this for constructors
semanticServices.getErrorHandler().genericError(argumentList.getNode(), "Arguments do not match " + resolutionResult.getFunctionDescriptor());
}
else {
semanticServices.getErrorHandler().unresolvedReference(referenceExpression);
}
break;
case AMBIGUITY:
if (argumentList != null) {
// TODO : More helpful message. NOTE: there's a separate handling for this for constructors
semanticServices.getErrorHandler().genericError(argumentList.getNode(), "Overload ambiguity [TODO : more helpful message]");
}
else {
semanticServices.getErrorHandler().unresolvedReference(referenceExpression);
}
break;
default:
// Not a success
} }
} }
} }
@@ -693,7 +707,9 @@ public class JetTypeInferrer {
} }
} }
else { else {
semanticServices.getErrorHandler().genericError(typeElement.getNode(), "Calling a constructor is only supported for ordinary classes"); // TODO : Better message if (typeElement != null) {
semanticServices.getErrorHandler().genericError(typeElement.getNode(), "Calling a constructor is only supported for ordinary classes"); // TODO : Better message
}
} }
} }
} }
@@ -799,7 +815,10 @@ public class JetTypeInferrer {
List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>(); List<JetExpression> positionedValueArguments = new ArrayList<JetExpression>();
for (JetArgument argument : valueArguments) { for (JetArgument argument : valueArguments) {
positionedValueArguments.add(argument.getArgumentExpression()); JetExpression argumentExpression = argument.getArgumentExpression();
if (argumentExpression != null) {
positionedValueArguments.add(argumentExpression);
}
} }
positionedValueArguments.addAll(functionLiteralArguments); positionedValueArguments.addAll(functionLiteralArguments);
@@ -809,9 +828,9 @@ public class JetTypeInferrer {
valueArgumentTypes.add(safeGetType(scope, valueArgument, false)); valueArgumentTypes.add(safeGetType(scope, valueArgument, false));
} }
FunctionDescriptor functionDescriptor = overloadDomain.getFunctionDescriptorForPositionedArguments(types, valueArgumentTypes); OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(types, valueArgumentTypes);
if (functionDescriptor != null) { if (resolutionResult.isSuccess()) {
return functionDescriptor.getUnsubstitutedReturnType(); return resolutionResult.getFunctionDescriptor().getUnsubstitutedReturnType();
} }
} }
return null; return null;
@@ -1,8 +1,11 @@
package org.jetbrains.jet.lang.types; package org.jetbrains.jet.lang.types;
import org.jetbrains.annotations.NotNull;
/** /**
* @author abreslav * @author abreslav
*/ */
public interface Named { public interface Named {
@NotNull
String getName(); String getName();
} }