diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java index 8f753b3929a..ec473f8c229 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/psi/JetPsiUtil.java @@ -121,12 +121,16 @@ public class JetPsiUtil { @Nullable public static JetExpression getBaseExpressionIfLabeledExpression(@NotNull JetPrefixExpression expression) { - if (JetTokens.LABELS.contains(expression.getOperationReference().getReferencedNameElementType())) { + if (isLabeledExpression(expression)) { return expression.getBaseExpression(); } return null; } + public static boolean isLabeledExpression(JetPrefixExpression expression) { + return JetTokens.LABELS.contains(expression.getOperationReference().getReferencedNameElementType()); + } + @NotNull public static Name safeName(@Nullable String name) { return name == null ? SpecialNames.NO_NAME_PROVIDED : Name.identifier(name); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java index 40fccf235d1..28c73f45565 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java @@ -25,16 +25,19 @@ import org.jetbrains.jet.lang.psi.*; import org.jetbrains.jet.lang.resolve.BindingContext; import org.jetbrains.jet.lang.resolve.DescriptorUtils; import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; -import org.jetbrains.jet.lang.resolve.calls.model.*; +import org.jetbrains.jet.lang.resolve.calls.model.DefaultValueArgument; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; +import org.jetbrains.jet.lang.resolve.calls.model.VarargValueArgument; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ExtensionReceiver; import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.lang.InlineUtil; import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; -import org.jetbrains.jet.lexer.JetTokens; -import java.util.*; +import java.util.HashSet; +import java.util.Set; public class InlineCallResolverExtension implements CallResolverExtension { @@ -55,7 +58,7 @@ public class InlineCallResolverExtension implements CallResolverExtension { } } - //add extension receiver as inlineable + //add extension receiver as inlinable ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); if (receiverParameter != null) { if (isInlinableParameter(receiverParameter)) { @@ -68,25 +71,23 @@ public class InlineCallResolverExtension implements CallResolverExtension { public void run( @NotNull ResolvedCall resolvedCall, @NotNull BasicCallResolutionContext context ) { - CallableDescriptor targetDescriptor = resolvedCall.getResultingDescriptor(); JetExpression expression = context.call.getCalleeExpression(); if (expression == null) { return; } //checking that only invoke or inlinable extension called on function parameter + CallableDescriptor targetDescriptor = resolvedCall.getResultingDescriptor(); checkCallWithReceiver(context, targetDescriptor, resolvedCall.getThisObject(), expression); checkCallWithReceiver(context, targetDescriptor, resolvedCall.getReceiverArgument(), expression); - boolean isInlinableClosure = inlinableParameters.contains(targetDescriptor); - if (isInlinableClosure) { + if (inlinableParameters.contains(targetDescriptor)) { if (!couldAccessVariable(expression)) { context.trace.report(Errors.USAGE_IS_NOT_INLINABLE.on(expression, expression, descriptor)); } } - for (Map.Entry entry : resolvedCall.getValueArguments().entrySet()) { - ResolvedValueArgument value = entry.getValue(); + for (ResolvedValueArgument value : resolvedCall.getValueArguments().values()) { if (!(value instanceof DefaultValueArgument)) { for (ValueArgument argument : value.getArguments()) { checkValueParameter(context, targetDescriptor, argument, value instanceof VarargValueArgument); @@ -97,7 +98,7 @@ public class InlineCallResolverExtension implements CallResolverExtension { checkVisibility(targetDescriptor, expression, context); } - private boolean couldAccessVariable(JetExpression expression) { + private static boolean couldAccessVariable(JetExpression expression) { PsiElement parent = expression.getParent(); while (parent != null) { if (parent instanceof JetValueArgument || @@ -109,12 +110,15 @@ public class InlineCallResolverExtension implements CallResolverExtension { } else if (parent instanceof JetParenthesizedExpression || parent instanceof JetBinaryExpressionWithTypeRHS) { parent = parent.getParent(); - } else if (parent instanceof JetPrefixExpression) { - boolean isLabeled = JetTokens.LABELS.contains(((JetPrefixExpression) parent).getOperationReference().getReferencedNameElementType()); - if (isLabeled) { - parent = parent.getParent(); + } + else if (parent instanceof JetPrefixExpression) { + boolean isLabeled = JetPsiUtil.isLabeledExpression((JetPrefixExpression) parent); + if (!isLabeled) { + return false; } - } else { + parent = parent.getParent(); + } + else { return false; } } @@ -139,30 +143,27 @@ public class InlineCallResolverExtension implements CallResolverExtension { @NotNull ReceiverValue receiver, @Nullable JetExpression expression ) { - if (receiver.exists()) { - CallableDescriptor varDescriptor = null; - JetExpression receiverExpression = null; - if (receiver instanceof ExpressionReceiver) { - receiverExpression = ((ExpressionReceiver) receiver).getExpression(); - varDescriptor = getDescriptor(context, receiverExpression); - } - else if (receiver instanceof ExtensionReceiver) { - ExtensionReceiver extensionReceiver = (ExtensionReceiver) receiver; - CallableDescriptor extensionFunction = extensionReceiver.getDeclarationDescriptor(); + if (!receiver.exists()) return; - ReceiverParameterDescriptor receiverParameter = extensionFunction.getReceiverParameter(); - assert receiverParameter != null : "Extension function should have receiverParameterDescriptor: " + extensionFunction; - varDescriptor = receiverParameter; + CallableDescriptor varDescriptor = null; + JetExpression receiverExpression = null; + if (receiver instanceof ExpressionReceiver) { + receiverExpression = ((ExpressionReceiver) receiver).getExpression(); + varDescriptor = getDescriptor(context, receiverExpression); + } + else if (receiver instanceof ExtensionReceiver) { + ExtensionReceiver extensionReceiver = (ExtensionReceiver) receiver; + CallableDescriptor extension = extensionReceiver.getDeclarationDescriptor(); - receiverExpression = expression; - } + varDescriptor = extension.getReceiverParameter(); + assert varDescriptor != null : "Extension should have receiverParameterDescriptor: " + extension; - if (varDescriptor != null) { - if (inlinableParameters.contains(varDescriptor)) { - //check that it's invoke - checkFunctionCall(context, targetDescriptor, receiverExpression); - } - } + receiverExpression = expression; + } + + if (inlinableParameters.contains(varDescriptor)) { + //check that it's invoke or inlinable extension + checkFunctionCall(context, targetDescriptor, receiverExpression, false); } } @@ -175,27 +176,19 @@ public class InlineCallResolverExtension implements CallResolverExtension { return thisCall != null ? thisCall.getResultingDescriptor() : null; } - private void checkFunctionCall( - BasicCallResolutionContext context, - CallableDescriptor targetDescriptor, - JetExpression receiverExpresssion - ) { - checkFunctionCall(context, targetDescriptor, receiverExpresssion, false); - } - private void checkFunctionCall( BasicCallResolutionContext context, CallableDescriptor targetDescriptor, JetExpression receiverExpresssion, boolean isVararg ) { - boolean inlineCall = isInvokeOrInlineExtension(targetDescriptor); - if (!inlineCall || isVararg) { + boolean inlinableCall = isInvokeOrInlineExtension(targetDescriptor); + if (!inlinableCall || isVararg) { context.trace.report(Errors.USAGE_IS_NOT_INLINABLE.on(receiverExpresssion, receiverExpresssion, descriptor)); } } - private boolean isInlinableParameter(@NotNull CallableDescriptor descriptor) { + private static boolean isInlinableParameter(@NotNull CallableDescriptor descriptor) { JetType type = descriptor.getReturnType(); return type != null && KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type) && @@ -211,7 +204,7 @@ public class InlineCallResolverExtension implements CallResolverExtension { DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); boolean isInvoke = descriptor.getName().asString().equals("invoke") && containingDeclaration instanceof ClassDescriptor && - isExactFunctionOrExtensionFunctionType(((ClassDescriptor) containingDeclaration).getDefaultType()); + KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(((ClassDescriptor) containingDeclaration).getDefaultType()); return isInvoke || //or inline extension diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java index 02710e3d0c1..aa2217fcce6 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java @@ -44,8 +44,8 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz "This method should be invoced on inline function: " + descriptor; checkDefaults(descriptor, function, trace); - checkModality(descriptor, function, trace); - checkHashInlinableAndNullability(descriptor, function, trace); + checkNotVirual(descriptor, function, trace); + checkHasInlinableAndNullability(descriptor, function, trace); JetVisitorVoid visitor = new JetVisitorVoid() { @@ -90,7 +90,7 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz } } - private static void checkModality( + private static void checkNotVirual( @NotNull FunctionDescriptor functionDescriptor, @NotNull JetFunction function, @NotNull BindingTrace trace @@ -99,15 +99,15 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz return; } - DeclarationDescriptor declaration = functionDescriptor.getContainingDeclaration(); - if (declaration instanceof NamespaceDescriptor) { + if (functionDescriptor.getContainingDeclaration() instanceof NamespaceDescriptor) { return; } trace.report(Errors.DECLARATION_CANT_BE_INLINED.on(function)); } - private void checkHashInlinableAndNullability( + + private static void checkHasInlinableAndNullability( @NotNull FunctionDescriptor functionDescriptor, @NotNull JetFunction function, @NotNull BindingTrace trace @@ -116,12 +116,13 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz List parameters = functionDescriptor.getValueParameters(); int index = 0; for (ValueParameterDescriptor parameter : parameters) { - hasInlinable |= checkParameter(parameter, function.getValueParameters().get(index++), functionDescriptor, trace); + hasInlinable |= checkInlinableParameter(parameter, function.getValueParameters().get(index++), functionDescriptor, trace); } ReceiverParameterDescriptor receiverParameter = functionDescriptor.getReceiverParameter(); if (receiverParameter != null) { JetTypeReference receiver = function.getReceiverTypeRef(); - hasInlinable |= checkParameter(receiverParameter, receiver, functionDescriptor, trace); + assert receiver != null : "Descriptor has a receiver but psi doesn't " + function.getText(); + hasInlinable |= checkInlinableParameter(receiverParameter, receiver, functionDescriptor, trace); } if (!hasInlinable) { @@ -129,7 +130,7 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz } } - private static boolean checkParameter( + private static boolean checkInlinableParameter( @NotNull CallableDescriptor parameter, @NotNull JetElement expression, @NotNull FunctionDescriptor functionDescriptor, @@ -141,7 +142,8 @@ public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.Analyz if (!InlineUtil.hasNoinlineAnnotation(parameter)) { if (type.isNullable()) { trace.report(Errors.NULLABLE_INLINE_PARAMETER.on(expression, expression, functionDescriptor)); - } else { + } + else { return true; } }