view dmd/TypeClass.d @ 135:af1bebfd96a4 dmd2037

dmd 2.038
author Eldar Insafutdinov <e.insafutdinov@gmail.com>
date Mon, 13 Sep 2010 22:19:42 +0100
parents 60bb0fe4563e
children d8565fbd755c
line wrap: on
line source

module dmd.TypeClass;

import dmd.common;
import dmd.Type;
import dmd.ClassDeclaration;
import dmd.TypeInstance;
import dmd.Loc;
import dmd.Dsymbol;
import dmd.Scope;
import dmd.OutBuffer;
import dmd.HdrGenState;
import dmd.Expression;
import dmd.Identifier;
import dmd.MATCH;
import dmd.DYNCAST;
import dmd.CppMangleState;
import dmd.ArrayTypes;
import dmd.TypeInfoDeclaration;
import dmd.TY;
import dmd.MOD;
import dmd.Global;
import dmd.TypePointer;
import dmd.Declaration;
import dmd.VarDeclaration;
import dmd.TOK;
import dmd.DotExp;
import dmd.Id;
import dmd.ScopeExp;
import dmd.DotVarExp;
import dmd.VarExp;
import dmd.PtrExp;
import dmd.AddExp;
import dmd.IntegerExp;
import dmd.DotIdExp;
import dmd.EnumMember;
import dmd.TemplateMixin;
import dmd.TemplateDeclaration;
import dmd.TemplateInstance;
import dmd.OverloadSet;
import dmd.DotTypeExp;
import dmd.TupleExp;
import dmd.ClassInfoDeclaration;
import dmd.TypeInfoInterfaceDeclaration;
import dmd.TypeInfoClassDeclaration;
import dmd.Util;
import dmd.NullExp;
import dmd.TypeExp;
import dmd.DotTemplateExp;
import dmd.ErrorExp;
import dmd.ThisExp;
import dmd.CommaExp;

import dmd.expression.Util;
import dmd.backend.Symbol;
import dmd.backend.TYPE;
import dmd.backend.Util;
import dmd.backend.SC;
import dmd.backend.STR;
import dmd.backend.TYM;
import dmd.backend.LIST;
import dmd.backend.Classsym;

import std.string : toStringz;

class TypeClass : Type
{
    ClassDeclaration sym;

    this(ClassDeclaration sym)
	{
		super(TY.Tclass);
		this.sym = sym;
	}

version (DumbClone) {
} else {
	Type clone()
	{
		assert(false);
	}
}
    override ulong size(Loc loc)
	{
		return PTRSIZE;
	}
	
    override string toChars()
	{
		if (mod)
			return Type.toChars();
		return sym.toPrettyChars();
	}
	
    override Type syntaxCopy()
	{
		assert(false);
	}
	
    override Type semantic(Loc loc, Scope sc)
	{
		//printf("TypeClass.semantic(%s)\n", sym.toChars());
		if (deco)
			return this;
		//printf("\t%s\n", merge().deco);
		return merge();
	}
	
    override Dsymbol toDsymbol(Scope sc)
	{
		return sym;
	}
	
    override void toDecoBuffer(OutBuffer buf, int flag)
	{
		string name = sym.mangle();
		//printf("TypeClass.toDecoBuffer('%s' flag=%d mod=%x) = '%s'\n", toChars(), flag, mod, name);
		Type.toDecoBuffer(buf, flag);
		buf.printf("%s", name);
	}
	
    override void toCBuffer2(OutBuffer buf, HdrGenState* hgs, MOD mod)
	{
		if (mod != this.mod)
		{	
			toCBuffer3(buf, hgs, mod);
			return;
		}
		buf.writestring(sym.toChars());
	}

    override Expression dotExp(Scope sc, Expression e, Identifier ident)
	{
		uint offset;

		Expression b;
		VarDeclaration v;
		Dsymbol s;

version (LOGDOTEXP) {
		printf("TypeClass.dotExp(e='%s', ident='%s')\n", e.toChars(), ident.toChars());
}

		if (e.op == TOK.TOKdotexp)
		{
			DotExp de = cast(DotExp)e;

			if (de.e1.op == TOK.TOKimport)
			{
				ScopeExp se = cast(ScopeExp)de.e1;

				s = se.sds.search(e.loc, ident, 0);
				e = de.e1;
				goto L1;
			}
		}

		if (ident is Id.tupleof_)
		{
			/* Create a TupleExp
			 */
			e = e.semantic(sc);	// do this before turning on noaccesscheck
			Expressions exps = new Expressions;
			exps.reserve(sym.fields.dim);
			for (size_t i = 0; i < sym.fields.dim; i++)
			{   
				VarDeclaration v2 = cast(VarDeclaration)sym.fields[i];
				Expression fe = new DotVarExp(e.loc, e, v2);
				exps.push(fe);
			}
			e = new TupleExp(e.loc, exps);
			sc = sc.push();
			sc.noaccesscheck = 1;
			e = e.semantic(sc);
			sc.pop();
			return e;
		}

		s = sym.search(e.loc, ident, 0);
	L1:
		if (!s)
		{
			// See if it's a base class
			ClassDeclaration cbase;
			for (cbase = sym.baseClass; cbase; cbase = cbase.baseClass)
			{
				if (cbase.ident.equals(ident))
				{
					e = new DotTypeExp(Loc(0), e, cbase);
					return e;
				}
			}

			if (ident is Id.classinfo_)
			{
				assert(ClassDeclaration.classinfo);
				Type t = ClassDeclaration.classinfo.type;
				if (e.op == TOK.TOKtype || e.op == TOK.TOKdottype)
				{
					/* For type.classinfo, we know the classinfo
					 * at compile time.
					 */
					if (!sym.vclassinfo)
						sym.vclassinfo = new TypeInfoClassDeclaration(sym.type);

					e = new VarExp(e.loc, sym.vclassinfo);
					e = e.addressOf(sc);
					e.type = t;	// do this so we don't get redundant dereference
				}
				else
				{	
					/* For class objects, the classinfo reference is the first
					 * entry in the vtbl[]
					 */
					e = new PtrExp(e.loc, e);
					e.type = t.pointerTo();
					if (sym.isInterfaceDeclaration())
					{
						if (sym.isCPPinterface())
						{	
							/* C++ interface vtbl[]s are different in that the
							 * first entry is always pointer to the first virtual
							 * function, not classinfo.
							 * We can't get a .classinfo for it.
							 */
							error(e.loc, "no .classinfo for C++ interface objects");
						}
						/* For an interface, the first entry in the vtbl[]
						 * is actually a pointer to an instance of struct Interface.
						 * The first member of Interface is the .classinfo,
						 * so add an extra pointer indirection.
						 */
						e.type = e.type.pointerTo();
						e = new PtrExp(e.loc, e);
						e.type = t.pointerTo();
					}
					e = new PtrExp(e.loc, e, t);
				}
				return e;
			}

			if (ident is Id.__vptr)
			{   
				/* The pointer to the vtbl[]
				 * *cast(invariant(void*)**)e
				 */
				e = e.castTo(sc, tvoidptr.invariantOf().pointerTo().pointerTo());
				e = new PtrExp(e.loc, e);
				e = e.semantic(sc);
				return e;
			}

			if (ident is Id.__monitor)
			{   /* The handle to the monitor (call it a void*)
				 * *(cast(void**)e + 1)
				 */
				e = e.castTo(sc, tvoidptr.pointerTo());
				e = new AddExp(e.loc, e, new IntegerExp(1));
				e = new PtrExp(e.loc, e);
				e = e.semantic(sc);
				return e;
			}

			if (ident is Id.typeinfo_)
			{
				if (!global.params.useDeprecated)
					error(e.loc, ".typeinfo deprecated, use typeid(type)");

				return getTypeInfo(sc);
			}
			if (ident is Id.outer && sym.vthis)
			{
				s = sym.vthis;
			}
			else
			{
				return noMember(sc, e, ident);
			}
		}

		if (!s.isFuncDeclaration())	// because of overloading
			s.checkDeprecated(e.loc, sc);
		
		s = s.toAlias();
		v = s.isVarDeclaration();
		
		if (v && !v.isDataseg())
		{	
			Expression ei = v.getConstInitializer();

			if (ei)
			{   
				e = ei.copy();	// need to copy it if it's a StringExp
				e = e.semantic(sc);
				return e;
			}
		}

		if (s.getType())
		{
		//	if (e.op == TOKtype)
				return new TypeExp(e.loc, s.getType());
		//	return new DotTypeExp(e.loc, e, s);
		}

		EnumMember em = s.isEnumMember();
		if (em)
		{
			assert(em.value);
			return em.value.copy();
		}

		TemplateMixin tm = s.isTemplateMixin();
		if (tm)
		{
			Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, tm));
			de.type = e.type;
			return de;
		}

		TemplateDeclaration td = s.isTemplateDeclaration();
		if (td)
		{
			e = new DotTemplateExp(e.loc, e, td);
			e.semantic(sc);
			return e;
		}

		TemplateInstance ti = s.isTemplateInstance();
		if (ti)
		{	
			if (!ti.semanticRun)
				ti.semantic(sc);
			s = ti.inst.toAlias();
			if (!s.isTemplateInstance())
				goto L1;
			Expression de = new DotExp(e.loc, e, new ScopeExp(e.loc, ti));
			de.type = e.type;
			return de;
		}

		OverloadSet o = s.isOverloadSet();
		if (o)
		{	
			/* We really should allow this
			 */
			error(e.loc, "overload set for %s.%s not allowed in struct declaration", e.toChars(), ident.toChars());
			return new ErrorExp();
		}

		Declaration d = s.isDeclaration();
		if (!d)
		{
			e.error("%s.%s is not a declaration", e.toChars(), ident.toChars());
			return new ErrorExp();
		}

		if (e.op == TOK.TOKtype)
		{
			/* It's:
			 *    Class.d
			 */
			if (d.isTupleDeclaration())
			{
				e = new TupleExp(e.loc, d.isTupleDeclaration());
				e = e.semantic(sc);
				return e;
			}
			else if (d.needThis() && (hasThis(sc) || !(sc.intypeof || d.isFuncDeclaration())))
			{
				if (sc.func)
				{
					ClassDeclaration thiscd;
					thiscd = sc.func.toParent().isClassDeclaration();

					if (thiscd)
					{
						ClassDeclaration cd = e.type.isClassHandle();

						if (cd is thiscd)
						{
							e = new ThisExp(e.loc);
							e = new DotTypeExp(e.loc, e, cd);
							DotVarExp de = new DotVarExp(e.loc, e, d);
							e = de.semantic(sc);
							return e;
						}
						else if ((!cd || !cd.isBaseOf(thiscd, null)) && !d.isFuncDeclaration())
							e.error("'this' is required, but %s is not a base class of %s", e.type.toChars(), thiscd.toChars());
					}
				}

				/* Rewrite as:
				 *	this.d
				 */
				DotVarExp de = new DotVarExp(e.loc, new ThisExp(e.loc), d);
				e = de.semantic(sc);
				return e;
			}
			else
			{
				VarExp ve = new VarExp(e.loc, d, 1);
				return ve;
			}
		}

		if (d.isDataseg())
		{
			// (e, d)
			accessCheck(e.loc, sc, e, d);
			VarExp ve = new VarExp(e.loc, d);
			e = new CommaExp(e.loc, e, ve);
			e.type = d.type;
			return e;
		}

		if (d.parent && d.toParent().isModule())
		{
			// (e, d)
			VarExp ve = new VarExp(e.loc, d, 1);
			e = new CommaExp(e.loc, e, ve);
			e.type = d.type;
			return e;
		}

		DotVarExp de = new DotVarExp(e.loc, e, d);
		return de.semantic(sc);
	}
	
    override ClassDeclaration isClassHandle()
	{
		return sym;
	}
	
    override bool isBaseOf(Type t, int* poffset)
	{
		if (t.ty == Tclass)
		{   
			ClassDeclaration cd;

			cd   = (cast(TypeClass)t).sym;
			if (sym.isBaseOf(cd, poffset))
				return true;
		}
		
		return false;
	}
	
    override MATCH implicitConvTo(Type to)
	{
		//printf("TypeClass.implicitConvTo(to = '%s') %s\n", to.toChars(), toChars());
		MATCH m = constConv(to);
		if (m != MATCH.MATCHnomatch)
			return m;

		ClassDeclaration cdto = to.isClassHandle();
		if (cdto && cdto.isBaseOf(sym, null))
		{	
			//printf("'to' is base\n");
			return MATCH.MATCHconvert;
		}

		if (global.params.Dversion == 1)
		{
			// Allow conversion to (void *)
			if (to.ty == TY.Tpointer && (cast(TypePointer)to).next.ty == TY.Tvoid)
				return MATCH.MATCHconvert;
		}

		m = MATCH.MATCHnomatch;
		if (sym.aliasthis)
		{
			Declaration d = sym.aliasthis.isDeclaration();
			if (d)
			{   
				assert(d.type);
				Type t = d.type.addMod(mod);
				m = t.implicitConvTo(to);
			}
		}

		return m;
	}
	
    override Expression defaultInit(Loc loc)
	{
version (LOGDEFAULTINIT) {
		printf("TypeClass::defaultInit() '%s'\n", toChars());
}
		return new NullExp(loc, this);
	}
	
    override bool isZeroInit(Loc loc)
	{
		return true;
	}
	
    override MATCH 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(Loc(0), ti);
				return t.deduceType(sc, tparam, parameters, dedtypes);
			}

			/* Match things like:
			 *  S!(T).foo
			 */
			TypeInstance tpi = cast(TypeInstance)tparam;
			if (tpi.idents.dim)
			{   Identifier id = cast(Identifier)tpi.idents.data[tpi.idents.dim - 1];
				if (id.dyncast() == 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;
					}
				}
			}
		}

		// Extra check
		if (tparam && tparam.ty == Tclass)
		{
			TypeClass tp = cast(TypeClass)tparam;

			//printf("\t%d\n", (MATCH) implicitConvTo(tp));
			return implicitConvTo(tp);
		}
		return Type.deduceType(sc, tparam, parameters, dedtypes);
	}
	
    override bool isauto()
	{
		return sym.isauto;
	}
	
    override bool checkBoolean()
	{
		return true;
	}
	
    override TypeInfoDeclaration getTypeInfoDeclaration()
	{
		if (sym.isInterfaceDeclaration())
			return new TypeInfoInterfaceDeclaration(this);
		else
			return new TypeInfoClassDeclaration(this);
	}
	
    override bool hasPointers()
	{
		return true;
	}
	
    override bool builtinTypeInfo()
	{
		/* This is statically put out with the ClassInfo, so
		 * claim it is built in so it isn't regenerated by each module.
		 */
	version (DMDV2) {
		return mod ? false : true;
	} else {
		return true;
	}
	}
	
version (DMDV2) {
    override Type toHeadMutable()
	{
		assert(false);
	}
	
    override MATCH constConv(Type to)
	{
		if (equals(to))
			return MATCH.MATCHexact;

		if (ty == to.ty && sym == (cast(TypeClass)to).sym && to.mod == MOD.MODconst)
			return MATCH.MATCHconst;

		return MATCH.MATCHnomatch;
	}
	
version (CPP_MANGLE) {
    void toCppMangle(OutBuffer buf, CppMangleState* cms)
	{
		assert(false);
	}
}
}

    override type* toCtype()
	{
		type* t;
		Symbol* s;

		//printf("TypeClass.toCtype() %s\n", toChars());
		if (ctype)
			return ctype;

		/* Need this symbol to do C++ name mangling
		 */
		string name = sym.isCPPinterface() ? sym.ident.toChars() : sym.toPrettyChars();
		s = symbol_calloc(toStringz(name));
		s.Sclass = SC.SCstruct;
		s.Sstruct = struct_calloc();
		s.Sstruct.Sflags |= STR.STRclass;
		s.Sstruct.Salignsize = sym.alignsize;
		s.Sstruct.Sstructalign = cast(ubyte)sym.structalign;
		s.Sstruct.Sstructsize = sym.structsize;

		t = type_alloc(TYM.TYstruct);
		t.Ttag = cast(Classsym*)s;		// structure tag name
		t.Tcount++;
		s.Stype = t;
		slist_add(s);

		t = type_allocn(TYM.TYnptr, t);

		t.Tcount++;
		ctype = t;

		/* Add in fields of the class
		 * (after setting ctype to avoid infinite recursion)
		 */
		if (global.params.symdebug)
			for (int i = 0; i < sym.fields.dim; i++)
			{   
				VarDeclaration v = cast(VarDeclaration)sym.fields[i];

				Symbol* s2 = symbol_name(toStringz(v.ident.toChars()), SC.SCmember, v.type.toCtype());
				s2.Smemoff = v.offset;
				list_append(&s.Sstruct.Sfldlst, s2);
			}

		return t;
	}
	
    override Symbol* toSymbol()
	{
		return sym.toSymbol();
	}
}