diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionLiteral.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionLiteral.java index 976b8d04d62..6f20e9a1478 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionLiteral.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionLiteral.java @@ -3,6 +3,7 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import com.intellij.psi.PsiElement; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lexer.JetTokens; /** @@ -36,4 +37,20 @@ public class JetFunctionLiteral extends JetFunction { public JetBlockExpression getBodyExpression() { return (JetBlockExpression) super.getBodyExpression(); } + + @NotNull + public ASTNode getOpenBraceNode() { + return getNode().findChildByType(JetTokens.LBRACE); + } + + @Nullable + @IfNotParsed + public ASTNode getClosingBraceNode() { + return getNode().findChildByType(JetTokens.RBRACE); + } + + @Nullable + public ASTNode getArrowNode() { + return getNode().findChildByType(JetTokens.DOUBLE_ARROW); + } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionLiteralExpression.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionLiteralExpression.java index a91fbac044e..070bf524ff3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionLiteralExpression.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetFunctionLiteralExpression.java @@ -2,7 +2,9 @@ package org.jetbrains.jet.lang.psi; import com.intellij.lang.ASTNode; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.JetNodeTypes; +import org.jetbrains.jet.lexer.JetTokens; /** * @author max @@ -47,4 +49,5 @@ public class JetFunctionLiteralExpression extends JetExpression implements JetDe public JetElement asElement() { return this; } + } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index f0f64418c2b..02ea69673d3 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -32,7 +32,8 @@ public interface BindingContext { WritableSlice RESOLUTION_SCOPE = Slices.createSimpleSlice("RESOLUTION_SCOPE"); WritableSlice VARIABLE_REASSIGNMENT = Slices.createSimpleSetSlice("VARIABLE_REASSIGNMENT"); - WritableSlice VARIABLE_ASSIGNMENT = Slices.createSimpleSlice("VARIABLE_ASSIGNMENT"); + WritableSlice AUTO_CREATED_IT = Slices.createSimpleSetSlice("AUTO_CREATED_IT"); + WritableSlice VARIABLE_ASSIGNMENT = Slices.createSimpleSlice("VARIABLE_ASSIGNMENT"); WritableSlice PROCESSED = Slices.createSimpleSetSlice("PROCESSED"); WritableSlice STATEMENT = Slices.createRemovableSetSlice("STATEMENT"); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java index cb2611a1ed0..d1074f7e62f 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/types/JetTypeInferrer.java @@ -899,36 +899,46 @@ public class JetTypeInferrer { List parameterTypes = new ArrayList(); List valueParameterDescriptors = Lists.newArrayList(); - List parameters = functionLiteral.getValueParameters(); + List declaredValueParameters = functionLiteral.getValueParameters(); JetType expectedType = context.expectedType; - - List valueParameters = null; + boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(expectedType); - if (functionTypeExpected) { - valueParameters = JetStandardClasses.getValueParameters(functionDescriptor, expectedType); + List expectedValueParameters = (functionTypeExpected) + ? JetStandardClasses.getValueParameters(functionDescriptor, expectedType) + : null; + + if (functionTypeExpected && declaredValueParameters.isEmpty() && expectedValueParameters.size() == 1) { + ValueParameterDescriptor valueParameterDescriptor = expectedValueParameters.get(0); + ValueParameterDescriptor it = new ValueParameterDescriptorImpl( + functionDescriptor, 0, Collections.emptyList(), "it", valueParameterDescriptor.getInType(), valueParameterDescriptor.getOutType(), valueParameterDescriptor.hasDefaultValue(), valueParameterDescriptor.isVararg() + ); + valueParameterDescriptors.add(it); + parameterTypes.add(it.getOutType()); + context.trace.record(AUTO_CREATED_IT, it); } + else { + for (int i = 0; i < declaredValueParameters.size(); i++) { + JetParameter declaredParameter = declaredValueParameters.get(i); + JetTypeReference typeReference = declaredParameter.getTypeReference(); - for (int i = 0, parametersSize = parameters.size(); i < parametersSize; i++) { - JetParameter parameter = parameters.get(i); - JetTypeReference typeReference = parameter.getTypeReference(); - - JetType type; - if (typeReference != null) { - type = context.typeResolver.resolveType(context.scope, typeReference); - } - else { - if (valueParameters != null) { - type = valueParameters.get(i).getOutType(); + JetType type; + if (typeReference != null) { + type = context.typeResolver.resolveType(context.scope, typeReference); } else { -// context.trace.getErrorHandler().genericError(parameter.getNode(), "Cannot infer a type for this parameter. To specify it explicitly use the {(p : Type) => ...} notation"); - context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(parameter)); - type = ErrorUtils.createErrorType("Cannot be inferred"); + if (expectedValueParameters != null && i < expectedValueParameters.size()) { + type = expectedValueParameters.get(i).getOutType(); + } + else { + // context.trace.getErrorHandler().genericError(declaredParameter.getNode(), "Cannot infer a type for this declaredParameter. To specify it explicitly use the {(p : Type) => ...} notation"); + context.trace.report(CANNOT_INFER_PARAMETER_TYPE.on(declaredParameter)); + type = ErrorUtils.createErrorType("Cannot be inferred"); + } } + ValueParameterDescriptor valueParameterDescriptor = context.classDescriptorResolver.resolveValueParameterDescriptor(functionDescriptor, declaredParameter, i, type); + parameterTypes.add(valueParameterDescriptor.getOutType()); + valueParameterDescriptors.add(valueParameterDescriptor); } - ValueParameterDescriptor valueParameterDescriptor = context.classDescriptorResolver.resolveValueParameterDescriptor(functionDescriptor, parameter, i, type); - parameterTypes.add(valueParameterDescriptor.getOutType()); - valueParameterDescriptors.add(valueParameterDescriptor); } JetType effectiveReceiverType; diff --git a/idea/src/org/jetbrains/jet/checkers/CheckerTestUtil.java b/idea/src/org/jetbrains/jet/checkers/CheckerTestUtil.java index 2654c959201..edff0f640a1 100644 --- a/idea/src/org/jetbrains/jet/checkers/CheckerTestUtil.java +++ b/idea/src/org/jetbrains/jet/checkers/CheckerTestUtil.java @@ -176,9 +176,14 @@ public class CheckerTestUtil { closeDiagnosticString(result); opened.pop(); } - if (currentDescriptor != null && i == currentDescriptor.start) { + while (currentDescriptor != null && i == currentDescriptor.start) { openDiagnosticsString(result, currentDescriptor); - opened.push(currentDescriptor); + if (currentDescriptor.getEnd() == i) { + closeDiagnosticString(result); + } + else { + opened.push(currentDescriptor); + } if (iterator.hasNext()) { currentDescriptor = iterator.next(); } diff --git a/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java b/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java index 243f8a72e93..79903d2774b 100644 --- a/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java +++ b/idea/src/org/jetbrains/jet/plugin/JetHighlighter.java @@ -97,6 +97,24 @@ public class JetHighlighter extends SyntaxHighlighterBase { JET_AUTO_CAST_EXPRESSION = TextAttributesKey.createTextAttributesKey("JET.AUTO.CAST.EXPRESSION", clone); } + public static final TextAttributesKey JET_AUTOCREATED_IT; + + static { + TextAttributes attributes = new TextAttributes(); + attributes.setFontType(Font.BOLD); +// TODO: proper attributes + JET_AUTOCREATED_IT = TextAttributesKey.createTextAttributesKey("JET.AUTO.CREATED.IT", attributes); + } + + public static final TextAttributesKey JET_FUNCTION_LITERAL_DELIMITER; + + static { + TextAttributes attributes = new TextAttributes(); + attributes.setFontType(Font.BOLD); +// TODO: proper attributes + JET_FUNCTION_LITERAL_DELIMITER = TextAttributesKey.createTextAttributesKey("JET.AUTO.CREATED.IT", attributes); + } + public static final TextAttributesKey JET_DEBUG_INFO; static { diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java index 9dd958ceee2..29f8a1abe65 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/JetPsiChecker.java @@ -13,7 +13,9 @@ import com.intellij.psi.MultiRangeReference; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiReference; import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; import org.jetbrains.jet.lang.descriptors.PropertyDescriptor; +import org.jetbrains.jet.lang.descriptors.ValueParameterDescriptor; import org.jetbrains.jet.lang.descriptors.VariableDescriptor; import org.jetbrains.jet.lang.diagnostics.*; import org.jetbrains.jet.lang.psi.*; @@ -27,6 +29,10 @@ import org.jetbrains.jet.plugin.quickfix.QuickFixes; import java.util.Collection; import java.util.Set; +import static org.jetbrains.jet.lang.resolve.BindingContext.AUTOCAST; +import static org.jetbrains.jet.lang.resolve.BindingContext.AUTO_CREATED_IT; +import static org.jetbrains.jet.lang.resolve.BindingContext.REFERENCE_TARGET; + /** * @author abreslav */ @@ -100,9 +106,21 @@ public class JetPsiChecker implements Annotator { highlightBackingFields(holder, file, bindingContext); file.acceptChildren(new JetVisitorVoid() { + @Override + public void visitSimpleNameExpression(JetSimpleNameExpression expression) { + DeclarationDescriptor target = bindingContext.get(REFERENCE_TARGET, expression); + if (target instanceof ValueParameterDescriptor) { + ValueParameterDescriptor parameterDescriptor = (ValueParameterDescriptor) target; + if (bindingContext.get(AUTO_CREATED_IT, parameterDescriptor)) { + holder.createInfoAnnotation(expression, "Automatically declared based on the expected type").setTextAttributes(JetHighlighter.JET_AUTOCREATED_IT); + } + } + super.visitSimpleNameExpression(expression); + } + @Override public void visitExpression(JetExpression expression) { - JetType autoCast = bindingContext.get(BindingContext.AUTOCAST, expression); + JetType autoCast = bindingContext.get(AUTOCAST, expression); if (autoCast != null) { holder.createInfoAnnotation(expression, "Automatically cast to " + autoCast).setTextAttributes(JetHighlighter.JET_AUTO_CAST_EXPRESSION); } diff --git a/idea/src/org/jetbrains/jet/plugin/annotations/SoftKeywordsAnnotator.java b/idea/src/org/jetbrains/jet/plugin/annotations/SoftKeywordsAnnotator.java index 77aa4d0eac4..194d06ab932 100644 --- a/idea/src/org/jetbrains/jet/plugin/annotations/SoftKeywordsAnnotator.java +++ b/idea/src/org/jetbrains/jet/plugin/annotations/SoftKeywordsAnnotator.java @@ -3,8 +3,10 @@ */ package org.jetbrains.jet.plugin.annotations; +import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; +import com.intellij.openapi.application.ApplicationManager; import com.intellij.psi.PsiElement; import com.intellij.psi.impl.source.tree.LeafPsiElement; import org.jetbrains.annotations.NotNull; @@ -13,20 +15,41 @@ import org.jetbrains.jet.plugin.JetHighlighter; import org.jetbrains.jet.lexer.JetTokens; public class SoftKeywordsAnnotator implements Annotator { - public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { - if (element instanceof LeafPsiElement) { - if (JetTokens.SOFT_KEYWORDS.contains(((LeafPsiElement) element).getElementType())) { - holder.createInfoAnnotation(element, null).setTextAttributes(JetHighlighter.JET_SOFT_KEYWORD); + public void annotate(@NotNull PsiElement element, @NotNull final AnnotationHolder holder) { + element.accept(new JetVisitorVoid() { + @Override + public void visitElement(PsiElement element) { + if (element instanceof LeafPsiElement) { + if (JetTokens.SOFT_KEYWORDS.contains(((LeafPsiElement) element).getElementType())) { + holder.createInfoAnnotation(element, null).setTextAttributes(JetHighlighter.JET_SOFT_KEYWORD); + } + } } - } - else if (element instanceof JetAnnotationEntry) { - JetAnnotationEntry entry = (JetAnnotationEntry) element; - JetTypeReference typeReference = entry.getTypeReference(); - if (typeReference != null) { - JetTypeElement typeElement = typeReference.getTypeElement(); - markAnnotationIdentifiers(typeElement, holder); + + @Override + public void visitAnnotationEntry(JetAnnotationEntry annotationEntry) { + JetTypeReference typeReference = annotationEntry.getTypeReference(); + if (typeReference != null) { + JetTypeElement typeElement = typeReference.getTypeElement(); + markAnnotationIdentifiers(typeElement, holder); + } } - } + + @Override + public void visitFunctionLiteralExpression(JetFunctionLiteralExpression expression) { + if (ApplicationManager.getApplication().isUnitTestMode()) return; + JetFunctionLiteral functionLiteral = expression.getFunctionLiteral(); + holder.createInfoAnnotation(functionLiteral.getOpenBraceNode(), null).setTextAttributes(JetHighlighter.JET_FUNCTION_LITERAL_DELIMITER); + ASTNode closingBraceNode = functionLiteral.getClosingBraceNode(); + if (closingBraceNode != null) { + holder.createInfoAnnotation(closingBraceNode, null).setTextAttributes(JetHighlighter.JET_FUNCTION_LITERAL_DELIMITER); + } + ASTNode arrowNode = functionLiteral.getArrowNode(); + if (arrowNode != null) { + holder.createInfoAnnotation(arrowNode, null).setTextAttributes(JetHighlighter.JET_FUNCTION_LITERAL_DELIMITER); + } + } + }); } private void markAnnotationIdentifiers(JetTypeElement typeElement, @NotNull AnnotationHolder holder) { diff --git a/idea/testData/checkerWithErrorTypes/quick/AutoCreatedIt.jet b/idea/testData/checkerWithErrorTypes/quick/AutoCreatedIt.jet new file mode 100644 index 00000000000..66c9e1f9543 --- /dev/null +++ b/idea/testData/checkerWithErrorTypes/quick/AutoCreatedIt.jet @@ -0,0 +1,32 @@ +fun text() { + "direct:a" to "mock:a" + "direct:a" on {it.body == ""} to "mock:a" + "direct:a" on {it => it.body == ""} to "mock:a" + bar {1} + bar {it + 1} + bar {it, it1 => it} + + bar1 {1} + bar1 {it + 1} + + bar2 {} + bar2 {1} + bar2 {it} + bar2 {it => it} +} + +fun bar(f : fun (Int, Int) : Int) {} +fun bar1(f : fun (Int) : Int) {} +fun bar2(f : fun () : Int) {} + +fun String.to(dest : String) { + +} + +fun String.on(predicate : fun (s : URI) : Boolean) : URI { + return URI(this) +} + +class URI(val body : Any) { + fun to(dest : String) {} +} \ No newline at end of file