Обновление: у меня проблемы с воспроизведением ошибки opCmp, особенно в примерах игрушек, но я думаю, что выяснил, что происходит.
Кажется, что создание анонимных внутренних классов, которые наследуют интерфейсы внутри анонимных функций, является ошибочным (см. Рисунок). В частности, анонимные классы и не очень хорошо себя ведут по отношению к виртуальным функциям. Даже с определенным opCmp у меня были ошибки с toString и конструкторами по умолчанию, и были члены, которые просто ничего не делают (но не выдают или выдают ошибку при вызове). __traits(allMembers, MyInterface)
возвращает ожидаемую информацию, как и __traits(allMembers, typeof(anonInstance))
, но вызов часто встречающихся участников не работает. Weird.
Но если я изменю интерфейс на класс с абстрактными методами, ошибка opCmp разрешается, анонимный класс ведет себя как ожидалось и т. Д. Я не знаю много о компиляторах, но я думаю, что во время компиляции создается таблица символов, которая сопоставляет имена виртуальных функций с адресами памяти, хранящимися в vtbl. Я думаю, что происходит то, что генерируемая карта меняется при возврате анонимного класса, полученного из интерфейса. Это возможно, потому что интерфейсы поддерживают множественное наследование и поэтому не могут предписывать абсолютное отображение vtbl. Классы, однако, могут потребовать, чтобы все наследники придерживались одной и той же схемы отображения (я не знаю, делают ли они, но могли бы), и поэтому анонимные классы не могут получить другое отображение.
Опять же, я действительно не уверен, но кажется, что это соответствует симптому, вызывается opCmp, хотя я нигде не использовал его. Я не думаю, что именно opCmp был проблемой, я думаю, что все виртуальные функции, определенные в Object, уязвимы. Я смог поддержать это следующим:
testopcmphelper.d
interface TestInterface {
string helloWorld();
}
class TestClass {
abstract string helloWorld();
}
testopcmp.d
import testopcmphelper;
import std.stdio;
void invokeFn(TestInterface function() f) {
auto t = f();
auto s = t.helloWorld();
writeln(s);
}
unittest {
auto f = function() {
return new class TestInterface {
string helloWorld() {
return "Hello World!";
}
};
};
invokeFn(f);
}
void invokeFn(TestClass function() f) {
auto t = f();
auto s = t.helloWorld();
writeln(s);
}
unittest {
auto f = function() {
return new class TestClass {
string helloWorld() {
return "Goodbye World!";
}
};
};
invokeFn(f);
}
Какие отпечатки:
src.utilities.testopcmp.__unittest2.__funcliteral1.__anonclass10
Goodbye World!
Указывает, что invokeFn(TestInterface)
вызывает Object.toString
вместо TestInterface.helloWorld
.
Я собираюсь оставить вопрос открытым на другой день, если я допустил ошибку. Я, вероятно, тогда сообщу об этом как об ошибке в DMD. Я буду обходить эту проблему, используя только абстрактные классы для базовых типов анонимных функций фабрики.
TL; DR Кажется, что это ошибка.