"it" inference supported
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ public interface BindingContext {
|
||||
WritableSlice<JetExpression, JetScope> RESOLUTION_SCOPE = Slices.createSimpleSlice("RESOLUTION_SCOPE");
|
||||
|
||||
WritableSlice<JetExpression, Boolean> VARIABLE_REASSIGNMENT = Slices.createSimpleSetSlice("VARIABLE_REASSIGNMENT");
|
||||
WritableSlice<JetExpression, DeclarationDescriptor> VARIABLE_ASSIGNMENT = Slices.createSimpleSlice("VARIABLE_ASSIGNMENT");
|
||||
WritableSlice<ValueParameterDescriptor, Boolean> AUTO_CREATED_IT = Slices.createSimpleSetSlice("AUTO_CREATED_IT");
|
||||
WritableSlice<JetExpression, DeclarationDescriptor> VARIABLE_ASSIGNMENT = Slices.createSimpleSlice("VARIABLE_ASSIGNMENT");
|
||||
WritableSlice<JetExpression, Boolean> PROCESSED = Slices.createSimpleSetSlice("PROCESSED");
|
||||
WritableSlice<JetElement, Boolean> STATEMENT = Slices.createRemovableSetSlice("STATEMENT");
|
||||
|
||||
|
||||
@@ -899,36 +899,46 @@ public class JetTypeInferrer {
|
||||
|
||||
List<JetType> parameterTypes = new ArrayList<JetType>();
|
||||
List<ValueParameterDescriptor> valueParameterDescriptors = Lists.newArrayList();
|
||||
List<JetParameter> parameters = functionLiteral.getValueParameters();
|
||||
List<JetParameter> declaredValueParameters = functionLiteral.getValueParameters();
|
||||
JetType expectedType = context.expectedType;
|
||||
|
||||
List<ValueParameterDescriptor> valueParameters = null;
|
||||
|
||||
boolean functionTypeExpected = expectedType != NO_EXPECTED_TYPE && JetStandardClasses.isFunctionType(expectedType);
|
||||
if (functionTypeExpected) {
|
||||
valueParameters = JetStandardClasses.getValueParameters(functionDescriptor, expectedType);
|
||||
List<ValueParameterDescriptor> 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.<AnnotationDescriptor>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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
fun text() {
|
||||
"direct:a" to "mock:a"
|
||||
"direct:a" on {it.body == "<hello/>"} to "mock:a"
|
||||
"direct:a" on {it => it.body == "<hello/>"} to "mock:a"
|
||||
bar <!TYPE_MISMATCH!>{1}<!>
|
||||
bar <!TYPE_MISMATCH!>{<!UNRESOLVED_REFERENCE!>it<!> <!UNRESOLVED_REFERENCE!>+<!> 1}<!>
|
||||
bar {it, it1 => it}
|
||||
|
||||
bar1 {1}
|
||||
bar1 {it + 1}
|
||||
|
||||
bar2 <!TYPE_MISMATCH!>{<!TYPE_MISMATCH!><!>}<!>
|
||||
bar2 {1}
|
||||
bar2 {<!UNRESOLVED_REFERENCE!>it<!>}
|
||||
bar2 <!TYPE_MISMATCH!>{<!CANNOT_INFER_PARAMETER_TYPE!>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) {}
|
||||
}
|
||||
Reference in New Issue
Block a user