http://d.puremagic.com/issues/show_bug.cgi?id=4173


Don <clugd...@yahoo.com.au> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |patch


--- Comment #4 from Don <clugd...@yahoo.com.au> 2010-09-03 11:19:35 PDT ---
This patch is a drop-in replacement for TypeClass::deduceType() in template.c,
line 2180 in D1, 2480 in D2. The patch is unchanged between D1 & D2.
It fixes these bugs:

bug 1715 Template specialization checks for equality rather than convertibility
bug 1970 Templated interfaces not matched
bug 4173 Regression(2.037) Explicitly instantiated templates still try to do
IFTI in some cases

It is far more general than any of those bugs. It checks all base interfaces,
and detects ambiguities. It copes with some pretty difficult cases:

interface TwoWay(A,B) {}
class C1: TwoWay!(char, float), TwoWay!(int, float) {}
class C2: TwoWay!(int, char), TwoWay!(float, char) {}

C1 twoway;
C2 twoway2;
B foo(A, B)(TwoWay!(A, B) x, TwoWay!(B, A) y) { return B.init;}

static assert(is(typeof(foo(twoway, twoway2)) == float));
static assert(is(typeof(foo(twoway2, twoway)) == char));

though it can only do this if it can determine at least one template parameter
from the first function parameter.

PATCH: Template.c line 2480, replacing TypeClass::deduceType()
----------------------
/* Helper for TypeClass::deduceType().
 * Classes can match with implicit conversion to a base class or interface. 
 * This is complicated, because there may be more than one base class which
 * matches. In such cases, one or more parameters remain ambiguous.
 * For example,
 *
 *   interface I(X, Y) {}
 *   class C : I(uint, double), I(char, double) {}
 *   C x;
 *   foo(T, U)( I!(T, U) x)
 *
 *   deduces that U is double, but T remains ambiguous (could be char or uint).
 *
 * Given a baseclass b, and initial deduced types 'dedtypes', this function
 * tries to match tparam with b, and also tries all base interfaces of b.
 * If a match occurs, numBaseClassMatches is incremented, and the new deduced
 * types are ANDed with the current 'best' estimate for dedtypes.
 */
void deduceBaseClassParameters(BaseClass *b, 
    Scope *sc, Type *tparam, TemplateParameters *parameters, Objects *dedtypes, 
    Objects *best, int &numBaseClassMatches)
{
    TemplateInstance *parti = b->base->parent->isTemplateInstance();
    if (parti) 
    {
        // Make a temporary copy of dedtypes so we don't destroy it
        Objects *tmpdedtypes = new Objects();
        tmpdedtypes->setDim(dedtypes->dim);
        memcpy(tmpdedtypes->data, dedtypes->data, dedtypes->dim * sizeof(void
*));

        TypeInstance *t = new TypeInstance(0, parti);
        MATCH m = t->deduceType(sc, tparam, parameters, tmpdedtypes);
        if (m != MATCHnomatch)
        {
            // If this is the first ever match, it becomes our best estimate
            if (numBaseClassMatches==0)
                memcpy(best->data, tmpdedtypes->data, tmpdedtypes->dim *
sizeof(void *));                        
            else for (size_t k = 0; k < tmpdedtypes->dim; ++k)
            {
                // If we've found more than one possible type for a parameter,
                // mark it as unknown.
                if (tmpdedtypes->data[k] != best->data[k])
                    best->data[k] = dedtypes->data[k];
            }
            ++numBaseClassMatches;
        }
    }
    // Now recursively test the inherited interfaces
    for (size_t j = 0; j < b->baseInterfaces_dim; ++j)
    {
        deduceBaseClassParameters( &(b->baseInterfaces)[j], 
            sc, tparam, parameters, dedtypes, 
            best, numBaseClassMatches);
    }

}

MATCH TypeClass::deduceType(Scope *sc, Type *tparam, TemplateParameters
*parameters, Objects *dedtypes)
{
    //printf("TypeClass::deduceType(this = %s)\n", toChars());

    /* If this class is a template class, and we're matching
     * it against a template instance, convert the class type
     * to a template instance, too, and try again.
     */
    TemplateInstance *ti = sym->parent->isTemplateInstance();

    if (tparam && tparam->ty == Tinstance)
    {
        if (ti && ti->toAlias() == sym)
        {
            TypeInstance *t = new TypeInstance(0, ti);
            MATCH m = t->deduceType(sc, tparam, parameters, dedtypes);
            // Even if the match fails, there is still a chance it could match
            // a base class.
            if (m != MATCHnomatch)
                return m;
        }        

        /* Match things like:
         *  S!(T).foo
         */
        TypeInstance *tpi = (TypeInstance *)tparam;
        if (tpi->idents.dim)
        {   Identifier *id = (Identifier *)tpi->idents.data[tpi->idents.dim -
1];
            if (id->dyncast() == DYNCAST_IDENTIFIER && sym->ident->equals(id))
            {
                Type *tparent = sym->parent->getType();
                if (tparent)
                {
                    /* Slice off the .foo in S!(T).foo
                     */
                    tpi->idents.dim--;
                    MATCH m = tparent->deduceType(sc, tpi, parameters,
dedtypes);
                    tpi->idents.dim++;
                    return m;
                }
            }
        }

        // If it matches exactly or via implicit conversion, we're done
        MATCH m = Type::deduceType(sc, tparam, parameters, dedtypes);
        if (m != MATCHnomatch)
            return m;

        /* There is still a chance to match via implicit conversion to
         * a base class or interface. Because there could be more than one such
         * match, we need to check them all.
         */

        int numBaseClassMatches = 0; // Have we found an interface match?

        // Our best guess at dedtypes
        Objects *best = new Objects();
        best->setDim(dedtypes->dim);

        ClassDeclaration *s = sym;
        while(s && s->baseclasses->dim > 0)
        {
            // Test the base class
            deduceBaseClassParameters((BaseClass *)(s->baseclasses->data[0]), 
                sc, tparam, parameters, dedtypes, 
                best, numBaseClassMatches);

            // Test the interfaces inherited by the base class    
            for (size_t i = 0; i < s->interfaces_dim; ++i)
            {
                BaseClass *b = s->interfaces[i];
                deduceBaseClassParameters(b, sc, tparam, parameters, dedtypes, 
                    best, numBaseClassMatches);
            }
            s = ((BaseClass *)(s->baseclasses->data[0]))->base;
        }            

        if (numBaseClassMatches == 0)
            return MATCHnomatch;

        // If we got at least one match, copy the known types into dedtypes
        memcpy(dedtypes->data, best->data, best->dim * sizeof(void *));
        return MATCHconvert;
    }

    // Extra check
    if (tparam && tparam->ty == Tclass)
    {
        TypeClass *tp = (TypeClass *)tparam;

        //printf("\t%d\n", (MATCH) implicitConvTo(tp));
        return implicitConvTo(tp);
    }
    return Type::deduceType(sc, tparam, parameters, dedtypes);
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------

Reply via email to