Mercurial > projects > ddmd
diff dmd/DelegateExp.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 2e2a5c3f943a |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/DelegateExp.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,218 @@ +module dmd.DelegateExp; + +import dmd.Expression; +import dmd.backend.elem; +import dmd.AggregateDeclaration; +import dmd.UnaExp; +import dmd.TypeDelegate; +import dmd.FuncDeclaration; +import dmd.MATCH; +import dmd.Type; +import dmd.OutBuffer; +import dmd.Loc; +import dmd.TY; +import dmd.Scope; +import dmd.InlineCostState; +import dmd.IRState; +import dmd.PREC; +import dmd.HdrGenState; +import dmd.TOK; + +import dmd.expression.Util; +import dmd.codegen.Util; +import dmd.backend.Util; +import dmd.backend.Symbol; +import dmd.backend.TYM; +import dmd.backend.OPER; + +class DelegateExp : UnaExp +{ + FuncDeclaration func; + int hasOverloads; + + this(Loc loc, Expression e, FuncDeclaration f, int hasOverloads = 0) + { + super(loc, TOK.TOKdelegate, DelegateExp.sizeof, e); + this.func = f; + this.hasOverloads = hasOverloads; + } + + Expression semantic(Scope sc) + { + version (LOGSEMANTIC) { + printf("DelegateExp.semantic('%s')\n", toChars()); + } + if (!type) + { + e1 = e1.semantic(sc); + type = new TypeDelegate(func.type); + type = type.semantic(loc, sc); + AggregateDeclaration ad = func.toParent().isAggregateDeclaration(); + if (func.needThis()) + e1 = getRightThis(loc, sc, ad, e1, func); + } + return this; + } + + MATCH implicitConvTo(Type t) + { + static if (false) { + printf("DelegateExp.implicitConvTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); + } + MATCH result; + + result = type.implicitConvTo(t); + + if (result == MATCHnomatch) + { + // Look for pointers to functions where the functions are overloaded. + FuncDeclaration f; + + t = t.toBasetype(); + if (type.ty == Tdelegate && type.nextOf().ty == Tfunction && + t.ty == Tdelegate && t.nextOf().ty == Tfunction) + { + if (func && func.overloadExactMatch(t.nextOf())) + result = MATCHexact; + } + } + return result; + } + + Expression castTo(Scope sc, Type t) + { + static if (false) { + printf("DelegateExp.castTo(this=%s, type=%s, t=%s)\n", + toChars(), type.toChars(), t.toChars()); + } + static string msg = "cannot form delegate due to covariant return type"; + + Expression e = this; + Type tb = t.toBasetype(); + Type typeb = type.toBasetype(); + if (tb != typeb) + { + // Look for delegates to functions where the functions are overloaded. + FuncDeclaration f; + + if (typeb.ty == Tdelegate && typeb.nextOf().ty == Tfunction && + tb.ty == Tdelegate && tb.nextOf().ty == Tfunction) + { + if (func) + { + f = func.overloadExactMatch(tb.nextOf()); + if (f) + { + int offset; + if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset) + error("%s", msg); + f.tookAddressOf++; + e = new DelegateExp(loc, e1, f); + e.type = t; + return e; + } + if (func.tintro) + error("%s", msg); + } + } + e = Expression.castTo(sc, t); + } + else + { + int offset; + + func.tookAddressOf++; + if (func.tintro && func.tintro.nextOf().isBaseOf(func.type.nextOf(), &offset) && offset) + error("%s", msg); + e = copy(); + e.type = t; + } + return e; + } + + void toCBuffer(OutBuffer buf, HdrGenState* hgs) + { + buf.writeByte('&'); + if (!func.isNested()) + { + expToCBuffer(buf, hgs, e1, PREC.PREC_primary); + buf.writeByte('.'); + } + buf.writestring(func.toChars()); + } + + void dump(int indent) + { + assert(false); + } + + int inlineCost(InlineCostState* ics) + { + assert(false); + } + + elem* toElem(IRState* irs) + { + elem* e; + elem* ethis; + elem* ep; + Symbol* sfunc; + int directcall = 0; + + //printf("DelegateExp.toElem() '%s'\n", toChars()); + sfunc = func.toSymbol(); + if (func.isNested()) + { + ep = el_ptr(sfunc); + ethis = getEthis(loc, irs, func); + } + else + { + ethis = e1.toElem(irs); + if (e1.type.ty != Tclass && e1.type.ty != Tpointer) + ethis = addressElem(ethis, e1.type); + + if (e1.op == TOKsuper) + directcall = 1; + + if (!func.isThis()) + error("delegates are only for non-static functions"); + + if (!func.isVirtual() || + directcall || + func.isFinal()) + { + ep = el_ptr(sfunc); + } + else + { + // Get pointer to function out of virtual table + assert(ethis); + ep = el_same(ðis); + ep = el_una(OPind, TYnptr, ep); + uint vindex = func.vtblIndex; + + // Build *(ep + vindex * 4) + ep = el_bin(OPadd,TYnptr,ep,el_long(TYint, vindex * 4)); + ep = el_una(OPind,TYnptr,ep); + } + + // if (func.tintro) + // func.error(loc, "cannot form delegate due to covariant return type"); + } + + if (ethis.Eoper == OPcomma) + { + ethis.E2() = el_pair(TYullong, ethis.E2, ep); + ethis.Ety = TYullong; + e = ethis; + } + else + e = el_pair(TYullong, ethis, ep); + + el_setLoc(e,loc); + + return e; + } +} \ No newline at end of file