changeset 113:27b9f749d9fe trunk

[svn r117] Initial working implementation of interfaces. Groundwork for all the different types of class/interface casts laid out.
author lindquist
date Sat, 24 Nov 2007 06:33:00 +0100
parents 368547b1cbe6
children 5880c12dba83
files gen/classes.cpp gen/classes.h gen/functions.cpp gen/irstate.cpp gen/irstate.h gen/structs.cpp gen/toir.cpp gen/tollvm.cpp gen/toobj.cpp gen/typinf.cpp llvmdc.kdevelop.filelist lphobos/build.sh lphobos/internal/cast.d lphobos/internal/objectimpl.d test/interface1.d test/interface2.d test/interface3.d test/interface4.d
diffstat 18 files changed, 868 insertions(+), 146 deletions(-) [+]
line wrap: on
line diff
--- a/gen/classes.cpp	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/classes.cpp	Sat Nov 24 06:33:00 2007 +0100
@@ -1,3 +1,4 @@
+#include <sstream>
 #include "gen/llvm.h"
 
 #include "mtype.h"
@@ -11,6 +12,8 @@
 #include "gen/logger.h"
 #include "gen/classes.h"
 #include "gen/functions.h"
+#include "gen/runtime.h"
+#include "gen/dvalue.h"
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
@@ -21,10 +24,14 @@
     {
         BaseClass* bc = (BaseClass*)(bcs->data[j]);
         assert(bc);
+        if (bc->base->isInterfaceDeclaration())
+            continue; // interfaces only has methods
+
+        LLVM_AddBaseClassData(&bc->base->baseclasses);
+
         Logger::println("Adding base class members of %s", bc->base->toChars());
         LOG_SCOPE;
 
-        LLVM_AddBaseClassData(&bc->base->baseclasses);
         for (int k=0; k < bc->base->members->dim; k++) {
             Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]);
             if (dsym->isVarDeclaration())
@@ -46,10 +53,17 @@
     if (cd->baseClass) {
         DtoResolveClass(cd->baseClass);
     }
-    // resolve typeinfo
-    //DtoResolveClass(ClassDeclaration::typeinfo);
-    // resolve classinfo
-    //DtoResolveClass(ClassDeclaration::classinfo);
+
+    // resolve interfaces
+    if (cd->vtblInterfaces) {
+        for (int i=0; i < cd->vtblInterfaces->dim; i++) {
+            BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i];
+            ClassDeclaration *id = b->base;
+            DtoResolveClass(id);
+            // Fill in vtbl[]
+            b->fillVtbl(cd, &b->vtbl, 1);
+        }
+    }
 
     Logger::println("DtoResolveClass(%s)", cd->toPrettyChars());
     LOG_SCOPE;
@@ -71,6 +85,22 @@
     std::vector<const llvm::Type*> fieldtypes;
     fieldtypes.push_back(vtabty);
 
+    // add interface vtables
+    if (cd->vtblInterfaces)
+    for (size_t i = 0; i < cd->vtblInterfaces->dim; i++)
+    {
+        BaseClass *b = (BaseClass *)cd->vtblInterfaces->data[i];
+        ClassDeclaration *id = b->base;
+        assert(id->type->ty == Tclass);
+        TypeClass* itc = (TypeClass*)id->type;
+        const llvm::Type* ivtblTy = llvm::PointerType::get(itc->llvmVtblType->get());
+        fieldtypes.push_back(ivtblTy);
+
+        // add this interface to the map
+        IRInterface* iri = new IRInterface(b, isaStruct(itc->llvmVtblType->get()));
+        irstruct->interfaces.insert(std::make_pair(id, iri));
+    }
+
     // base classes first
     LLVM_AddBaseClassData(&cd->baseclasses);
 
@@ -98,16 +128,31 @@
     else
         *ts->llvmType = structtype;
 
-    bool needs_definition = false;
     if (cd->parent->isModule()) {
         gIR->module->addTypeName(cd->mangle(), ts->llvmType->get());
-        needs_definition = (cd->getModule() == gIR->dmodule);
     }
     else {
         assert(0 && "class parent is not a module");
     }
 
-    // generate vtable
+    // build interface info type
+    std::vector<const llvm::Type*> infoTypes;
+    // ClassInfo classinfo
+    ClassDeclaration* cinfod = ClassDeclaration::classinfo;
+    DtoResolveClass(cinfod);
+    infoTypes.push_back(llvm::PointerType::get(cinfod->type->llvmType->get()));
+    // void*[] vtbl
+    std::vector<const llvm::Type*> infoVtbltypes;
+    infoVtbltypes.push_back(DtoSize_t());
+    const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty));
+    infoVtbltypes.push_back(byteptrptrty);
+    infoTypes.push_back(llvm::StructType::get(infoVtbltypes));
+    // int offset
+    infoTypes.push_back(llvm::Type::Int32Ty);
+    // create type
+    const llvm::StructType* infoTy = llvm::StructType::get(infoTypes);
+
+    // create vtable type
     llvm::GlobalVariable* svtblVar = 0;
     std::vector<const llvm::Type*> sinits_ty;
 
@@ -124,18 +169,21 @@
             const llvm::Type* fpty = llvm::PointerType::get(tf->llvmType->get());
             sinits_ty.push_back(fpty);
         }
-        else if (ClassDeclaration* cd = dsym->isClassDeclaration()) {
-            //Logger::println("*** ClassDeclaration in vtable: %s", cd->toChars());
+        else if (ClassDeclaration* cd2 = dsym->isClassDeclaration()) {
+            Logger::println("*** ClassDeclaration in vtable: %s", cd2->toChars());
             const llvm::Type* cinfoty;
-            if (cd != ClassDeclaration::classinfo) {
-                cd = ClassDeclaration::classinfo;
-                DtoResolveClass(cd);
-                cinfoty = cd->type->llvmType->get();
+            if (cd->isInterfaceDeclaration()) {
+                cinfoty = infoTy;
+            }
+            else if (cd != cinfod) {
+                DtoResolveClass(cinfod);
+                cinfoty = cinfod->type->llvmType->get();
             }
             else {
+                // this is the ClassInfo class, the type is this type
                 cinfoty = ts->llvmType->get();
             }
-            const llvm::Type* cty = llvm::PointerType::get(cd->type->llvmType->get());
+            const llvm::Type* cty = llvm::PointerType::get(cinfoty);
             sinits_ty.push_back(cty);
         }
         else
@@ -182,26 +230,78 @@
         needs_definition = (cd->getModule() == gIR->dmodule);
     }
 
-    // vtable
-    std::string varname("_D");
-    varname.append(cd->mangle());
-    varname.append("6__vtblZ");
+    // interface vtables are emitted by the class implementing them
+    // also interfaces have no static initializer
+    if (!cd->isInterfaceDeclaration()) {
+        // vtable
+        std::string varname("_D");
+        varname.append(cd->mangle());
+        varname.append("6__vtblZ");
+
+        llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
+
+        const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get());
+        cd->llvmVtbl = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module);
 
-    std::string styname(cd->mangle());
-    styname.append("__vtblTy");
-
-    llvm::GlobalValue::LinkageTypes _linkage = llvm::GlobalValue::ExternalLinkage;
+        // build interface info type
+        std::vector<const llvm::Type*> types;
+        // ClassInfo classinfo
+        ClassDeclaration* cd2 = ClassDeclaration::classinfo;
+        DtoResolveClass(cd2);
+        types.push_back(llvm::PointerType::get(cd2->type->llvmType->get()));
+        // void*[] vtbl
+        std::vector<const llvm::Type*> vtbltypes;
+        vtbltypes.push_back(DtoSize_t());
+        const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty));
+        vtbltypes.push_back(byteptrptrty);
+        types.push_back(llvm::StructType::get(vtbltypes));
+        // int offset
+        types.push_back(llvm::Type::Int32Ty);
+        // create type
+        const llvm::StructType* infoTy = llvm::StructType::get(types);
 
-    const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get());
-    cd->llvmVtbl = new llvm::GlobalVariable(svtbl_ty, true, _linkage, 0, varname, gIR->module);
+        // interface info array
+        if (needs_definition && cd->vtblInterfaces->dim > 0) {
+            // symbol name
+            std::string nam = "_D";
+            nam.append(cd->mangle());
+            nam.append("16__interfaceInfosZ");
+            // resolve array type
+            const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, cd->vtblInterfaces->dim);
+            // declare global
+            irstruct->interfaceInfosTy = arrTy;
+            irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, llvm::GlobalValue::InternalLinkage, 0, nam, gIR->module);
+        }
+
+        // interface vtables
+        unsigned idx = 0;
+        for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i)
+        {
+            ClassDeclaration* id = i->first;
+            IRInterface* iri = i->second;
 
-    // init
-    std::string initname("_D");
-    initname.append(cd->mangle());
-    initname.append("6__initZ");
+            std::string nam("_D");
+            nam.append(cd->mangle());
+            nam.append("11__interface");
+            nam.append(id->mangle());
+            nam.append("6__vtblZ");
 
-    llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module);
-    ts->llvmInit = initvar;
+            assert(iri->vtblTy);
+            iri->vtbl = new llvm::GlobalVariable(iri->vtblTy, true, _linkage, 0, nam, gIR->module);
+            iri->infoTy = infoTy;
+            llvm::Constant* idxs[2] = {DtoConstUint(0), DtoConstUint(idx)};
+            iri->info = llvm::ConstantExpr::getGetElementPtr(irstruct->interfaceInfos, idxs, 2);
+            idx++;
+        }
+
+        // init
+        std::string initname("_D");
+        initname.append(cd->mangle());
+        initname.append("6__initZ");
+
+        llvm::GlobalVariable* initvar = new llvm::GlobalVariable(ts->llvmType->get(), true, _linkage, NULL, initname, gIR->module);
+        ts->llvmInit = initvar;
+    }
 
     gIR->classes.pop_back();
     gIR->structs.pop_back();
@@ -225,6 +325,9 @@
     if (cd->llvmInitialized) return;
     cd->llvmInitialized = true;
 
+    if (cd->isInterfaceDeclaration())
+        return; // nothing to do
+
     Logger::println("DtoConstInitClass(%s)", cd->toPrettyChars());
     LOG_SCOPE;
 
@@ -248,6 +351,14 @@
     assert(cd->llvmVtbl != 0);
     fieldinits.push_back(cd->llvmVtbl);
 
+    // next comes interface vtables
+    for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i)
+    {
+        IRInterface* iri = i->second;
+        assert(iri->vtbl);
+        fieldinits.push_back(iri->vtbl);
+    }
+
     // rest
     for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) {
         Logger::println("adding fieldinit for: %s", i->second.var->toChars());
@@ -260,7 +371,8 @@
     const llvm::StructType* structtype = isaStruct(ts->llvmType->get());
 
     // generate initializer
-    /*Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n';
+#if 0
+    Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n';
 
     for(size_t i=0; i<structtype->getNumElements(); ++i) {
         Logger::cout() << "s#" << i << " = " << *structtype->getElementType(i) << '\n';
@@ -268,7 +380,8 @@
 
     for(size_t i=0; i<fieldinits.size(); ++i) {
         Logger::cout() << "i#" << i << " = " << *fieldinits[i]->getType() << '\n';
-    }*/
+    }
+#endif
 
     llvm::Constant* _init = llvm::ConstantStruct::get(structtype, fieldinits);
     assert(_init);
@@ -300,16 +413,83 @@
 
     const llvm::StructType* svtbl_ty = isaStruct(ts->llvmVtblType->get());
 
-    /*for (size_t i=0; i< sinits.size(); ++i)
+#if 0
+    for (size_t i=0; i< sinits.size(); ++i)
     {
         Logger::cout() << "field[" << i << "] = " << *svtbl_ty->getElementType(i) << '\n';
         Logger::cout() << "init [" << i << "] = " << *sinits[i]->getType() << '\n';
         assert(svtbl_ty->getElementType(i) == sinits[i]->getType());
-    }*/
+    }
+#endif
 
     llvm::Constant* cvtblInit = llvm::ConstantStruct::get(svtbl_ty, sinits);
     cd->llvmConstVtbl = llvm::cast<llvm::ConstantStruct>(cvtblInit);
 
+    // create interface vtable const initalizers
+    int idx = 1;
+    int idxScale = (global.params.is64bit) ? 8 : 4;
+    for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i)
+    {
+        ClassDeclaration* id = i->first;
+        assert(id->type->ty == Tclass);
+        TypeClass* its = (TypeClass*)id->type;
+
+        IRInterface* iri = i->second;
+        BaseClass* b = iri->base;
+
+        const llvm::StructType* ivtbl_ty = isaStruct(its->llvmVtblType->get());
+
+        // generate interface info initializer
+        std::vector<llvm::Constant*> infoInits;
+        // classinfo
+        assert(id->llvmClass);
+        llvm::Constant* c = id->llvmClass;
+        infoInits.push_back(c);
+        // vtbl
+        const llvm::Type* byteptrptrty = llvm::PointerType::get(llvm::PointerType::get(llvm::Type::Int8Ty));
+        c = llvm::ConstantExpr::getBitCast(iri->vtbl, byteptrptrty);
+        c = DtoConstSlice(DtoConstSize_t(b->vtbl.dim), c);
+        infoInits.push_back(c);
+        // offset
+        infoInits.push_back(DtoConstInt(idx*idxScale));
+        // create interface info initializer constant
+        iri->infoInit = llvm::cast<llvm::ConstantStruct>(llvm::ConstantStruct::get(iri->infoTy, infoInits));
+
+        // generate vtable initializer
+        std::vector<llvm::Constant*> iinits;
+
+        // add interface info
+        iinits.push_back(iri->info);
+
+        for (int k=1; k < b->vtbl.dim; k++)
+        {
+            Logger::println("interface vtbl const init nr. %d", k);
+            Dsymbol* dsym = (Dsymbol*)b->vtbl.data[k];
+            FuncDeclaration* fd = dsym->isFuncDeclaration();
+            assert(fd);
+            DtoForceDeclareDsymbol(fd);
+            assert(fd->llvmValue);
+            llvm::Constant* c = llvm::cast<llvm::Constant>(fd->llvmValue);
+            // we have to bitcast, as the type created in ResolveClass expects a different this type
+            c = llvm::ConstantExpr::getBitCast(c, iri->vtblTy->getContainedType(k));
+            iinits.push_back(c);
+        }
+
+#if 1
+        for (size_t x=0; x< iinits.size(); ++x)
+        {
+            Logger::cout() << "field[" << x << "] = " << *ivtbl_ty->getElementType(x) << "\n\n";
+            Logger::cout() << "init [" << x << "] = " << *iinits[x] << "\n\n";
+            assert(ivtbl_ty->getElementType(x) == iinits[x]->getType());
+        }
+#endif
+
+        llvm::Constant* civtblInit = llvm::ConstantStruct::get(ivtbl_ty, iinits);
+        iri->vtblInit = llvm::cast<llvm::ConstantStruct>(civtblInit);
+
+        idx++;
+    }
+
     gIR->classes.pop_back();
     gIR->structs.pop_back();
 }
@@ -330,8 +510,26 @@
 
     bool def = false;
     if (cd->parent->isModule() && cd->getModule() == gIR->dmodule) {
-        ts->llvmInit->setInitializer(cd->llvmInitZ);
-        cd->llvmVtbl->setInitializer(cd->llvmConstVtbl);
+        // interfaces don't have initializers
+        if (!cd->isInterfaceDeclaration()) {
+            ts->llvmInit->setInitializer(cd->llvmInitZ);
+            cd->llvmVtbl->setInitializer(cd->llvmConstVtbl);
+
+            // initialize interface vtables
+            IRStruct* irstruct = cd->llvmIRStruct;
+            std::vector<llvm::Constant*> infoInits;
+            for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i)
+            {
+                IRInterface* iri = i->second;
+                iri->vtbl->setInitializer(iri->vtblInit);
+                infoInits.push_back(iri->infoInit);
+            }
+            // initialize interface info array
+            if (!infoInits.empty()) {
+                llvm::Constant* arrInit = llvm::ConstantArray::get(irstruct->interfaceInfosTy, infoInits);
+                irstruct->interfaceInfos->setInitializer(arrInit);
+            }
+        }
         def = true;
     }
 
@@ -394,6 +592,54 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+DValue* DtoCastObjectToInterface(DValue* val, Type* _to)
+{
+    // call:
+    // Object _d_dynamic_cast(Object o, ClassInfo c)
+
+    llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_dynamic_cast");
+    const llvm::FunctionType* funcTy = func->getFunctionType();
+
+    std::vector<llvm::Value*> args;
+
+    // Object o
+    llvm::Value* tmp = val->getRVal();
+    tmp = DtoBitCast(tmp, funcTy->getParamType(0));
+    args.push_back(tmp);
+
+    // ClassInfo c
+    TypeClass* to = (TypeClass*)DtoDType(_to);
+    DtoForceDeclareDsymbol(to->sym);
+    assert(to->sym->llvmClass);
+    args.push_back(to->sym->llvmClass);
+
+    // call it
+    llvm::Value* ret = gIR->ir->CreateCall(func, args.begin(), args.end(), "tmp");
+    ret = DtoBitCast(ret, DtoType(_to));
+    return new DImValue(_to, ret);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
+DValue* DtoCastInterfaceToObject(DValue* val)
+{
+    // call:
+    // Object _d_toObject(void* p)
+
+    llvm::Function* func = LLVM_D_GetRuntimeFunction(gIR->module, "_d_toObject");
+    const llvm::FunctionType* funcTy = func->getFunctionType();
+
+    // void* p
+    llvm::Value* tmp = val->getRVal();
+    tmp = DtoBitCast(tmp, funcTy->getParamType(0));
+
+    // call it
+    llvm::Value* ret = gIR->ir->CreateCall(func, tmp, "tmp");
+    return new DImValue(ClassDeclaration::object->type, ret);
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
 void DtoDeclareClassInfo(ClassDeclaration* cd)
 {
     if (cd->llvmClassDeclared) return;
@@ -407,7 +653,10 @@
 
     std::string gname("_D");
     gname.append(cd->mangle());
-    gname.append("7__ClassZ");
+    if (!cd->isInterfaceDeclaration())
+        gname.append("7__ClassZ");
+    else
+        gname.append("11__InterfaceZ");
 
     const llvm::Type* st = cinfo->type->llvmType->get();
 
@@ -538,6 +787,7 @@
 
 static uint build_classinfo_flags(ClassDeclaration* cd)
 {
+    // adapted from original dmd code
     uint flags = 0;
     //flags |= isCOMclass(); // IUnknown
     bool hasOffTi = false;
@@ -591,12 +841,14 @@
 
     assert(cd->type->ty == Tclass);
     assert(cd->llvmClass);
-    assert(cd->llvmInitZ);
-    assert(cd->llvmVtbl);
-    assert(cd->llvmConstVtbl);
 
     TypeClass* cdty = (TypeClass*)cd->type;
-    assert(cdty->llvmInit);
+    if (!cd->isInterfaceDeclaration()) {
+        assert(cd->llvmInitZ);
+        assert(cd->llvmVtbl);
+        assert(cd->llvmConstVtbl);
+        assert(cdty->llvmInit);
+    }
 
     // holds the list of initializers for llvm
     std::vector<llvm::Constant*> inits;
@@ -617,10 +869,15 @@
 
     // byte[] init
     const llvm::Type* byteptrty = llvm::PointerType::get(llvm::Type::Int8Ty);
-    c = llvm::ConstantExpr::getBitCast(cdty->llvmInit, byteptrty);
-    assert(!cd->llvmInitZ->getType()->isAbstract());
-    size_t initsz = gTargetData->getTypeSize(cd->llvmInitZ->getType());
-    c = DtoConstSlice(DtoConstSize_t(initsz), c);
+    if (cd->isInterfaceDeclaration()) {
+        c = cinfo->llvmInitZ->getOperand(1);
+    }
+    else {
+        c = llvm::ConstantExpr::getBitCast(cdty->llvmInit, byteptrty);
+        assert(!cd->llvmInitZ->getType()->isAbstract());
+        size_t initsz = gTargetData->getTypeSize(cd->llvmInitZ->getType());
+        c = DtoConstSlice(DtoConstSize_t(initsz), c);
+    }
     inits.push_back(c);
 
     // class name
@@ -636,21 +893,34 @@
     inits.push_back(c);
 
     // vtbl array
-    const llvm::Type* byteptrptrty = llvm::PointerType::get(byteptrty);
-    assert(!cd->llvmVtbl->getType()->isAbstract());
-    c = llvm::ConstantExpr::getBitCast(cd->llvmVtbl, byteptrptrty);
-    assert(!cd->llvmConstVtbl->getType()->isAbstract());
-    size_t vtblsz = gTargetData->getTypeSize(cd->llvmConstVtbl->getType());
-    c = DtoConstSlice(DtoConstSize_t(vtblsz), c);
+    if (cd->isInterfaceDeclaration()) {
+        c = cinfo->llvmInitZ->getOperand(3);
+    }
+    else {
+        const llvm::Type* byteptrptrty = llvm::PointerType::get(byteptrty);
+        assert(!cd->llvmVtbl->getType()->isAbstract());
+        c = llvm::ConstantExpr::getBitCast(cd->llvmVtbl, byteptrptrty);
+        assert(!cd->llvmConstVtbl->getType()->isAbstract());
+        size_t vtblsz = cd->llvmConstVtbl->getType()->getNumElements();
+        c = DtoConstSlice(DtoConstSize_t(vtblsz), c);
+    }
     inits.push_back(c);
 
     // interfaces array
-    // TODO
-    c = cinfo->llvmInitZ->getOperand(4);
+    IRStruct* irstruct = cd->llvmIRStruct;
+    if (cd->isInterfaceDeclaration() || !irstruct->interfaceInfos) {
+        c = cinfo->llvmInitZ->getOperand(4);
+    }
+    else {
+        const llvm::Type* t = cinfo->llvmInitZ->getOperand(4)->getType()->getContainedType(1);
+        c = llvm::ConstantExpr::getBitCast(irstruct->interfaceInfos, t);
+        size_t iisz = irstruct->interfaceInfosTy->getNumElements();
+        c = DtoConstSlice(DtoConstSize_t(iisz), c);
+    }
     inits.push_back(c);
 
     // base classinfo
-    if (cd->baseClass) {
+    if (cd->baseClass && !cd->isInterfaceDeclaration()) {
         DtoDeclareClassInfo(cd->baseClass);
         c = cd->baseClass->llvmClass;
         assert(c);
@@ -663,7 +933,12 @@
     }
 
     // destructor
-    c = build_class_dtor(cd);
+    if (cd->isInterfaceDeclaration()) {
+        c = cinfo->llvmInitZ->getOperand(6);
+    }
+    else {
+        c = build_class_dtor(cd);
+    }
     inits.push_back(c);
 
     // invariant
@@ -671,9 +946,14 @@
     c = cinfo->llvmInitZ->getOperand(7);
     inits.push_back(c);
 
-    // uint flags, adapted from original dmd code
-    uint flags = build_classinfo_flags(cd);
-    c = DtoConstUint(flags);
+    // uint flags
+    if (cd->isInterfaceDeclaration()) {
+        c = cinfo->llvmInitZ->getOperand(8);
+    }
+    else {
+        uint flags = build_classinfo_flags(cd);
+        c = DtoConstUint(flags);
+    }
     inits.push_back(c);
 
     // allocator
@@ -682,11 +962,16 @@
     inits.push_back(c);
 
     // offset typeinfo
-    c = build_offti_array(cd, cinfo->llvmInitZ->getOperand(10));
+    if (cd->isInterfaceDeclaration()) {
+        c = cinfo->llvmInitZ->getOperand(10);
+    }
+    else {
+        c = build_offti_array(cd, cinfo->llvmInitZ->getOperand(10));
+    }
     inits.push_back(c);
 
     // default constructor
-    if (cd->defaultCtor) {
+    if (cd->defaultCtor && !cd->isInterfaceDeclaration()) {
         DtoForceDeclareDsymbol(cd->defaultCtor);
         c = isaConstant(cd->defaultCtor->llvmValue);
         //const llvm::Type* toTy = cinfo->llvmInitZ->getOperand(11)->getType();
--- a/gen/classes.h	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/classes.h	Sat Nov 24 06:33:00 2007 +0100
@@ -27,4 +27,7 @@
 void DtoCallClassDtors(TypeClass* tc, llvm::Value* instance);
 void DtoInitClass(TypeClass* tc, llvm::Value* dst);
 
+DValue* DtoCastObjectToInterface(DValue* val, Type* to);
+DValue* DtoCastInterfaceToObject(DValue* val);
+
 #endif
--- a/gen/functions.cpp	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/functions.cpp	Sat Nov 24 06:33:00 2007 +0100
@@ -192,7 +192,7 @@
         if (AggregateDeclaration* ad = fdecl->isMember()) {
             Logger::print("isMember = this is: %s\n", ad->type->toChars());
             thisty = DtoType(ad->type);
-            Logger::cout() << "this llvm type: " << *thisty << '\n';
+            //Logger::cout() << "this llvm type: " << *thisty << '\n';
             if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->recty.get()))
                 thisty = llvm::PointerType::get(thisty);
         }
@@ -277,7 +277,8 @@
     DtoFunctionType(fdecl);
 
     // queue declaration
-    gIR->declareList.push_back(fdecl);
+    if (!fdecl->isAbstract())
+        gIR->declareList.push_back(fdecl);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -290,6 +291,8 @@
     Logger::println("DtoDeclareFunction(%s)", fdecl->toPrettyChars());
     LOG_SCOPE;
 
+    assert(!fdecl->isAbstract());
+
     if (fdecl->llvmRunTimeHack) {
         Logger::println("runtime hack func chars: %s", fdecl->toChars());
         if (!fdecl->llvmValue)
--- a/gen/irstate.cpp	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/irstate.cpp	Sat Nov 24 06:33:00 2007 +0100
@@ -107,6 +107,8 @@
     type = t;
     defined = false;
     constinited = false;
+    interfaceInfosTy = NULL;
+    interfaceInfos = NULL;
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
--- a/gen/irstate.h	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/irstate.h	Sat Nov 24 06:33:00 2007 +0100
@@ -8,6 +8,7 @@
 #include <list>
 
 #include "root.h"
+#include "aggregate.h"
 
 // global ir state for current module
 struct IRState;
@@ -20,6 +21,7 @@
 struct FuncDeclaration;
 struct Module;
 struct TypeStruct;
+struct BaseClass;
 
 /*
 struct LLVMValue
@@ -39,6 +41,32 @@
     IRScope(llvm::BasicBlock* b, llvm::BasicBlock* e);
 };
 
+struct IRInterface : Object
+{
+    BaseClass* base;
+    ClassDeclaration* decl;
+
+    const llvm::StructType* vtblTy;
+    llvm::ConstantStruct* vtblInit;
+    llvm::GlobalVariable* vtbl;
+
+    const llvm::StructType* infoTy;
+    llvm::ConstantStruct* infoInit;
+    llvm::Constant* info;
+
+    IRInterface(BaseClass* b, const llvm::StructType* vt)
+    {
+        base = b;
+        decl = b->base;
+        vtblTy = vt;
+        vtblInit = NULL;
+        vtbl = NULL;
+        infoTy = NULL;
+        infoInit = NULL;
+        info = NULL;
+    }
+};
+
 // represents a struct or class
 struct IRStruct : Object
 {
@@ -54,6 +82,8 @@
 
     typedef std::multimap<unsigned, Offset> OffsetMap;
     typedef std::vector<VarDeclaration*> VarDeclVector;
+    typedef std::map<ClassDeclaration*, IRInterface*> InterfaceMap;
+    typedef InterfaceMap::iterator InterfaceIter;
 
 public:
     IRStruct(Type*);
@@ -63,6 +93,10 @@
     OffsetMap offsets;
     VarDeclVector defaultFields;
 
+    InterfaceMap interfaces;
+    const llvm::ArrayType* interfaceInfosTy;
+    llvm::GlobalVariable* interfaceInfos;
+
     bool defined;
     bool constinited;
 };
--- a/gen/structs.cpp	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/structs.cpp	Sat Nov 24 06:33:00 2007 +0100
@@ -445,7 +445,7 @@
         }
     }
 
-    {
+    /*{
         LOG_SCOPE;
         Logger::println("******** DUnion BEGIN");
         size_t n = fields.size();
@@ -458,7 +458,7 @@
             }
         }
         Logger::println("******** DUnion END");
-    }
+    }*/
 }
 
 static void push_nulls(size_t nbytes, std::vector<llvm::Constant*>& out)
--- a/gen/toir.cpp	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/toir.cpp	Sat Nov 24 06:33:00 2007 +0100
@@ -1230,10 +1230,10 @@
 
     if (p->topexp() && p->topexp()->e1 == this) {
         Logger::println("lval PtrExp");
-        //if (a->isField()) return a;
         return new DVarValue(type, a->getRVal(), true);
     }
 
+    // this should be deterministic but right now lvalue casts don't propagate lvalueness !?!
     llvm::Value* lv = a->getRVal();
     llvm::Value* v = lv;
     if (DtoCanLoad(v))
@@ -1253,7 +1253,7 @@
     Type* t = DtoDType(type);
     Type* e1type = DtoDType(e1->type);
 
-    Logger::print("e1->type=%s\n", e1type->toChars());
+    Logger::print("e1type=%s\n", e1type->toChars());
 
     if (VarDeclaration* vd = var->isVarDeclaration()) {
         llvm::Value* arrptr;
@@ -1265,7 +1265,7 @@
             std::vector<unsigned> vdoffsets;
             arrptr = DtoIndexStruct(src, ts->sym, vd->type, vd->offset, vdoffsets);
         }
-        else if (e1->type->ty == Tclass) {
+        else if (e1type->ty == Tclass) {
             TypeClass* tc = (TypeClass*)e1type;
             Logger::println("Class member offset: %d", vd->offset);
             std::vector<unsigned> vdoffsets(1,0);
@@ -1282,14 +1282,19 @@
     }
     else if (FuncDeclaration* fdecl = var->isFuncDeclaration())
     {
-        if (fdecl->llvmValue == 0)
-        {
-            DtoForceDeclareDsymbol(fdecl);
+        DtoResolveDsymbol(fdecl);
+
+        llvm::Value* funcval;
+        llvm::Value* vthis2 = 0;
+        if (e1type->ty == Tclass) {
+            TypeClass* tc = (TypeClass*)e1type;
+            if (tc->sym->isInterfaceDeclaration()) {
+                vthis2 = DtoCastInterfaceToObject(l)->getRVal();
+            }
         }
-
-        llvm::Value* funcval = fdecl->llvmValue;
         llvm::Value* vthis = l->getRVal();
-        unsigned cc = (unsigned)-1;
+        if (!vthis2) vthis2 = vthis;
+        //unsigned cc = (unsigned)-1;
 
         // virtual call
         if (!fdecl->isFinal() && fdecl->isVirtual()) {
@@ -1303,10 +1308,17 @@
             funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
             funcval = DtoGEP(funcval, zero, vtblidx, toChars(), p->scopebb());
             funcval = new llvm::LoadInst(funcval,"tmp",p->scopebb());
-            assert(funcval->getType() == fdecl->llvmValue->getType());
-            cc = DtoCallingConv(fdecl->linkage);
+            //assert(funcval->getType() == DtoType(fdecl->type));
+            //cc = DtoCallingConv(fdecl->linkage);
         }
-        return new DFuncValue(fdecl, funcval, vthis);
+        // static call
+        else {
+            DtoForceDeclareDsymbol(fdecl);
+            funcval = fdecl->llvmValue;
+            assert(funcval);
+            //assert(funcval->getType() == DtoType(fdecl->type));
+        }
+        return new DFuncValue(fdecl, funcval, vthis2);
     }
     else {
         printf("unknown: %s\n", var->toChars());
@@ -1829,15 +1841,14 @@
     //assert(e1->type->ty != Tclass);
 
     DValue* v = e1->toElem(p);
-    llvm::Value* val = v->getRVal();
+    const llvm::Type* t = DtoType(v->getType());
     llvm::Value* ldval = 0;
-
-    const llvm::Type* t = val->getType();
     llvm::Constant* z = llvm::Constant::getNullValue(t);
 
     Type* e1type = DtoDType(e1->type);
 
     if (e1type->ty == Tpointer) {
+        llvm::Value* val = v->getRVal();
         Logger::cout() << *z << '\n';
         Logger::cout() << *val << '\n';
         new llvm::FreeInst(val, p->scopebb());
@@ -1845,16 +1856,23 @@
     }
     else if (e1type->ty == Tclass) {
         TypeClass* tc = (TypeClass*)e1type;
-        DtoCallClassDtors(tc, val);
+        llvm::Value* val = 0;
+        if (tc->sym->dtors.dim > 0) {
+            val = v->getRVal();
+            DtoCallClassDtors(tc, val);
+        }
 
         if (DVarValue* vv = v->isVar()) {
-            if (vv->var && !vv->var->onstack)
+            if (vv->var && !vv->var->onstack) {
+                if (!val) val = v->getRVal();
                 new llvm::FreeInst(val, p->scopebb());
+            }
         }
         new llvm::StoreInst(z, v->getLVal(), p->scopebb());
     }
     else if (e1type->ty == Tarray) {
         // must be on the heap (correct?)
+        llvm::Value* val = v->getRVal();
         llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty, 0, false);
         llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty, 1, false);
         llvm::Value* ptr = DtoGEP(val,zero,one,"tmp",p->scopebb());
--- a/gen/tollvm.cpp	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/tollvm.cpp	Sat Nov 24 06:33:00 2007 +0100
@@ -1140,11 +1140,35 @@
 
 DValue* DtoCastClass(DValue* val, Type* _to)
 {
-    const llvm::Type* tolltype = DtoType(_to);
     Type* to = DtoDType(_to);
-    assert(to->ty == Tclass || to->ty == Tpointer);
-    llvm::Value* rval = new llvm::BitCastInst(val->getRVal(), tolltype, "tmp", gIR->scopebb());
-    return new DImValue(_to, rval);
+    if (to->ty == Tpointer) {
+        const llvm::Type* tolltype = DtoType(_to);
+        llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype);
+        return new DImValue(_to, rval);
+    }
+
+    assert(to->ty == Tclass);
+    TypeClass* tc = (TypeClass*)to;
+
+    Type* from = DtoDType(val->getType());
+    TypeClass* fc = (TypeClass*)from;
+
+    if (tc->sym->isInterfaceDeclaration()) {
+        assert(!fc->sym->isInterfaceDeclaration());
+        return DtoCastObjectToInterface(val, _to);
+    }
+    else {
+        if (fc->sym->isInterfaceDeclaration()) {
+            assert(0);
+            return DtoCastInterfaceToObject(val);
+        }
+        else {
+            const llvm::Type* tolltype = DtoType(_to);
+            assert(to->ty == Tclass);
+            llvm::Value* rval = DtoBitCast(val->getRVal(), tolltype);
+            return new DImValue(_to, rval);
+        }
+    }
 }
 
 DValue* DtoCast(DValue* val, Type* to)
--- a/gen/toobj.cpp	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/toobj.cpp	Sat Nov 24 06:33:00 2007 +0100
@@ -389,7 +389,9 @@
     unsigned idx = 0;
     unsigned r = LLVM_ClassOffsetToIndex(this, os, idx);
     assert(r != (unsigned)-1 && "Offset not found in any aggregate field");
-    result.push_back(r+1); // vtable is 0
+    r++; // vtable is 0
+    r += vtblInterfaces->dim;
+    result.push_back(r); 
 }
 
 /* ================================================================== */
--- a/gen/typinf.cpp	Thu Nov 22 22:30:10 2007 +0100
+++ b/gen/typinf.cpp	Sat Nov 24 06:33:00 2007 +0100
@@ -1029,76 +1029,127 @@
 
 void TypeInfoInterfaceDeclaration::llvmDeclare()
 {
-    assert(0 && "TypeInfoTupleDeclaration");
+    Logger::println("TypeInfoInterfaceDeclaration::llvmDeclare() %s", toChars());
+    LOG_SCOPE;
+
+    // init typeinfo class
+    ClassDeclaration* base = Type::typeinfointerface;
+    assert(base);
+    DtoResolveClass(base);
+
+    // get type of typeinfo class
+    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
+
+    // create the symbol
+    llvmValue = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
 }
 
 void TypeInfoInterfaceDeclaration::llvmDefine()
 {
-    assert(0 && "TypeInfoTupleDeclaration");
+    Logger::println("TypeInfoInterfaceDeclaration::llvmDefine() %s", toChars());
+    LOG_SCOPE;
+
+    // init typeinfo class
+    ClassDeclaration* base = Type::typeinfointerface;
+    assert(base);
+    DtoForceConstInitDsymbol(base);
+
+    // get type of typeinfo class
+    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
+
+    // initializer vector
+    std::vector<llvm::Constant*> sinits;
+    // first is always the vtable
+    sinits.push_back(base->llvmVtbl);
+
+    // get classinfo
+    assert(tinfo->ty == Tclass);
+    TypeClass *tc = (TypeClass *)tinfo;
+    assert(tc->sym->llvmClass);
+    sinits.push_back(tc->sym->llvmClass);
+
+    // create the symbol
+    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
+    isaGlobalVar(llvmValue)->setInitializer(tiInit);
 }
 
 void TypeInfoInterfaceDeclaration::toDt(dt_t **pdt)
 {
-    assert(0 && "TypeInfoInterfaceDeclaration");
-
-    /*
-    //printf("TypeInfoInterfaceDeclaration::toDt() %s\n", tinfo->toChars());
-    dtxoff(pdt, Type::typeinfointerface->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfoInterface
-    dtdword(pdt, 0);                // monitor
-
-    assert(tinfo->ty == Tclass);
-
-    TypeClass *tc = (TypeClass *)tinfo;
-    Symbol *s;
-
-    if (!tc->sym->vclassinfo)
-    tc->sym->vclassinfo = new ClassInfoDeclaration(tc->sym);
-    s = tc->sym->vclassinfo->toSymbol();
-    dtxoff(pdt, s, 0, TYnptr);      // ClassInfo for tinfo
-    */
+    assert(0);
 }
 
 /* ========================================================================= */
 
 void TypeInfoTupleDeclaration::llvmDeclare()
 {
-    assert(0 && "TypeInfoTupleDeclaration");
+    Logger::println("TypeInfoTupleDeclaration::llvmDeclare() %s", toChars());
+    LOG_SCOPE;
+
+    // init typeinfo class
+    ClassDeclaration* base = Type::typeinfotypelist;
+    assert(base);
+    DtoResolveClass(base);
+
+    // get type of typeinfo class
+    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
+
+    // create the symbol
+    llvmValue = new llvm::GlobalVariable(stype,true,llvm::GlobalValue::WeakLinkage,NULL,toChars(),gIR->module);
 }
 
 void TypeInfoTupleDeclaration::llvmDefine()
 {
-    assert(0 && "TypeInfoTupleDeclaration");
+    Logger::println("TypeInfoTupleDeclaration::llvmDefine() %s", toChars());
+    LOG_SCOPE;
+
+    // init typeinfo class
+    ClassDeclaration* base = Type::typeinfotypelist;
+    assert(base);
+    DtoForceConstInitDsymbol(base);
+
+    // get type of typeinfo class
+    const llvm::StructType* stype = isaStruct(base->type->llvmType->get());
+
+    // initializer vector
+    std::vector<llvm::Constant*> sinits;
+    // first is always the vtable
+    sinits.push_back(base->llvmVtbl);
+
+    // create elements array
+    assert(tinfo->ty == Ttuple);
+    TypeTuple *tu = (TypeTuple *)tinfo;
+
+    size_t dim = tu->arguments->dim;
+    std::vector<llvm::Constant*> arrInits;
+
+    const llvm::Type* tiTy = Type::typeinfo->type->llvmType->get();
+    tiTy = llvm::PointerType::get(tiTy);
+
+    for (size_t i = 0; i < dim; i++)
+    {
+        Argument *arg = (Argument *)tu->arguments->data[i];
+        arg->type->getTypeInfo(NULL);
+        DtoForceDeclareDsymbol(arg->type->vtinfo);
+        assert(arg->type->vtinfo->llvmValue);
+        llvm::Constant* c = isaConstant(arg->type->vtinfo->llvmValue);
+        c = llvm::ConstantExpr::getBitCast(c, tiTy);
+        arrInits.push_back(c);
+    }
+
+    // build array type
+    const llvm::ArrayType* arrTy = llvm::ArrayType::get(tiTy, dim);
+    llvm::Constant* arrC = llvm::ConstantArray::get(arrTy, arrInits);
+
+    // build the slice
+    llvm::Constant* slice = DtoConstSlice(DtoConstSize_t(dim), arrC);
+    sinits.push_back(slice);
+
+    // create the symbol
+    llvm::Constant* tiInit = llvm::ConstantStruct::get(stype, sinits);
+    isaGlobalVar(llvmValue)->setInitializer(tiInit);
 }
 
 void TypeInfoTupleDeclaration::toDt(dt_t **pdt)
 {
-    assert(0 && "TypeInfoTupleDeclaration");
-
-    /*
-    //printf("TypeInfoTupleDeclaration::toDt() %s\n", tinfo->toChars());
-    dtxoff(pdt, Type::typeinfotypelist->toVtblSymbol(), 0, TYnptr); // vtbl for TypeInfoInterface
-    dtdword(pdt, 0);                // monitor
-
-    assert(tinfo->ty == Ttuple);
-
-    TypeTuple *tu = (TypeTuple *)tinfo;
-
-    size_t dim = tu->arguments->dim;
-    dtdword(pdt, dim);              // elements.length
-
-    dt_t *d = NULL;
-    for (size_t i = 0; i < dim; i++)
-    {   Argument *arg = (Argument *)tu->arguments->data[i];
-    Expression *e = arg->type->getTypeInfo(NULL);
-    e = e->optimize(WANTvalue);
-    e->toDt(&d);
-    }
-
-    Symbol *s;
-    s = static_sym();
-    s->Sdt = d;
-    outdata(s);
-
-    dtxoff(pdt, s, 0, TYnptr);          // elements.ptr
-    */
+    assert(0);
 }
--- a/llvmdc.kdevelop.filelist	Thu Nov 22 22:30:10 2007 +0100
+++ b/llvmdc.kdevelop.filelist	Sat Nov 24 06:33:00 2007 +0100
@@ -148,6 +148,7 @@
 lphobos/internal/aaA.d
 lphobos/internal/adi.d
 lphobos/internal/arrays.d
+lphobos/internal/cast.d
 lphobos/internal/contract.d
 lphobos/internal/mem.d
 lphobos/internal/moduleinit.d
@@ -338,7 +339,6 @@
 test/classinfo2.d
 test/classinfo3.d
 test/classinfo4.d
-test/classinfo5.d
 test/comma.d
 test/complex1.d
 test/complex2.d
@@ -378,6 +378,10 @@
 test/imports2.d
 test/imports_1of2.d
 test/imports_2of2.d
+test/interface1.d
+test/interface2.d
+test/interface3.d
+test/interface4.d
 test/intrinsics.d
 test/mainargs1.d
 test/memory1.d
--- a/lphobos/build.sh	Thu Nov 22 22:30:10 2007 +0100
+++ b/lphobos/build.sh	Sat Nov 24 06:33:00 2007 +0100
@@ -27,6 +27,10 @@
 rebuild typeinfos2.d -c -oqobj -dc=llvmdc-posix || exit 1
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo2.*.bc` ../lib/llvmdcore.bc || exit 1
 
+echo "compiling object/interface casting runtime support"
+llvmdc internal/cast.d -c -odobj || exit 1
+llvm-link -f -o=../lib/llvmdcore.bc obj/cast.bc ../lib/llvmdcore.bc || exit 1
+
 echo "compiling string foreach runtime support"
 llvmdc internal/aApply.d -c -odobj || exit 1
 llvmdc internal/aApplyR.d -c -odobj || exit 1
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/internal/cast.d	Sat Nov 24 06:33:00 2007 +0100
@@ -0,0 +1,182 @@
+/*
+ *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
+ *  Written by Walter Bright
+ *
+ *  This software is provided 'as-is', without any express or implied
+ *  warranty. In no event will the authors be held liable for any damages
+ *  arising from the use of this software.
+ *
+ *  Permission is granted to anyone to use this software for any purpose,
+ *  including commercial applications, and to alter it and redistribute it
+ *  freely, in both source and binary form, subject to the following
+ *  restrictions:
+ *
+ *  o  The origin of this software must not be misrepresented; you must not
+ *     claim that you wrote the original software. If you use this software
+ *     in a product, an acknowledgment in the product documentation would be
+ *     appreciated but is not required.
+ *  o  Altered source versions must be plainly marked as such, and must not
+ *     be misrepresented as being the original software.
+ *  o  This notice may not be removed or altered from any source
+ *     distribution.
+ */
+
+
+import object;
+import std.c.stdio;
+
+extern (C):
+
+/******************************************
+ * Given a pointer:
+ *	If it is an Object, return that Object.
+ *	If it is an interface, return the Object implementing the interface.
+ *	If it is null, return null.
+ *	Else, undefined crash
+ */
+
+Object _d_toObject(void* p)
+{   Object o;
+
+    if (p)
+    {
+	o = cast(Object)p;
+	//ClassInfo oc = o.classinfo;
+	Interface *pi = **cast(Interface ***)p;
+
+	/* Interface.offset lines up with ClassInfo.name.ptr,
+	 * so we rely on pointers never being less than 64K,
+	 * and Objects never being greater.
+	 */
+	if (pi.offset < 0x10000)
+	{
+	    //printf("\tpi.offset = %d\n", pi.offset);
+	    o = cast(Object)(p - pi.offset);
+	}
+    }
+    return o;
+}
+
+
+/*************************************
+ * Attempts to cast Object o to class c.
+ * Returns o if successful, null if not.
+ */
+
+Object _d_interface_cast(void* p, ClassInfo c)
+{   Object o;
+
+    //printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
+    if (p)
+    {
+	Interface *pi = **cast(Interface ***)p;
+
+	//printf("\tpi.offset = %d\n", pi.offset);
+	o = cast(Object)(p - pi.offset);
+	return _d_dynamic_cast(o, c);
+    }
+    return o;
+}
+
+Object _d_dynamic_cast(Object o, ClassInfo c)
+{   ClassInfo oc;
+    uint offset = 0;
+
+    //printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
+
+    if (o)
+    {
+	oc = o.classinfo;
+	if (_d_isbaseof2(oc, c, offset))
+	{
+	    //printf("\toffset = %d\n", offset);
+	    o = cast(Object)(cast(void*)o + offset);
+	}
+	else
+	    o = null;
+    }
+    //printf("\tresult = %p\n", o);
+    return o;
+}
+
+int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout uint offset)
+{   int i;
+
+    if (oc is c)
+	return 1;
+    do
+    {
+	if (oc.base is c)
+	    return 1;
+	for (i = 0; i < oc.interfaces.length; i++)
+	{
+	    ClassInfo ic;
+
+	    ic = oc.interfaces[i].classinfo;
+	    if (ic is c)
+	    {	offset = oc.interfaces[i].offset;
+		return 1;
+	    }
+	}
+	for (i = 0; i < oc.interfaces.length; i++)
+	{
+	    ClassInfo ic;
+
+	    ic = oc.interfaces[i].classinfo;
+	    if (_d_isbaseof2(ic, c, offset))
+	    {	offset = oc.interfaces[i].offset;
+		return 1;
+	    }
+	}
+	oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+int _d_isbaseof(ClassInfo oc, ClassInfo c)
+{   int i;
+
+    if (oc is c)
+	return 1;
+    do
+    {
+	if (oc.base is c)
+	    return 1;
+	for (i = 0; i < oc.interfaces.length; i++)
+	{
+	    ClassInfo ic;
+
+	    ic = oc.interfaces[i].classinfo;
+	    if (ic is c || _d_isbaseof(ic, c))
+		return 1;
+	}
+	oc = oc.base;
+    } while (oc);
+    return 0;
+}
+
+/*********************************
+ * Find the vtbl[] associated with Interface ic.
+ */
+
+void *_d_interface_vtbl(ClassInfo ic, Object o)
+{   int i;
+    ClassInfo oc;
+
+    //printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
+
+    assert(o);
+
+    oc = o.classinfo;
+    for (i = 0; i < oc.interfaces.length; i++)
+    {
+	ClassInfo oic;
+
+	oic = oc.interfaces[i].classinfo;
+	if (oic is ic)
+	{
+	    return cast(void *)oc.interfaces[i].vtbl;
+	}
+    }
+    assert(0);
+}
--- a/lphobos/internal/objectimpl.d	Thu Nov 22 22:30:10 2007 +0100
+++ b/lphobos/internal/objectimpl.d	Sat Nov 24 06:33:00 2007 +0100
@@ -879,8 +879,6 @@
     ClassInfo info;
 }
 
-/+
-
 class TypeInfo_Interface : TypeInfo
 {
     char[] toString() { return info.name; }
@@ -944,8 +942,6 @@
     ClassInfo info;
 }
 
-+/
-
 class TypeInfo_Struct : TypeInfo
 {
     char[] toString() { return name; }
@@ -1038,8 +1034,6 @@
     uint m_flags;
 }
 
-/+
-
 class TypeInfo_Tuple : TypeInfo
 {
     TypeInfo[] elements;
@@ -1102,8 +1096,6 @@
     }
 }
 
-+/
-
 class TypeInfo_Const : TypeInfo
 {
     char[] toString() { return "const " ~ base.toString(); }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/interface1.d	Sat Nov 24 06:33:00 2007 +0100
@@ -0,0 +1,22 @@
+module interface1;
+
+interface Inter
+{
+    void func();
+}
+
+class Class : Inter
+{
+    override void func()
+    {
+        printf("hello world\n");
+    }
+}
+
+void main()
+{
+    scope c = new Class;
+    c.func();
+    Inter i = c;
+    i.func();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/interface2.d	Sat Nov 24 06:33:00 2007 +0100
@@ -0,0 +1,35 @@
+module interface2;
+
+interface A
+{
+    void a();
+}
+
+interface B
+{
+    void b();
+}
+
+class C : A,B
+{
+    int i = 0;
+    override void a()
+    {
+        printf("hello from C.a\n");
+    }
+    override void b()
+    {
+        printf("hello from C.b\n");
+    }
+}
+
+void main()
+{
+    scope c = new C;
+    {c.a();
+    c.b();}
+    {A a = c;
+    a.a();}
+    {B b = c;
+    b.b();}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/interface3.d	Sat Nov 24 06:33:00 2007 +0100
@@ -0,0 +1,28 @@
+module interface3;
+
+interface I
+{
+    void func();
+}
+
+class C : I
+{
+    int i = 42;
+    override void func()
+    {
+        printf("hello %d\n", i);
+        i++;
+    }
+}
+
+void main()
+{
+    scope c = new C;
+    {c.func();}
+    {
+        I i = c;
+        {i.func();}
+    }
+    {printf("final %d\n", c.i);}
+    {assert(c.i == 44);}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/interface4.d	Sat Nov 24 06:33:00 2007 +0100
@@ -0,0 +1,33 @@
+module interface4;
+
+interface I
+{
+    void func();
+}
+
+interface I2
+{
+    void func();
+}
+
+class C : I,I2
+{
+    int i = 42;
+    override void func()
+    {
+        printf("hello %d\n", i);
+        i++;
+    }
+}
+
+void main()
+{
+    scope c = new C;
+    c.func();
+    I i = c;
+    i.func();
+    I2 i2 = c;
+    i2.func();
+    printf("final %d\n", c.i);
+    assert(c.i == 45);
+}