Frontend support for function as expression

This commit is contained in:
Stanislav Erokhin
2015-02-05 23:29:22 +03:00
parent 6ccd8ab764
commit 44895a23cf
28 changed files with 498 additions and 10 deletions
@@ -233,6 +233,9 @@ public interface Errors {
DiagnosticFactory0<PsiElement> REIFIED_TYPE_PARAMETER_NO_INLINE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetDeclaration> TYPE_PARAMETERS_NOT_ALLOWED
= DiagnosticFactory0.create(ERROR, TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE);
// Members
DiagnosticFactory0<JetModifierListOwner> PACKAGE_MEMBER_CANNOT_BE_PROTECTED =
@@ -339,6 +342,10 @@ public interface Errors {
DiagnosticFactory0<JetNamedFunction> NO_TAIL_CALLS_FOUND = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE);
DiagnosticFactory0<JetParameter> FUNCTION_EXPRESSION_PARAMETER_WITH_DEFAULT_VALUE = DiagnosticFactory0.create(ERROR, PARAMETER_DEFAULT_VALUE);
DiagnosticFactory0<JetParameter> USELESS_VARARG_ON_PARAMETER = DiagnosticFactory0.create(WARNING);
// Named parameters
DiagnosticFactory0<JetParameter> DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE = DiagnosticFactory0.create(ERROR, PARAMETER_DEFAULT_VALUE);
@@ -168,6 +168,18 @@ public object PositioningStrategies {
}
}
public val TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE: PositioningStrategy<JetDeclaration> = object : PositioningStrategy<JetDeclaration>() {
override fun mark(element: JetDeclaration): List<TextRange> {
if (element is JetTypeParameterListOwner) {
val jetTypeParameterList = element.getTypeParameterList()
if (jetTypeParameterList != null) {
return markElement(jetTypeParameterList)
}
}
return DECLARATION_SIGNATURE.mark(element)
}
}
public val ABSTRACT_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.ABSTRACT_KEYWORD)
public val INNER_MODIFIER: PositioningStrategy<JetModifierListOwner> = modifierSetPosition(JetTokens.INNER_KEYWORD)
@@ -229,6 +229,9 @@ public class DefaultErrorMessages {
MAP.put(PUBLIC_MEMBER_SHOULD_SPECIFY_TYPE, "Public or protected member should have specified type");
MAP.put(FUNCTION_EXPRESSION_PARAMETER_WITH_DEFAULT_VALUE, "A function expression is not allowed to specify default values for its parameters");
MAP.put(USELESS_VARARG_ON_PARAMETER, "Vararg on this parameter is useless");
MAP.put(PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT, "Projections are not allowed on type arguments of functions and properties");
MAP.put(SUPERTYPE_NOT_INITIALIZED, "This type has a constructor, and thus must be initialized here");
MAP.put(NOTHING_TO_OVERRIDE, "''{0}'' overrides nothing", NAME);
@@ -570,6 +573,7 @@ public class DefaultErrorMessages {
MAP.put(TYPE_PARAMETER_AS_REIFIED, "Cannot use ''{0}'' as reified type parameter. Use a class instead.", NAME);
MAP.put(REIFIED_TYPE_PARAMETER_NO_INLINE, "Only type parameters of inline functions can be reified");
MAP.put(REIFIED_TYPE_FORBIDDEN_SUBSTITUTION, "Cannot use ''{0}'' as reified type parameter", RENDER_TYPE);
MAP.put(TYPE_PARAMETERS_NOT_ALLOWED, "Type parameters are not allowed here");
MAP.put(SUPERTYPES_FOR_ANNOTATION_CLASS, "Annotation class cannot have supertypes");
MAP.put(MISSING_VAL_ON_ANNOTATION_PARAMETER, "'val' keyword is missing on annotation parameter");
@@ -241,7 +241,7 @@ public class DescriptorResolver {
}
@NotNull
public SimpleFunctionDescriptor resolveAnonymousFunctionDescriptor(
public SimpleFunctionDescriptor resolveFunctionExpressionDescriptor(
@NotNull DeclarationDescriptor containingDescriptor,
@NotNull JetScope scope,
@NotNull JetNamedFunction function,
@@ -20,6 +20,8 @@ import com.google.common.collect.Lists;
import com.intellij.psi.PsiElement;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import com.intellij.util.Function;
import com.intellij.util.containers.ContainerUtil;
import kotlin.Function1;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -29,6 +31,7 @@ import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor;
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
import org.jetbrains.kotlin.diagnostics.Diagnostic;
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
@@ -1302,22 +1305,78 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
boolean isStatement,
@Nullable WritableScope statementScope // must be not null if isStatement
) {
SimpleFunctionDescriptor functionDescriptor = components.expressionTypingServices.getDescriptorResolver().
resolveFunctionDescriptorWithAnnotationArguments(
context.scope.getContainingDeclaration(), context.scope, function, context.trace, context.dataFlowInfo);
if (!isStatement) { // function expression
if (!function.getTypeParameters().isEmpty()) {
context.trace.report(TYPE_PARAMETERS_NOT_ALLOWED.on(function));
}
for (JetParameter parameter : function.getValueParameters()) {
if (parameter.hasDefaultValue()) {
context.trace.report(FUNCTION_EXPRESSION_PARAMETER_WITH_DEFAULT_VALUE.on(parameter));
}
if (parameter.isVarArg()) {
context.trace.report(USELESS_VARARG_ON_PARAMETER.on(parameter));
}
}
}
ExpressionTypingServices services = components.expressionTypingServices;
SimpleFunctionDescriptor functionDescriptor;
if (isStatement) {
functionDescriptor = services.getDescriptorResolver().
resolveFunctionDescriptorWithAnnotationArguments(
context.scope.getContainingDeclaration(), context.scope, function, context.trace, context.dataFlowInfo);
assert statementScope != null : "statementScope must be not null for function: " +
function.getName() +
" at location " +
DiagnosticUtils.atLocation(function);
statementScope.addFunctionDescriptor(functionDescriptor);
}
else {
functionDescriptor = services.getDescriptorResolver().resolveFunctionExpressionDescriptor(
context.scope.getContainingDeclaration(), context.scope, function, context.trace, context.dataFlowInfo);
}
statementScope.addFunctionDescriptor(functionDescriptor);
JetScope functionInnerScope = FunctionDescriptorUtil.getFunctionInnerScope(context.scope, functionDescriptor, context.trace);
components.expressionTypingServices.checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace);
services.checkFunctionReturnType(functionInnerScope, function, functionDescriptor, context.dataFlowInfo, null, context.trace);
components.expressionTypingServices.resolveValueParameters(function.getValueParameters(), functionDescriptor.getValueParameters(),
context.scope, context.dataFlowInfo, context.trace);
services.resolveValueParameters(function.getValueParameters(), functionDescriptor.getValueParameters(), context.scope,
context.dataFlowInfo, context.trace);
ModifiersChecker.create(context.trace, components.additionalCheckerProvider).checkModifiersForLocalDeclaration(function, functionDescriptor);
ModifiersChecker.create(context.trace, components.additionalCheckerProvider).checkModifiersForLocalDeclaration(function,
functionDescriptor);
if (!function.hasBody()) {
context.trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor));
}
return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo);
if (isStatement) {
return DataFlowUtils.checkStatementType(function, context, context.dataFlowInfo);
}
else {
return DataFlowUtils.checkType(createFunctionType(functionDescriptor), function, context, context.dataFlowInfo);
}
}
@Nullable
private JetType createFunctionType(@NotNull SimpleFunctionDescriptor functionDescriptor) {
JetType receiverType = functionDescriptor.getExtensionReceiverParameter() != null
? functionDescriptor.getExtensionReceiverParameter().getType()
: null;
JetType returnType = functionDescriptor.getReturnType();
if (returnType == null) {
return null;
}
List<JetType> parameters =
ContainerUtil.map(functionDescriptor.getValueParameters(), new Function<ValueParameterDescriptor, JetType>() {
@Override
public JetType fun(ValueParameterDescriptor descriptor) {
return descriptor.getType();
}
});
return components.builtIns.getFunctionType(Annotations.EMPTY, receiverType, parameters, returnType);
}
@Override