diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java index 716357da6b8..025e21b53a4 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/Errors.java @@ -560,6 +560,13 @@ public interface Errors { DiagnosticFactory1 INACCESSIBLE_OUTER_CLASS_EXPRESSION = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 NESTED_CLASS_NOT_ALLOWED = DiagnosticFactory0.create(ERROR); + //Inline and inlinable parameters + DiagnosticFactory2 INVISIBLE_MEMBER_FROM_INLINE = DiagnosticFactory2.create(ERROR, CALL_ELEMENT); + DiagnosticFactory2 NOT_YET_SUPPORTED_IN_INLINE = DiagnosticFactory2.create(ERROR); + DiagnosticFactory1 NOTHING_TO_INLINE = DiagnosticFactory1.create(WARNING); + DiagnosticFactory2 USAGE_IS_NOT_INLINABLE = DiagnosticFactory2.create(ERROR); + DiagnosticFactory2 NULLABLE_INLINE_PARAMETER = DiagnosticFactory2.create(ERROR); + DiagnosticFactory0 DECLARATION_CANT_BE_INLINED = DiagnosticFactory0.create(ERROR); // Error sets ImmutableSet UNRESOLVED_REFERENCE_DIAGNOSTICS = ImmutableSet.of( diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java index d61518689d5..641210646f8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/diagnostics/rendering/DefaultErrorMessages.java @@ -33,6 +33,7 @@ import java.lang.reflect.Modifier; import java.util.Collection; import static org.jetbrains.jet.lang.diagnostics.Errors.*; +import static org.jetbrains.jet.lang.diagnostics.Errors.DECLARATION_CANT_BE_INLINED; import static org.jetbrains.jet.lang.diagnostics.rendering.Renderers.*; public class DefaultErrorMessages { @@ -471,6 +472,14 @@ public class DefaultErrorMessages { "''{0}'' is a member and an extension at the same time. References to such elements are not allowed", TO_STRING); MAP.put(CALLABLE_REFERENCE_LHS_NOT_A_CLASS, "Callable reference left-hand side cannot be a type parameter"); + //Inline + MAP.put(INVISIBLE_MEMBER_FROM_INLINE, "Cannot access effectively non-public-api ''{0}'' member from effectively public-api ''{1}''", TO_STRING, TO_STRING); + MAP.put(NOT_YET_SUPPORTED_IN_INLINE, "''{0}'' construction not yet supported in inline functions", ELEMENT_TEXT, TO_STRING); + MAP.put(DECLARATION_CANT_BE_INLINED, "Inline annotation could be present only on nonvirtual members (private or final)"); + MAP.put(NOTHING_TO_INLINE, "There are no parameters of Function types to be inlined in ''{0}''", TO_STRING); + MAP.put(USAGE_IS_NOT_INLINABLE, "Illegal usage of inline-parameter ''{0}'' in ''{1}''. Annotate the parameter with [noinline]", ELEMENT_TEXT, TO_STRING); + MAP.put(NULLABLE_INLINE_PARAMETER, "Inline-parameter ''{0}'' of ''{1}'' must not be nullable. Annotate the parameter with [noinline] or make not nullable", ELEMENT_TEXT, TO_STRING); + MAP.setImmutable(); for (Field field : Errors.class.getFields()) { diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/FunctionAnalyzerExtension.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/FunctionAnalyzerExtension.java index 30db4e14ba7..801dc794b0b 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/FunctionAnalyzerExtension.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/FunctionAnalyzerExtension.java @@ -20,9 +20,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; import org.jetbrains.jet.lang.psi.JetNamedFunction; +import org.jetbrains.jet.lang.resolve.extension.InlineAnalyzerExtension; import javax.inject.Inject; -import java.util.Collections; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -36,7 +37,7 @@ public class FunctionAnalyzerExtension { private BindingTrace trace; @Inject - public void setTrace(BindingTrace trace) { + public void setTrace(@NotNull BindingTrace trace) { this.trace = trace; } @@ -52,8 +53,13 @@ public class FunctionAnalyzerExtension { } @NotNull - private List getExtensions(@NotNull FunctionDescriptor functionDescriptor) { - return Collections.emptyList(); + private static List getExtensions(@NotNull FunctionDescriptor functionDescriptor) { + List list = new ArrayList(); + if (functionDescriptor instanceof SimpleFunctionDescriptor && + ((SimpleFunctionDescriptor) functionDescriptor).isInline()) { + list.add(InlineAnalyzerExtension.INSTANCE); + } + return list; } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverExtensionProvider.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverExtensionProvider.java index 43a97a873f3..4405603c85a 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverExtensionProvider.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/CallResolverExtensionProvider.java @@ -19,6 +19,7 @@ package org.jetbrains.jet.lang.resolve.calls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor; +import org.jetbrains.jet.lang.descriptors.SimpleFunctionDescriptor; import java.lang.ref.WeakReference; import java.util.*; @@ -69,8 +70,13 @@ public class CallResolverExtensionProvider { } // with default one at the end - private void appendExtensionsFor(DeclarationDescriptor declarationDescriptor, List extensions) { - // add your extensions here + private static void appendExtensionsFor(DeclarationDescriptor declarationDescriptor, List extensions) { + if (declarationDescriptor instanceof SimpleFunctionDescriptor) { + SimpleFunctionDescriptor descriptor = (SimpleFunctionDescriptor) declarationDescriptor; + if (descriptor.isInline()) { + extensions.add(new InlineCallResolverExtension(descriptor)); + } + } extensions.add(DEFAULT); } } 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 new file mode 100644 index 00000000000..1895a74ccd0 --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/calls/InlineCallResolverExtension.java @@ -0,0 +1,189 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.calls; + +import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jetbrains.jet.lang.descriptors.*; +import org.jetbrains.jet.lang.diagnostics.Errors; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingContext; +import org.jetbrains.jet.lang.resolve.calls.context.BasicCallResolutionContext; +import org.jetbrains.jet.lang.resolve.calls.model.ExpressionValueArgument; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; +import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; +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 java.util.*; + +public class InlineCallResolverExtension implements CallResolverExtension { + + private SimpleFunctionDescriptor descriptor; + + private Set inlinableParameters = new HashSet(); + + public InlineCallResolverExtension(@NotNull SimpleFunctionDescriptor descriptor) { + assert descriptor.isInline() : "This extension should be created only for inline functions but not " + descriptor; + + this.descriptor = descriptor; + Iterator iterator = descriptor.getValueParameters().iterator(); + while (iterator.hasNext()) { + ValueParameterDescriptor next = iterator.next(); + JetType type = next.getType(); + if (KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type)) { + //TODO check annotations + if (!InlineUtil.hasNoinlineAnnotation(next)) { + inlinableParameters.add(next); + } + } + } + + //add extension receiver as inlineable + ReceiverParameterDescriptor receiverParameter = descriptor.getReceiverParameter(); + if (receiverParameter != null) { + if (isExactFunctionOrExtensionFunctionType(receiverParameter.getType())) { + inlinableParameters.add(receiverParameter); + } + } + } + + @Override + 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 + checkCallWithReceiver(context, targetDescriptor, resolvedCall.getThisObject(), expression); + checkCallWithReceiver(context, targetDescriptor, resolvedCall.getReceiverArgument(), expression); + + boolean isInlinableClosure = inlinableParameters.contains(targetDescriptor); + if (isInlinableClosure) { + PsiElement parent = expression.getParent(); + if (parent instanceof JetValueArgument || parent instanceof JetBinaryExpression || parent instanceof JetDotQualifiedExpression || parent instanceof JetCallExpression) { + //check that it's in inlineable call would be in resolve call of parent + } else { + context.trace.report(Errors.USAGE_IS_NOT_INLINABLE.on(expression, expression, descriptor)); + } + } + + for (Map.Entry entry : resolvedCall.getValueArguments().entrySet()) { + ResolvedValueArgument value = entry.getValue(); + if (value instanceof ExpressionValueArgument) { + JetExpression jetExpression = ((ExpressionValueArgument) value).getValueArgument().getArgumentExpression(); + + DeclarationDescriptor varDescriptor = getDescriptor(context, jetExpression); + + if (varDescriptor != null && inlinableParameters.contains(varDescriptor)) { + checkFunctionCall(context, targetDescriptor, jetExpression); + } + } + + //TODO default and vararg + } + } + + private void checkCallWithReceiver( + @NotNull BasicCallResolutionContext context, + @NotNull CallableDescriptor targetDescriptor, + @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(); + + ReceiverParameterDescriptor receiverParameter = extensionFunction.getReceiverParameter(); + assert receiverParameter != null : "Extension function should have receiverParameterDescriptor: " + extensionFunction; + varDescriptor = receiverParameter; + + receiverExpression = expression; + } + + if (varDescriptor != null) { + if (inlinableParameters.contains(varDescriptor)) { + //check that it's invoke + checkFunctionCall(context, targetDescriptor, receiverExpression); + } + } + } + } + + @Nullable + private static CallableDescriptor getDescriptor( + @NotNull BasicCallResolutionContext context, + @NotNull JetExpression expression + ) { + ResolvedCall thisCall = context.trace.get(BindingContext.RESOLVED_CALL, expression); + return thisCall != null ? thisCall.getResultingDescriptor() : null; + } + + private void checkFunctionCall( + BasicCallResolutionContext context, + CallableDescriptor targetDescriptor, + JetExpression receiverExpresssion + ) { + if (!isInvokeOrInlineExtension(targetDescriptor)) { + context.trace.report(Errors.USAGE_IS_NOT_INLINABLE.on(receiverExpresssion, receiverExpresssion, descriptor)); + } + } + + + private boolean isExactFunctionOrExtensionFunctionType(@NotNull JetType type) { + return KotlinBuiltIns.getInstance().isExactFunctionOrExtensionFunctionType(type); + } + + private static boolean isInvokeOrInlineExtension(@NotNull CallableDescriptor descriptor) { + if (!(descriptor instanceof SimpleFunctionDescriptor)) { + return false; + } + + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + boolean isInvoke = descriptor.getName().asString().equals("invoke") && + containingDeclaration instanceof ClassDescriptor && + isExactFunctionOrExtensionFunctionType(((ClassDescriptor) containingDeclaration).getDefaultType()); + + return isInvoke || + //or inline extension + ((SimpleFunctionDescriptor) descriptor).isInline(); + } + + private void checkVisibility(){ + + } + + interface FunctionParameter { + + } +} 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 new file mode 100644 index 00000000000..b5ed78db47b --- /dev/null +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/extension/InlineAnalyzerExtension.java @@ -0,0 +1,65 @@ +/* + * Copyright 2010-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.jet.lang.resolve.extension; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.jet.lang.descriptors.FunctionDescriptor; +import org.jetbrains.jet.lang.diagnostics.Errors; +import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.resolve.BindingTrace; +import org.jetbrains.jet.lang.resolve.FunctionAnalyzerExtension; + +public class InlineAnalyzerExtension implements FunctionAnalyzerExtension.AnalyzerExtension { + + public static final InlineAnalyzerExtension INSTANCE = new InlineAnalyzerExtension(); + + private InlineAnalyzerExtension() { + + } + + @Override + public void process( + @NotNull final FunctionDescriptor descriptor, @NotNull JetNamedFunction function, @NotNull final BindingTrace trace + ) { + + JetVisitorVoid visitor = new JetVisitorVoid() { + + @Override + public void visitJetElement(@NotNull JetElement element) { + super.visitJetElement(element); + element.acceptChildren(this); + } + + @Override + public void visitClass(@NotNull JetClass klass) { + trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(klass, klass, descriptor)); + } + + @Override + public void visitObjectDeclaration(@NotNull JetObjectDeclaration declaration) { + trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(declaration, declaration, descriptor)); + } + + @Override + public void visitNamedFunction(@NotNull JetNamedFunction function) { + trace.report(Errors.NOT_YET_SUPPORTED_IN_INLINE.on(function, function, descriptor)); + } + }; + + function.acceptChildren(visitor); + } +} diff --git a/compiler/testData/diagnostics/tests/inline/capture.kt b/compiler/testData/diagnostics/tests/inline/capture.kt new file mode 100644 index 00000000000..1915a8c8d85 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/capture.kt @@ -0,0 +1,51 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE + +fun Function1.noInlineExt(p: Int) {} + +inline fun Function1.inlineExt2(p: Int) { + { + noInlineExt(11) + this.noInlineExt(11) + this noInlineExt 11 + this + }() +} + + +inline fun Function1.inlineExt() { + { + inlineExt2(1) + this.inlineExt2(1) + this inlineExt2 1 + this(11) + }() +} + +inline fun inlineFunWithInvoke(s: (p: Int) -> Unit) { + { + s(11) + s.invoke(11) + s invoke 11 + }() +} + +inline fun inlineFunWithInvokeNonInline(noinline s: (p: Int) -> Unit) { + { + s(11) + s.invoke(11) + s invoke 11 + }() +} + + +inline fun testExtension(s: (p: Int) -> Unit) { + { + s.inlineExt() + } () +} + +inline fun inlineFunWrongExtension(s: (p: Int) -> Unit) { + { + s.noInlineExt(11) + } () +} diff --git a/compiler/testData/diagnostics/tests/inline/constructor.kt b/compiler/testData/diagnostics/tests/inline/constructor.kt new file mode 100644 index 00000000000..5a6b2b35290 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/constructor.kt @@ -0,0 +1,7 @@ +class Z(s: (Int) -> Int) { + +} + +public inline fun test(s : (Int) -> Int) { + Z(s) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/extensionOnFunction.kt b/compiler/testData/diagnostics/tests/inline/extensionOnFunction.kt new file mode 100644 index 00000000000..429d33a3ac8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/extensionOnFunction.kt @@ -0,0 +1,28 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE + +fun Function1.noInlineExt(p: Int) {} + +inline fun Function1.inlineExt2(p: Int) { + noInlineExt(11) + this.noInlineExt(11) + this noInlineExt 11 + this +} + +inline fun Function1.inlineExt() { + inlineExt2(1) + this.inlineExt2(1) + this inlineExt2 1 +} + +inline fun testExtension(s: (p: Int) -> Unit) { + s.inlineExt() +} + +inline fun inlineFunWrongExtension(s: (p: Int) -> Unit) { + s.noInlineExt(11) +} + +inline fun inlineFunNoInline(noinline s: (p: Int) -> Unit) { + s.noInlineExt(11) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/functions.kt b/compiler/testData/diagnostics/tests/inline/functions.kt new file mode 100644 index 00000000000..9956b63ba57 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/functions.kt @@ -0,0 +1,12 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -UNNECESSARY_NOT_NULL_ASSERTION -UNNECESSARY_SAFE_CALL + +fun getFun(s: (p: Int) -> Unit): Function1 = {11} + +inline fun getInlineFun(s: (p: Int) -> Unit): Function1 = {11} + +inline fun testExtension(s: (p: Int) -> Unit) { + getFun(s).invoke(10) + getInlineFun(s).invoke(10) + getInlineFun(s)!!.invoke(10) + getInlineFun(s)?.invoke(10) +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/invoke.kt b/compiler/testData/diagnostics/tests/inline/invoke.kt new file mode 100644 index 00000000000..d706fd56e0f --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/invoke.kt @@ -0,0 +1,26 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE + +inline fun inlineFunWithInvoke(s: (p: Int) -> Unit, ext: Int.(p: Int) -> Unit) { + s(11) + s.invoke(11) + s invoke 11 + + 11.ext(11) + 11 ext 11 +} + +inline fun inlineFunWithInvokeNonInline(noinline s: (p: Int) -> Unit, ext: Int.(p: Int) -> Unit) { + s(11) + s.invoke(11) + s invoke 11 + + 11.ext(11) + 11 ext 11 +} + +inline fun Function1.inlineExt() { + invoke(11) + this.invoke(11) + this invoke 11 + this(11) +} diff --git a/compiler/testData/diagnostics/tests/inline/propagation.kt b/compiler/testData/diagnostics/tests/inline/propagation.kt new file mode 100644 index 00000000000..239172d8043 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/propagation.kt @@ -0,0 +1,37 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE + +inline fun inlineFunWithInvoke(s: (p: Int) -> Unit, ext: Int.(p: Int) -> Unit) { + subInline(s, ext) + subNoInline(s, ext) +} + +inline fun inlineFunWithInvokeClosure(s: (p: Int) -> Unit, ext: Int.(p: Int) -> Unit) { + subInline({(p: Int) -> s(p)}, {Int.(p:Int) -> this.ext(p)}) + subNoInline({(p: Int) -> s(p)}, {Int.(p:Int) -> this.ext(p)}) +} + +//No inline +inline fun inlineFunWithInvokeNonInline(noinline s: (p: Int) -> Unit, noinline ext: Int.(p: Int) -> Unit) { + subInline(s, ext) + subNoInline(s, ext) +} + +inline fun inlineFunWithInvokeClosureNoinline(noinline s: (p: Int) -> Unit, noinline ext: Int.(p: Int) -> Unit) { + subInline({(p: Int) -> s(p)}, {Int.(p:Int) -> this.ext(p)}) + subNoInline({(p: Int) -> s(p)}, {Int.(p:Int) -> this.ext(p)}) +} + +//ext function +inline fun Function1.inlineExt(ext: Int.(p: Int) -> Unit) { + subInline(this, ext) + subNoInline(this, ext) +} + +inline fun Function1.inlineExtWithClosure(ext: Int.(p: Int) -> Unit) { + subInline({(p: Int) -> this(p)}, {Int.(p:Int) -> this.ext(p)}) + subNoInline({(p: Int) -> this(p)}, {Int.(p:Int) -> this.ext(p)}) +} + +inline fun subInline(s: (p: Int) -> Unit, ext: Int.(p: Int) -> Unit) {} + +fun subNoInline(s: (p: Int) -> Unit, ext: Int.(p: Int) -> Unit) {} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/returns.kt b/compiler/testData/diagnostics/tests/inline/returns.kt new file mode 100644 index 00000000000..d61831d0d03 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/returns.kt @@ -0,0 +1,20 @@ +inline fun inlineFun(s: (p: Int) -> Unit) : (p: Int) -> Unit { + return s +} + +inline fun inlineFun2(s: (p: Int) -> Unit) : (p: Int) -> Unit = s + + +inline fun inlineFunWithExt(ext: Int.(p: Int) -> Unit) : Int.(p: Int) -> Unit { + return ext +} + +inline fun inlineFunWithExt2(ext: Int.(p: Int) -> Unit) : Int.(p: Int) -> Unit = ext + + + +inline fun Function1.inlineExt(): Function1 { + return this +} + +inline fun Function1.inlineExt2(): Function1 = this \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.kt b/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.kt new file mode 100644 index 00000000000..37ba68a8a38 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/unsupportedConstruction.kt @@ -0,0 +1,26 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE + +inline fun unsupported() { + + class A { + fun a() { + class AInner {} + } + } + + object B{ + object BInner {} + } + + val s = object { + fun a() { + val sInner = object { + fun aInner() {} + } + } + } + + fun local() { + fun localInner() {} + } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/inline/wrongUsage.kt b/compiler/testData/diagnostics/tests/inline/wrongUsage.kt new file mode 100644 index 00000000000..8b7350d44a1 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/wrongUsage.kt @@ -0,0 +1,55 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE -UNUSED_VALUE + +inline fun inlineFunWrongUsage(s: (p: Int) -> Unit) { + s + + if (true) s else 0 + + var c = s + c = s +} + +inline fun inlineFunWrongUsageExt(ext: Int.(p: Int) -> Unit) { + ext + + if (true) ext else 0 + + var c = ext + c = ext +} + +inline fun inlineFunWrongUsageInClosure(s: (p: Int) -> Unit) { + { + s + + if (true) s else 0 + + var c = s + c = s + }() +} + +inline fun inlineFunWrongUsageInClosureExt(ext: Int.(p: Int) -> Unit) { + { + ext + + if (true) ext else 0 + + var c = ext + c = ext + }() +} + +inline fun inlineFunNoInline(noinline s: (p: Int) -> Unit) { + s + if (true) s else 0 + var c = s + c = s +} + +inline fun inlineFunNoInline(noinline ext: Int.(p: Int) -> Unit) { + ext + if (true) ext else 0 + var c = ext + c = ext +} diff --git a/compiler/testData/diagnostics/tests/inline/wrongUsage2.kt b/compiler/testData/diagnostics/tests/inline/wrongUsage2.kt new file mode 100644 index 00000000000..00b6d2d0488 --- /dev/null +++ b/compiler/testData/diagnostics/tests/inline/wrongUsage2.kt @@ -0,0 +1,24 @@ +// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE -UNNECESSARY_SAFE_CALL -UNNECESSARY_NOT_NULL_ASSERTION + +public inline fun assertNot(message: String, block: ()-> Boolean) {} + +public inline fun assertNot(block: ()-> Boolean) : Unit = assertNot(block.toString(), block) + + +public fun callable(action: ()-> T) { + +} + +public inline fun String.submit(action: ()->T) { + callable(action) +} + +public inline fun Function1.submit() { + this?.invoke(11) + this!!.invoke(11) +} + +public inline fun submit(action: Function1) { + action?.invoke(10) + action!!.invoke(10) +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java index f986037fc39..2cf65bf7d8a 100644 --- a/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/checkers/JetDiagnosticsTestGenerated.java @@ -33,7 +33,7 @@ import org.jetbrains.jet.checkers.AbstractDiagnosticsTestWithEagerResolve; @InnerTestClasses({JetDiagnosticsTestGenerated.Tests.class, JetDiagnosticsTestGenerated.Script.class}) public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEagerResolve { @TestMetadata("compiler/testData/diagnostics/tests") - @InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.CallableReference.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ClassObjects.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.DelegatedProperty.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Numbers.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Suppress.class, Tests.ThisAndSuper.class, Tests.Varargs.class, Tests.When.class}) + @InnerTestClasses({Tests.Annotations.class, Tests.BackingField.class, Tests.CallableReference.class, Tests.Cast.class, Tests.CheckArguments.class, Tests.ClassObjects.class, Tests.ControlFlowAnalysis.class, Tests.ControlStructures.class, Tests.DataClasses.class, Tests.DataFlow.class, Tests.DataFlowInfoTraversal.class, Tests.DeclarationChecks.class, Tests.DelegatedProperty.class, Tests.Deparenthesize.class, Tests.Enum.class, Tests.Extensions.class, Tests.FunctionLiterals.class, Tests.Generics.class, Tests.IncompleteCode.class, Tests.Inference.class, Tests.Infos.class, Tests.Inline.class, Tests.Inner.class, Tests.J_k.class, Tests.Jdk_annotations.class, Tests.Library.class, Tests.NullabilityAndAutoCasts.class, Tests.NullableTypes.class, Tests.Numbers.class, Tests.Objects.class, Tests.OperatorsOverloading.class, Tests.Overload.class, Tests.Override.class, Tests.Recovery.class, Tests.Redeclarations.class, Tests.Regressions.class, Tests.Resolve.class, Tests.Scopes.class, Tests.SenselessComparison.class, Tests.Shadowing.class, Tests.SmartCasts.class, Tests.Substitutions.class, Tests.Subtyping.class, Tests.Suppress.class, Tests.ThisAndSuper.class, Tests.Varargs.class, Tests.When.class}) public static class Tests extends AbstractDiagnosticsTestWithEagerResolve { @TestMetadata("Abstract.kt") public void testAbstract() throws Exception { @@ -3750,6 +3750,64 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage } + @TestMetadata("compiler/testData/diagnostics/tests/inline") + public static class Inline extends AbstractDiagnosticsTestWithEagerResolve { + public void testAllFilesPresentInInline() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/diagnostics/tests/inline"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("capture.kt") + public void testCapture() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/capture.kt"); + } + + @TestMetadata("constructor.kt") + public void testConstructor() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/constructor.kt"); + } + + @TestMetadata("extensionOnFunction.kt") + public void testExtensionOnFunction() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/extensionOnFunction.kt"); + } + + @TestMetadata("functions.kt") + public void testFunctions() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/functions.kt"); + } + + @TestMetadata("invoke.kt") + public void testInvoke() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/invoke.kt"); + } + + @TestMetadata("propagation.kt") + public void testPropagation() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/propagation.kt"); + } + + @TestMetadata("returns.kt") + public void testReturns() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/returns.kt"); + } + + @TestMetadata("unsupportedConstruction.kt") + public void testUnsupportedConstruction() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/unsupportedConstruction.kt"); + } + + @TestMetadata("wrongUsage.kt") + public void testWrongUsage() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/wrongUsage.kt"); + } + + @TestMetadata("wrongUsage2.kt") + public void testWrongUsage2() throws Exception { + doTest("compiler/testData/diagnostics/tests/inline/wrongUsage2.kt"); + } + + } + @TestMetadata("compiler/testData/diagnostics/tests/inner") @InnerTestClasses({Inner.QualifiedExpression.class}) public static class Inner extends AbstractDiagnosticsTestWithEagerResolve { @@ -6255,6 +6313,7 @@ public class JetDiagnosticsTestGenerated extends AbstractDiagnosticsTestWithEage suite.addTest(IncompleteCode.innerSuite()); suite.addTest(Inference.innerSuite()); suite.addTestSuite(Infos.class); + suite.addTestSuite(Inline.class); suite.addTest(Inner.innerSuite()); suite.addTestSuite(J_k.class); suite.addTest(Jdk_annotations.innerSuite()); diff --git a/core/descriptors/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExtensionReceiver.java b/core/descriptors/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExtensionReceiver.java index c85273d131b..15983c34127 100644 --- a/core/descriptors/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExtensionReceiver.java +++ b/core/descriptors/src/org/jetbrains/jet/lang/resolve/scopes/receivers/ExtensionReceiver.java @@ -32,7 +32,7 @@ public class ExtensionReceiver extends AbstractReceiverValue implements ThisRece @NotNull @Override - public DeclarationDescriptor getDeclarationDescriptor() { + public CallableDescriptor getDeclarationDescriptor() { return descriptor; }