2015-08-01 8 views
0

При работе над проектом с QtJambi в качестве инструментария GUI я пытался закодировать библиотеку, чтобы упростить подключение сигналов и слотов. Я нашел следующую проблему.Функция встроенной линии Kotlin не работает должным образом

Вот мой код:

inline fun QSignalEmitter.Signal0.connect(
     inlineOptions(InlineOption.ONLY_LOCAL_RETURN) action:() -> Unit) { 
    connect(object { 
     fun execute() { 
      action() 
     } 
    }, "execute()") 
} 

inline fun <reified A> QSignalEmitter.Signal1<A>.connect(
     inlineOptions(InlineOption.ONLY_LOCAL_RETURN) action: (A) -> Unit) { 
    connect(object { 
     fun execute(a: A) { 
      action(a) 
     } 
    }, "execute(" + javaClass<A>().getCanonicalName() + ")") 
} 

Это работает для первого подключения функции, когда неты общих параметров ожидаемых. Но для второго подключения функции, когда я делаю что-то вроде:

QCheckBox().toggled.connect({ print(it) }) 

я получаю следующее сообщение об ошибке:

Exception in thread "main" com.trolltech.qt.QNoSuchSlotException: 

Could not find slot with signature: execute(java.lang.Boolean) 
Possible matching methods: 
    com.TestPackage$Test$f1214d02$main$$inlined$connect$1.execute(java.lang.Object) 

    at com.trolltech.qt.QSignalEmitter$AbstractSignal.connect(QSignalEmitter.java:72) 
    at com.trolltech.qt.QSignalEmitter$AbstractSignal.connect(QSignalEmitter.java:132) 
    at com.TestPackage$Test$f1214d02.main(Test.kt:9) 
    at com.TestPackage.main(Test.kt:1) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:483) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134) 

Какова возможная причина и как я могу получить вокруг него?

Редактирование: Пример использования

inline fun <reified A> QSignalEmitter.Signal1<A>.connect(noinline action: (A) -> Unit) { 
    connect(action, "invoke(${javaClass<A>()})") 
} 

fun main(args: Array<String>) { 
    QApplication.initialize(args) 

    val widget = QWidget() 
    val button = QPushButton("Say Hello") 
    button.clicked.connect { 
     println("Hello World") 
    } 
    val layout = QFormLayout(widget) 
    layout.addWidget(button) 

    widget.show() 
    QApplication.execStatic() 
} 

Котлин Bytecode

// ================_DefaultPackage$QtExtensions$7d5c0ac6.class ================= 
// class version 50.0 (50) 
// access flags 0x11 
public final class _DefaultPackage$QtExtensions$7d5c0ac6 { 


    // access flags 0x19 
    // signature <A:Ljava/lang/Object;>(Lcom/trolltech/qt/QSignalEmitter$Signal1<TA;>;Lkotlin/jvm/functions/Function1<-TA;+Lkotlin/Unit;>;)V 
    // declaration: void connect<A>(com.trolltech.qt.QSignalEmitter$Signal1<A>, kotlin.jvm.functions.Function1<? super A, ? extends kotlin.Unit>) 
    public final static connect(Lcom/trolltech/qt/QSignalEmitter$Signal1;Lkotlin/jvm/functions/Function1;)V 
    @Lkotlin/inline;() // invisible 
    @Ljet/runtime/typeinfo/JetValueParameter;(name="$receiver") // parameter 0 
    @Ljet/runtime/typeinfo/JetValueParameter;(name="action") // parameter 1 
    @Lkotlin/noinline;() // invisible, parameter 1 
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 1 
    L0 
    L1 
    ALOAD 0 
    LDC "$receiver" 
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V 
    ALOAD 1 
    LDC "action" 
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V 
    L2 
    LINENUMBER 9 L2 
    ALOAD 0 
    ALOAD 1 
    NEW java/lang/StringBuilder 
     DUP 
    INVOKESPECIAL java/lang/StringBuilder.<init>()V 
     LDC "invoke(" 
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; 
    LDC "A" 
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.reifyJavaClass (Ljava/lang/String;)V 
    LDC Ljava/lang/Object;.class 
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder; 
    LDC ")" 
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; 
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; 
    INVOKEVIRTUAL com/trolltech/qt/QSignalEmitter$Signal1.connect (Ljava/lang/Object;Ljava/lang/String;)V 
    L3 
    LINENUMBER 10 L3 
    RETURN 
    L4 
    LOCALVARIABLE $receiver Lcom/trolltech/qt/QSignalEmitter$Signal1; L0 L4 0 
    LOCALVARIABLE action Lkotlin/jvm/functions/Function1; L0 L4 1 
    MAXSTACK = 4 
    MAXLOCALS = 2 

    // access flags 0x19 
    public final static main([Ljava/lang/String;)V 
    @Ljet/runtime/typeinfo/JetValueParameter;(name="args") // parameter 0 
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0 
    L0 
    L1 
    ALOAD 0 
    LDC "args" 
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V 
    L2 
    LINENUMBER 13 L2 
    ALOAD 0 
    INVOKESTATIC com/trolltech/qt/gui/QApplication.initialize ([Ljava/lang/String;)V 
    L3 
    LINENUMBER 15 L3 
    NEW com/trolltech/qt/gui/QWidget 
     DUP 
    INVOKESPECIAL com/trolltech/qt/gui/QWidget.<init>()V 
     ASTORE 1 
    L4 
    L5 
    LINENUMBER 16 L5 
    NEW com/trolltech/qt/gui/QPushButton 
     DUP 
    LDC "Say Hello" 
    INVOKESPECIAL com/trolltech/qt/gui/QPushButton.<init> (Ljava/lang/String;)V 
    ASTORE 2 
    L6 
    L7 
    LINENUMBER 17 L7 
    ALOAD 2 
    CHECKCAST com/trolltech/qt/gui/QAbstractButton 
     GETFIELD com/trolltech/qt/gui/QAbstractButton.clicked : Lcom/trolltech/qt/QSignalEmitter$Signal1; 
    ASTORE 3 
    GETSTATIC _DefaultPackage$QtExtensions$7d5c0ac6$main$1.INSTANCE$ : L_DefaultPackage$QtExtensions$7d5c0ac6$main$1; 
    CHECKCAST kotlin/jvm/functions/Function1 
     ASTORE 4 
    NOP 
    L8 
    L9 
    L10 
    LINENUMBER 9 L10 
    ALOAD 3 
    ALOAD 4 
    NEW java/lang/StringBuilder 
     DUP 
    INVOKESPECIAL java/lang/StringBuilder.<init>()V 
     LDC "invoke(" 
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; 
    LDC Ljava/lang/Boolean;.class 
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/Object;)Ljava/lang/StringBuilder; 
    LDC ")" 
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder; 
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; 
    INVOKEVIRTUAL com/trolltech/qt/QSignalEmitter$Signal1.connect (Ljava/lang/Object;Ljava/lang/String;)V 
    L11 
    LINENUMBER 10 L11 
    L12 
    L13 
    L14 
    LINENUMBER 20 L14 
    NEW com/trolltech/qt/gui/QFormLayout 
     DUP 
    ALOAD 1 
    INVOKESPECIAL com/trolltech/qt/gui/QFormLayout.<init> (Lcom/trolltech/qt/gui/QWidget;)V 
    ASTORE 3 
    L15 
    L16 
    LINENUMBER 21 L16 
    ALOAD 3 
    ALOAD 2 
    CHECKCAST com/trolltech/qt/gui/QWidget 
     INVOKEVIRTUAL com/trolltech/qt/gui/QFormLayout.addWidget (Lcom/trolltech/qt/gui/QWidget;)V 
    L17 
    LINENUMBER 23 L17 
    ALOAD 1 
    INVOKEVIRTUAL com/trolltech/qt/gui/QWidget.show()V 
     L18 
    LINENUMBER 24 L18 
    INVOKESTATIC com/trolltech/qt/gui/QApplication.execStatic()I 
     POP 
    L19 
    LINENUMBER 25 L19 
    RETURN 
    L20 
    LOCALVARIABLE $receiver Lcom/trolltech/qt/QSignalEmitter$Signal1; L8 L12 3 
    LOCALVARIABLE action Lkotlin/jvm/functions/Function1; L8 L12 4 
    LOCALVARIABLE layout Lcom/trolltech/qt/gui/QFormLayout; L15 L20 3 
    LOCALVARIABLE button Lcom/trolltech/qt/gui/QPushButton; L6 L20 2 
    LOCALVARIABLE widget Lcom/trolltech/qt/gui/QWidget; L4 L20 1 
    LOCALVARIABLE args [Ljava/lang/String; L0 L20 0 
    MAXSTACK = 4 
    MAXLOCALS = 5 

    @Lkotlin/jvm/internal/KotlinSyntheticClass;(abiVersion=23, kind=Lkotlin/jvm/internal/KotlinSyntheticClass$Kind;.PACKAGE_PART) 
    // access flags 0x19 
    public final static INNERCLASS _DefaultPackage$QtExtensions$7d5c0ac6$main$1 null null 
    // compiled from: QtExtensions.kt 
    // debug info: SMAP 
    QtExtensions.kt 
    Kotlin 
    *S Kotlin 
    *F 
     + 1 QtExtensions.kt 
    _DefaultPackage 
    *L 
     1#1,25:1 
    *E 

} 


// ================_DefaultPackage$QtExtensions$7d5c0ac6$main$1.class ================= 
// class version 50.0 (50) 
// access flags 0x30 
// signature Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function1<Ljava/lang/Boolean;Lkotlin/Unit;>; 
// declaration: _DefaultPackage$QtExtensions$7d5c0ac6$main$1 extends kotlin.jvm.internal.Lambda implements kotlin.jvm.functions.Function1<java.lang.Boolean, kotlin.Unit> 
final class _DefaultPackage$QtExtensions$7d5c0ac6$main$1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function1 { 


    // access flags 0x41 
    public bridge invoke(Ljava/lang/Object;)Ljava/lang/Object; 
    ALOAD 0 
    ALOAD 1 
    CHECKCAST java/lang/Boolean 
     INVOKEVIRTUAL _DefaultPackage$QtExtensions$7d5c0ac6$main$1.invoke (Ljava/lang/Boolean;)V 
    GETSTATIC kotlin/Unit.INSTANCE$ : Lkotlin/Unit; 
    ARETURN 
    MAXSTACK = 2 
    MAXLOCALS = 2 

    // access flags 0x11 
    public final invoke(Ljava/lang/Boolean;)V 
    @Ljet/runtime/typeinfo/JetValueParameter;(name="it") // parameter 0 
    L0 
    L1 
    L2 
    LINENUMBER 18 L2 
     LDC "Hello World" 
    INVOKESTATIC kotlin/io/IoPackage.println (Ljava/lang/Object;)V 
    L3 
    RETURN 
    L4 
    LOCALVARIABLE this L_DefaultPackage$QtExtensions$7d5c0ac6$main$1; L0 L4 0 
    LOCALVARIABLE it Ljava/lang/Boolean; L0 L4 1 
    MAXSTACK = 1 
    MAXLOCALS = 2 

    // access flags 0x0 
    <init>()V 
     ALOAD 0 
     ICONST_1 
     INVOKESPECIAL kotlin/jvm/internal/Lambda.<init> (I)V 
     RETURN 
     MAXSTACK = 2 
     MAXLOCALS = 1 

     // access flags 0x1008 
     static synthetic <clinit>()V 
      NEW _DefaultPackage$QtExtensions$7d5c0ac6$main$1 
      DUP 
      INVOKESPECIAL _DefaultPackage$QtExtensions$7d5c0ac6$main$1.<init>()V 
       PUTSTATIC _DefaultPackage$QtExtensions$7d5c0ac6$main$1.INSTANCE$ : L_DefaultPackage$QtExtensions$7d5c0ac6$main$1; 
       RETURN 
       MAXSTACK = 2 
       MAXLOCALS = 0 

       // access flags 0x19 
       public final static L_DefaultPackage$QtExtensions$7d5c0ac6$main$1; INSTANCE$ 

       @Lkotlin/jvm/internal/KotlinSyntheticClass;(abiVersion=23, kind=Lkotlin/jvm/internal/KotlinSyntheticClass$Kind;.ANONYMOUS_FUNCTION) 
       OUTERCLASS _DefaultPackage$QtExtensions$7d5c0ac6 main ([Ljava/lang/String;)V 
       // access flags 0x19 
       public final static INNERCLASS _DefaultPackage$QtExtensions$7d5c0ac6$main$1 null null 
       // compiled from: QtExtensions.kt 
       } 


       // ================_DefaultPackage.class ================= 
       // class version 50.0 (50) 
       // access flags 0x11 
       public final class _DefaultPackage { 


       // access flags 0x8 
       static <clinit>()V 
        LDC L_DefaultPackage;.class 
        INVOKESTATIC kotlin/jvm/internal/Reflection.createKotlinPackage (Ljava/lang/Class;)Lkotlin/reflect/KPackage; 
        PUTSTATIC _DefaultPackage.$kotlinPackage : Lkotlin/reflect/KPackage; 
        RETURN 
        MAXSTACK = 1 
        MAXLOCALS = 0 

        // access flags 0x1019 
        public final static synthetic Lkotlin/reflect/KPackage; $kotlinPackage 

        // access flags 0x19 
        public final static main([Ljava/lang/String;)V 
        @Ljet/runtime/typeinfo/JetValueParameter;(name="args") // parameter 0 
        @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0 
        L0 
        L1 
        LINENUMBER 1 L1 
        ALOAD 0 
        INVOKESTATIC _DefaultPackage$QtExtensions$7d5c0ac6.main ([Ljava/lang/String;)V 
        RETURN 
        L2 
        LOCALVARIABLE args [Ljava/lang/String; L0 L2 0 
        MAXSTACK = 1 
        MAXLOCALS = 1 

        // access flags 0x19 
        // signature <A:Ljava/lang/Object;>(Lcom/trolltech/qt/QSignalEmitter$Signal1<TA;>;Lkotlin/jvm/functions/Function1<-TA;+Lkotlin/Unit;>;)V 
         // declaration: void connect<A>(com.trolltech.qt.QSignalEmitter$Signal1<A>, kotlin.jvm.functions.Function1<? super A, ? extends kotlin.Unit>) 
          public final static connect(Lcom/trolltech/qt/QSignalEmitter$Signal1;Lkotlin/jvm/functions/Function1;)V 
          @Lkotlin/inline;() // invisible 
          @Ljet/runtime/typeinfo/JetValueParameter;(name="$receiver") // parameter 0 
          @Ljet/runtime/typeinfo/JetValueParameter;(name="action") // parameter 1 
          @Lkotlin/noinline;() // invisible, parameter 1 
          @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 1 
          L0 
          L1 
          LINENUMBER 1 L1 
          ALOAD 0 
          ALOAD 1 
          INVOKESTATIC _DefaultPackage$QtExtensions$7d5c0ac6.connect (Lcom/trolltech/qt/QSignalEmitter$Signal1;Lkotlin/jvm/functions/Function1;)V 
          RETURN 
          L2 
          LOCALVARIABLE $receiver Lcom/trolltech/qt/QSignalEmitter$Signal1; L0 L2 0 
          LOCALVARIABLE action Lkotlin/jvm/functions/Function1; L0 L2 1 
          MAXSTACK = 2 
          MAXLOCALS = 2 

          @Lkotlin/jvm/internal/KotlinPackage;(abiVersion=23, data={"V\u0004)!Q.Y5o\u0015\u0011\u0009'oZ:\u000b\u000b\u0005\u0013(/Y=\u000b\r-|G\u000f\\5o\u0015\u0019\u0019FO]5oO*!QK\\5u\u0015\u0011Q\u0017M^1\u000b\u00091\u000cgn\u001a\u0006&?\u0012+g-Y;miB\u000b7m[1hK\u0012\nF/\u0012=uK:\u001c\u0018n\u001c8tI]\"Wg\u0019\u0019bGZR\u0011!\u0011\u0006\u0004\u0003:L(bB*jO:\u000cG.\r\u0006\u000f#NKwM\\1m\u000b6LG\u000f^3s\u0015\r\u0019w.\u001c\u0006\niJ|G\u000e\u001c;fG\"T!!\u001d;\u000b\u000f\r|gN\\3di*1\u0011m\u0019;j_:T\u0011BR;oGRLwN\\\u0019\u000b-E\u001b\u0016n\u001a8bY\u0016k\u0017\u000e\u001e;fe\u0012\u001a\u0016n\u001a8bYFR1A\u001b<n\u0015%1WO\\2uS>t7\u000f\u001e\u0006\u0003!\rQa\u0001\u0003\u0001\u0011\u0005a\u0001!B\u0002\u0005\u0001!\u0011A\u0002A\u0003\u0004\u0009\u0001A)\u0001\u0004\u0001\u0006\u0003!\u0019QA\u0001\u0003\u0003\u0011\u000f)!\u0001\"\u0002\u0009\u0005\u0015\u0019A\u0001\u0001\u0005\u0006\u0019\u0001)\u0011\u0001#\u0004\u0006\u0005\u0011!\u0001bB\u0003\u0003\u0009\u0013Ay!B\u0002\u0005\u000b!1A\u0002A\u0003\u0004\u0009\u0017AY\u0001\u0004\u0001\u0006\u0007\u0011\u0001\u0001\"\u0003\u0007\u0001\u000b\u0009!Q\u0001c\u0005\u0006\u0005\u0011\u0001\u0001BC\u0003\u0003\u0009\u001fA)\"\u0002\u0002\u0005\u0011!IQ1\u0007\u0003\u00011\u0001i*\u0002\u0002\u0001\u0009\u000251Q!\u0001E\u0001\u0013\rI!!B\u0001\u0009\u0003A\u001b\u0001!\u0009\u0002\u0006\u0003!\r\u0011k\u0001\u0004\u0005\u0001%\u0009A\u0001A\u0007\u0003\u0011\ra\u0009\u0001W\u0002\u0005\u000b?\"\u0009!E\u0004\u0005\u0001!%A\u0012A\u000b\u0004\u000b\u0005A9\u0001$\u0001\u0016\u000f\u0015\u0009\u0001BB\u0005\u0005\u0013\r)!\u0001\"\u0001\u0009\u0001aAQt\u0004C\u0001\u0011#i1\"B\u0001\u0009\u000e%!\u0011bA\u0003\u0003\u0009\u0003A\u0001!C\u0002\n\u0005\u0015\u0009\u00012\u0001)\u0004\u0002\u0005\u0012Q!\u0001E\u0002#\u000e9A\u0001C\u0005\u0002\u0009\u0001i\u0011\u0001C\u0004\u000e\u0003!E\u0001l\u0001\u0003"}) 
          // compiled from: QtExtensions.kt 
          } 

ответ

1

Классы внутри инлайн функции не специализируются так execute вашего объекта в байткод имеет следующую подпись execute(java.lang.Object). Но javaClass<A>() уточните и в connect вы найдете другую подпись: execute(java.lang.Boolean).

Попробуйте написать:

fun <A> QSignalEmitter.Signal1<A>.connect(action: (A) -> Unit) { 
    connect(action, "invoke(java.lang.Object)") 
} 

раствор 2:

inline fun <reified A> S<A>.connect(noinline action: (A) -> Unit) { 
    connect(action, "invoke(${javaClass<A>()})") 
} 
+0

Спасибо большое, что работал. Эта тема специализации документирована где-то? – ClinPath

+0

Дополнительная информация Вы можете найти в [ссылке] (http://kotlinlang.org/docs/reference/inline-functions.html#reified-type-parameters) и [spec] (https://github.com/JetBrains/ kotlin/blob/master/spec-docs/reified-type-parameters.md) – bashor

+0

Я посмотрел на сгенерированный код и понял, что о специализации класса я ошибался. Компилятор слегка специализирует классы, но, например, он не создает мосты. Я создаю [issue] (https://youtrack.jetbrains.com/issue/KT-8709) об этом. Не стесняйтесь голосовать или звать, чтобы получать обновления. – bashor