In the following example, the program block if compiled with -g and dmd 1.026/1.028. See the comments, there are 3 possiblilities of changes, which should not change behaviour, but does make this program work.
I tested this only on tango. Can someone confirm this bug also on phobos? and D2?
extern(C) int printf(char*,...);
public interface View(T){
// changing duplicate return type to View!(T) make it work
public Dispenser!(T) duplicate ();
public uint size ();
public uint mutation ();
public int opApply (int delegate (inout T value) dg);
}
public interface Dispenser(T) : View!(T){
public void removeAll (Iterator!(T) e);
public void remove (Iterator!(T) e);
public void removeAll (T element);
public void remove (T element);
}
public interface Seq(T) :
View!(T), // removing View!(T) interface make it work.
Dispenser!(T)
{
public T get(int index);
public alias get opIndex;
}
public interface Iterator(V) {
public bool more();
public V get();
int opApply (int delegate (inout V value) dg);
}
public interface GuardIterator(V) : Iterator!(V){
public uint remaining();
}
public abstract class AbstractIterator(T) : GuardIterator!(T) {
private View!(T) view;
private uint mutation;
private uint togo;
protected this (View!(T) v) {
view = v;
togo = v.size();
mutation = v.mutation();
}
public final uint remaining() {
return togo;
}
public final bool more() {
return togo > 0 && mutation is view.mutation;
}
protected final void decRemaining() {
--togo;
}
}
class ArrayIterator(T) : AbstractIterator!(T)
{
private int row;
private T[] array;
public this (ArraySeq!(T) seq) {
super (seq);
array = seq.array;
}
public final T get() {
decRemaining();
return array[row++];
}
int opApply (int delegate (inout T value) dg) {
int result;
for (auto i=remaining(); i--;)
{
auto value = get();
if ((result = dg(value)) != 0)
break;
}
return result;
}
}
public abstract class Collection(T) : Dispenser!(T)
{
alias View!(T) ViewT;
protected uint count;
public final uint size() {
return count;
}
public final uint mutation() {
return 0;
}
abstract void removeAll(T element);
abstract void remove (T element);
abstract void removeAll (Iterator!(T) e);
abstract void remove (Iterator!(T) e);
}
public abstract class SeqCollection(T) : Collection!(T), Seq!(T) {
public abstract override void remove(T it);
public abstract override void removeAll(T it);
public void removeAll (Iterator!(T) e) {
while (e.more)
removeAll (e.get);
}
public void remove (Iterator!(T) e) {
while (e.more)
remove (e.get);
}
}
public class ArraySeq(T) : SeqCollection!(T), Dispenser!(T) {
public static int minCapacity = 16;
package T array[];
public this () {
this ( null, 0);
}
package this (T[] b, int c) {
array = b;
count = c;
}
public final Dispenser!(T) duplicate() {
return null;
}
int opApply (int delegate (inout T value) dg){
auto scope iterator = new ArrayIterator!(T)(this);
return iterator.opApply (dg);
}
public final T get(int index){
return array[index];
}
public final override void remove(T element){}
public final override void removeAll(T element){}
public void remove(Iterator!(T) it){
super.remove(it);
}
public void removeAll(Iterator!(T) it){
super.removeAll(it);
}
}
// removing this variable decl will make it work
Seq!(Object) seq;
void main(){
auto alist = new ArraySeq!(Object);
foreach( el; alist ){
printf( "shall not come here.\n" );
}
printf( "ready\n" );
}
Comment #1 by benoit — 2008-04-08T05:18:00Z
I reduced it more...
Now the example prints:
remove
ready
It does not block, but remove() is called without call.
extern(C) int printf(char*,...);
public interface View(T){
// changing duplicate return type to View!(T) make it work
public Dispenser!(T) duplicate ();
public uint mutation ();
}
public interface Dispenser(T) : View!(T){
public void removeAll (Iterator!(T) e);
public void remove (Iterator!(T) e);
public void removeAll (T element);
public void remove (T element);
}
public interface Seq(T) :
View!(T), // removing View!(T) interface make it work.
Dispenser!(T)
{
}
public interface Iterator(V) {
int opApply (int delegate (inout V value) dg);
}
public abstract class AbstractIterator(T) : Iterator!(T) {
protected this (View!(T) v) {
v.mutation();
}
}
class ArrayIterator(T) : AbstractIterator!(T) {
public this (ArraySeq!(T) seq) {
super (seq);
}
int opApply (int delegate (inout T value) dg) {
return 0;
}
}
public abstract class Collection(T) : Dispenser!(T)
{
public final uint mutation() {
return 0;
}
}
// removing this intermediate class makes it work
public abstract class SeqCollection(T) : Collection!(T), Seq!(T) {
}
public class ArraySeq(T) : SeqCollection!(T)
, Dispenser!(T) // removing this makes it work, dispenser is already derived from SeqCollection
{
//
public final Dispenser!(T) duplicate() {
return null;
}
public final override void remove(T element){}
public final override void removeAll(T element){}
public void removeAll (Iterator!(T) e) {
printf( "removeAll\n" );
}
public void remove (Iterator!(T) e) {
printf( "remove\n" );
}
}
//import tango.util.collection.model.Seq;
//import tango.util.collection.ArraySeq;
// removing this variable decl will make it work
Seq!(Object) seq;
void main(){
auto alist = new ArraySeq!(Object);
auto scope iterator = new ArrayIterator!(Object)(alist);
foreach( el; iterator ){
printf( "shall not come here.\n" );
}
printf( "ready\n" );
}
Comment #2 by benoit — 2008-04-08T05:27:18Z
I verified the bug with dmd 1.028 and 2.012 with phobos.
Comment #3 by kamm-removethis — 2008-04-08T06:15:52Z
Further simplification:
extern(C) int printf(char*,...);
interface InterfaceB(T) : InterfaceA {}
interface InterfaceA{
// changing return type to InterfaceA makes it work
InterfaceB!(Object) func ();
}
class Foo(T) : InterfaceB!(T) {
InterfaceB!(Object) func() {
return null;
}
}
void main() {
auto foo = new Foo!(Object);
// without this call, segfault is gone
foo.func();
printf("foo.func() call passed\n");
InterfaceA ifA = foo;
assert(ifA !is null);
ifA.func(); // segfault
}