diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java index 66143c837c3..e8233d1f041 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetExpressionParsing.java @@ -26,7 +26,7 @@ public class JetExpressionParsing extends AbstractJetParsing { CONTINUE_KEYWORD, OBJECT_KEYWORD, IF_KEYWORD, TRY_KEYWORD, ELSE_KEYWORD, WHILE_KEYWORD, DO_KEYWORD, WHEN_KEYWORD, RBRACKET, RBRACE, RPAR, PLUSPLUS, MINUSMINUS, MUL, PLUS, MINUS, EXCL, DIV, PERC, LTEQ, // TODO GTEQ, foo=x - EQEQEQ, ARROW, DOUBLE_ARROW, EXCLEQEQEQ, EQEQ, EXCLEQ, ANDAND, OROR, SAFE_ACCESS, ELVIS, QUEST, + EQEQEQ, ARROW, DOUBLE_ARROW, EXCLEQEQEQ, EQEQ, EXCLEQ, ANDAND, OROR, SAFE_ACCESS, ELVIS, SEMICOLON, RANGE, EQ, MULTEQ, DIVEQ, PERCEQ, PLUSEQ, MINUSEQ, NOT_IN, NOT_IS, HASH, COLON ); @@ -398,7 +398,9 @@ public class JetExpressionParsing extends AbstractJetParsing { int gtPos = matchTokenStreamPredicate(new FirstBefore( new At(GT), new AtSet(TYPE_ARGUMENT_LIST_STOPPERS, TokenSet.create(RPAR, RBRACE, RBRACKET)) - .or(new AtFirstTokenOfTokens(IDENTIFIER, LPAR)) + .or(new AtFirstTokenOfTokens(IDENTIFIER, LPAR) +// .or(new AtFirstTokenOfTokens(QUEST, IDENTIFIER)) + ) ) { @Override public boolean isTopLevel(int openAngleBrackets, int openBrackets, int openBraces, int openParentheses) { @@ -412,7 +414,7 @@ public class JetExpressionParsing extends AbstractJetParsing { } }); if (gtPos >= 0) { - myJetParsing.parseTypeArgumentList(); + myJetParsing.parseTypeArgumentList(gtPos); if (!myBuilder.newlineBeforeCurrentToken() && at(LPAR)) parseValueArgumentList(); parseCallWithClosure(); } diff --git a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java index 3c4ad6be1df..5dca3fa8271 100644 --- a/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java +++ b/idea/src/org/jetbrains/jet/lang/parsing/JetParsing.java @@ -1249,7 +1249,7 @@ public class JetParsing extends AbstractJetParsing { expect(IDENTIFIER, "Type name expected", TokenSet.orSet(JetExpressionParsing.EXPRESSION_FIRST, JetExpressionParsing.EXPRESSION_FOLLOW)); reference.done(REFERENCE_EXPRESSION); - parseTypeArgumentList(); + parseTypeArgumentList(-1); if (!at(DOT)) { break; } @@ -1268,7 +1268,7 @@ public class JetParsing extends AbstractJetParsing { /* * (optionalProjection type){","} */ - public PsiBuilder.Marker parseTypeArgumentList() { + public PsiBuilder.Marker parseTypeArgumentList(int expectedGtOffset) { if (!at(LT)) return null; PsiBuilder.Marker list = mark(); @@ -1292,6 +1292,14 @@ public class JetParsing extends AbstractJetParsing { advance(); // COMMA } + if (expectedGtOffset >= 0 && myBuilder.getCurrentOffset() < expectedGtOffset) { + final PsiBuilder.Marker error = mark(); + while (myBuilder.getCurrentOffset() < expectedGtOffset) { + advance(); + } + error.error("Expecting a '>'"); + } + expect(GT, "Expecting a '>'"); myBuilder.restoreNewlinesState(); diff --git a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java index 3f461a35e75..1343a9168c3 100644 --- a/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java +++ b/idea/src/org/jetbrains/jet/lang/resolve/OverloadResolver.java @@ -63,10 +63,6 @@ public class OverloadResolver { 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; } diff --git a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index ff203a90bba..8f601937604 100644 --- a/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/idea/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -122,11 +122,19 @@ public class JetTypeInferrer { @NotNull List argumentTypes, boolean reportUnresolved) { OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name); + // No generics. Guaranteed overloadDomain = wrapForTracing(overloadDomain, reference, null, reportUnresolved); OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.emptyList(), argumentTypes); return resolutionResult.isSuccess() ? resolutionResult.getFunctionDescriptor() : null; } + @NotNull + private OverloadResolutionResult resolveNoParametersFunction(@NotNull JetType receiverType, @NotNull JetScope scope, @NotNull String name) { + OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name); + // No generics. Guaranteed + return overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.emptyList(), Collections.emptyList()); + } + private OverloadDomain getOverloadDomain( @Nullable final JetType receiverType, @NotNull final JetScope scope, @@ -163,6 +171,7 @@ public class JetTypeInferrer { String referencedName = referenceExpression.getReferencedName(); if (receiverType != null && referencedName != null) { + // No generics. Guaranteed result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referencedName); reference[0] = referenceExpression; } @@ -176,6 +185,7 @@ public class JetTypeInferrer { // a -- create a hierarchical lookup domain for this.a String referencedName = expression.getReferencedName(); if (referencedName != null) { + // No generics. Guaranteed result[0] = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, referencedName); reference[0] = expression; } @@ -215,12 +225,10 @@ public class JetTypeInferrer { } private OverloadDomain wrapForTracing( - @Nullable final OverloadDomain overloadDomain, - final JetReferenceExpression referenceExpression, + @NotNull final OverloadDomain overloadDomain, + @NotNull final JetReferenceExpression referenceExpression, @Nullable final PsiElement argumentList, final boolean reportErrors) { - if (overloadDomain == null) return OverloadDomain.EMPTY; - assert referenceExpression != null; return new OverloadDomain() { @NotNull @Override @@ -400,9 +408,9 @@ public class JetTypeInferrer { // 1) ends with a name -> (scope, name) to look up // 2) ends with something else -> just check types - final List typeArguments = call.getTypeArguments(); + final List jetTypeArguments = call.getTypeArguments(); - for (JetTypeProjection typeArgument : typeArguments) { + for (JetTypeProjection typeArgument : jetTypeArguments) { if (typeArgument.getProjectionKind() != JetProjectionKind.NONE) { trace.getErrorHandler().genericError(typeArgument.getNode(), "Projections are not allowed on type parameters for methods"); // TODO : better positioning } @@ -429,12 +437,12 @@ public class JetTypeInferrer { // result = overloadDomain.getFunctionDescriptorForNamedArguments(typeArguments, valueArguments, functionLiteralArgument); } else { - List types = new ArrayList(); - for (JetTypeProjection projection : typeArguments) { + List typeArguments = new ArrayList(); + for (JetTypeProjection projection : jetTypeArguments) { // TODO : check that there's no projection JetTypeReference typeReference = projection.getTypeReference(); if (typeReference != null) { - types.add(typeResolver.resolveType(scope, typeReference)); + typeArguments.add(typeResolver.resolveType(scope, typeReference)); } } @@ -453,9 +461,20 @@ public class JetTypeInferrer { valueArgumentTypes.add(safeGetType(scope, valueArgument, false)); } - OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(types, valueArgumentTypes); + OverloadResolutionResult resolutionResult = overloadDomain.getFunctionDescriptorForPositionedArguments(typeArguments, valueArgumentTypes); if (resolutionResult.isSuccess()) { - return resolutionResult.getFunctionDescriptor().getUnsubstitutedReturnType(); + final FunctionDescriptor functionDescriptor = resolutionResult.getFunctionDescriptor(); + + List typeParameters = functionDescriptor.getOriginal().getTypeParameters(); + for (int i = 0, typeParametersSize = typeParameters.size(); i < typeParametersSize; i++) { + TypeParameterDescriptor typeParameterDescriptor = typeParameters.get(i); + final JetType typeArgument = typeArguments.get(i); + if (!semanticServices.getTypeChecker().isSubtypeOf(typeArgument, typeParameterDescriptor.getBoundsAsType())) { + trace.getErrorHandler().genericError(jetTypeArguments.get(i).getNode(), "Bound of the type parameter " + DescriptorRenderer.TEXT.render(typeParameterDescriptor) + " is not respected by the type " + typeArgument); + } + + } + return functionDescriptor.getUnsubstitutedReturnType(); } } return null; @@ -1340,12 +1359,6 @@ public class JetTypeInferrer { return true; } - @NotNull - private OverloadResolutionResult resolveNoParametersFunction(@NotNull JetType receiverType, @NotNull JetScope scope, @NotNull String name) { - OverloadDomain overloadDomain = semanticServices.getOverloadResolver().getOverloadDomain(receiverType, scope, name); - return overloadDomain.getFunctionDescriptorForPositionedArguments(Collections.emptyList(), Collections.emptyList()); - } - @Override public void visitNewExpression(JetNewExpression expression) { // TODO : type argument inference @@ -1386,11 +1399,14 @@ public class JetTypeInferrer { } } + private JetType getCallExpressionType(@Nullable JetType receiverType, @NotNull JetCallExpression callExpression) { + OverloadDomain overloadDomain = getOverloadDomain(receiverType, scope, callExpression.getCalleeExpression(), callExpression.getValueArgumentList()); + return resolveCall(scope, overloadDomain, callExpression); + } + private JetType getSelectorReturnType(JetType receiverType, JetExpression selectorExpression) { if (selectorExpression instanceof JetCallExpression) { - JetCallExpression callExpression = (JetCallExpression) selectorExpression; - OverloadDomain overloadDomain = getOverloadDomain(receiverType, scope, callExpression.getCalleeExpression(), callExpression.getValueArgumentList()); - return resolveCall(scope, overloadDomain, callExpression); + return getCallExpressionType(receiverType, (JetCallExpression) selectorExpression); } else if (selectorExpression instanceof JetSimpleNameExpression) { JetScope compositeScope = new ScopeWithReceiver(scope, receiverType, semanticServices.getTypeChecker()); @@ -1405,9 +1421,7 @@ public class JetTypeInferrer { @Override public void visitCallExpression(JetCallExpression expression) { - JetExpression calleeExpression = expression.getCalleeExpression(); - OverloadDomain overloadDomain = getOverloadDomain(null, scope, calleeExpression, expression.getValueArgumentList()); - result = resolveCall(scope, overloadDomain, expression); + result = getCallExpressionType(null, expression); } @Override diff --git a/idea/testData/checker/Bounds.jet b/idea/testData/checker/Bounds.jet index fb3572843ec..47e9824bcee 100644 --- a/idea/testData/checker/Bounds.jet +++ b/idea/testData/checker/Bounds.jet @@ -23,3 +23,18 @@ namespace boundsWithSubstitutors { val x : {(B<Char>) : B<Any>} } + + +fun test() { + foo<Int?>() + foo() + bar() + bar() + bar<Double?>() + bar<Double>() + 1.buzz<Double>() +} + +fun foo() {} +fun bar() {} +fun Int.buzz() : Unit {} diff --git a/idea/testData/psi/TypeExpressionAmbiguities_ERR.jet b/idea/testData/psi/TypeExpressionAmbiguities_ERR.jet index 42e4918a0ed..fb993207d65 100644 --- a/idea/testData/psi/TypeExpressionAmbiguities_ERR.jet +++ b/idea/testData/psi/TypeExpressionAmbiguities_ERR.jet @@ -1,4 +1,6 @@ fun foo() { + foo() + fooo() dd<(Int, Int, Int)>(if (true) (1, 1, 1) else (2, 2, 2)) foo(bar(d)) foo(bar(d)) diff --git a/idea/testData/psi/TypeExpressionAmbiguities_ERR.txt b/idea/testData/psi/TypeExpressionAmbiguities_ERR.txt index 0f4338ef3b8..433bb1c6922 100644 --- a/idea/testData/psi/TypeExpressionAmbiguities_ERR.txt +++ b/idea/testData/psi/TypeExpressionAmbiguities_ERR.txt @@ -11,6 +11,42 @@ JetFile: TypeExpressionAmbiguities_ERR.jet BLOCK PsiElement(LBRACE)('{') PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('foo') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Int') + PsiElement(QUEST)('?') + PsiElement(GT)('>') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') + CALL_EXPRESSION + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('fooo') + TYPE_ARGUMENT_LIST + PsiElement(LT)('<') + TYPE_PROJECTION + TYPE_REFERENCE + NULLABLE_TYPE + USER_TYPE + REFERENCE_EXPRESSION + PsiElement(IDENTIFIER)('Double') + PsiElement(QUEST)('?') + PsiErrorElement:Expecting a '>' + PsiElement(IDENTIFIER)('addddd') + PsiElement(GT)('>') + VALUE_ARGUMENT_LIST + PsiElement(LPAR)('(') + PsiElement(RPAR)(')') + PsiWhiteSpace('\n ') CALL_EXPRESSION REFERENCE_EXPRESSION PsiElement(IDENTIFIER)('dd')