Mercurial > projects > ddmd
diff dmd/expression/Util.d @ 0:10317f0c89a5
Initial commit
author | korDen |
---|---|
date | Sat, 24 Oct 2009 08:42:06 +0400 |
parents | |
children | 5c9b78899f5d |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd/expression/Util.d Sat Oct 24 08:42:06 2009 +0400 @@ -0,0 +1,1363 @@ +module dmd.expression.Util; + +import dmd.Expression; +import dmd.Loc; +import dmd.BUILTIN; +import dmd.Scope; +import dmd.FuncExp; +import dmd.DelegateExp; +import dmd.LINK; +import dmd.NullExp; +import dmd.SymOffExp; +import dmd.ExpInitializer; +import dmd.Lexer; +import dmd.TypeSArray; +import dmd.TypeArray; +import dmd.VarDeclaration; +import dmd.VoidInitializer; +import dmd.DeclarationExp; +import dmd.VarExp; +import dmd.NewExp; +import dmd.STC; +import dmd.WANT; +import dmd.IndexExp; +import dmd.AssignExp; +import dmd.CommaExp; +import dmd.Argument; +import dmd.DefaultInitExp; +import dmd.Identifier; +import dmd.Dsymbol; +import dmd.Global; +import dmd.ScopeDsymbol; +import dmd.DotIdExp; +import dmd.DotVarExp; +import dmd.CallExp; +import dmd.TY; +import dmd.MATCH; +import dmd.TypeFunction; +import dmd.declaration.Match; +import dmd.ArrayTypes; +import dmd.Declaration; +import dmd.FuncAliasDeclaration; +import dmd.AliasDeclaration; +import dmd.FuncDeclaration; +import dmd.TemplateDeclaration; +import dmd.AggregateDeclaration; +import dmd.IntegerExp; +import dmd.Type; +import dmd.TOK; +import dmd.TypeExp; +import dmd.TypeTuple; +import dmd.TupleExp; +import dmd.OutBuffer; +import dmd.HdrGenState; +import dmd.ClassDeclaration; +import dmd.TypeClass; +import dmd.StructDeclaration; +import dmd.TypeStruct; +import dmd.MOD; +import dmd.PROT; +import dmd.PREC; +import dmd.Util; +import dmd.TypeAArray; +import dmd.Id; + +import std.stdio : writef; + + +/*********************************** + * Utility to build a function call out of this reference and argument. + */ +Expression build_overload(Loc loc, Scope sc, Expression ethis, Expression earg, Identifier id) +{ + Expression e; + + //printf("build_overload(id = '%s')\n", id.toChars()); + //earg.print(); + //earg.type.print(); + e = new DotIdExp(loc, ethis, id); + + if (earg) + e = new CallExp(loc, e, earg); + else + e = new CallExp(loc, e); + + e = e.semantic(sc); + return e; +} + +/*************************************** + * Search for function funcid in aggregate ad. + */ + +Dsymbol search_function(ScopeDsymbol ad, Identifier funcid) +{ + Dsymbol s; + FuncDeclaration fd; + TemplateDeclaration td; + + s = ad.search(Loc(0), funcid, 0); + if (s) + { + Dsymbol s2; + + //printf("search_function: s = '%s'\n", s.kind()); + s2 = s.toAlias(); + //printf("search_function: s2 = '%s'\n", s2.kind()); + fd = s2.isFuncDeclaration(); + if (fd && fd.type.ty == TY.Tfunction) + return fd; + + td = s2.isTemplateDeclaration(); + if (td) + return td; + } + + return null; +} + +/******************************************** + * Find function in overload list that exactly matches t. + */ + +/*************************************************** + * Visit each overloaded function in turn, and call + * dg(param, f) on it. + * Exit when no more, or dg(param, f) returns 1. + * Returns: + * 0 continue + * 1 done + */ + +int overloadApply(FuncDeclaration fstart, int delegate(FuncDeclaration) dg) +{ + FuncDeclaration f; + Declaration d; + Declaration next; + + for (d = fstart; d; d = next) + { + FuncAliasDeclaration fa = d.isFuncAliasDeclaration(); + + if (fa) + { + if (overloadApply(fa.funcalias, dg)) + return 1; + next = fa.overnext; + } + else + { + AliasDeclaration a = d.isAliasDeclaration(); + + if (a) + { + Dsymbol s = a.toAlias(); + next = s.isDeclaration(); + if (next is a) + break; + if (next is fstart) + break; + } + else + { + f = d.isFuncDeclaration(); + if (f is null) + { + d.error("is aliased to a function"); + break; // BUG: should print error message? + } + if (dg(f)) + return 1; + + next = f.overnext; + } + } + } + return 0; +} + +/******************************************** + * Decide which function matches the arguments best. + */ + +struct Param2 +{ + Match* m; + Expression ethis; + Expressions arguments; + + int fp2(FuncDeclaration f) + { + MATCH match; + + if (f != m.lastf) // skip duplicates + { + m.anyf = f; + TypeFunction tf = cast(TypeFunction)f.type; + match = tf.callMatch(f.needThis() ? ethis : null, arguments); + //printf("match = %d\n", match); + if (match != MATCH.MATCHnomatch) + { + if (match > m.last) + goto LfIsBetter; + + if (match < m.last) + goto LlastIsBetter; + + /* See if one of the matches overrides the other. + */ + if (m.lastf.overrides(f)) + goto LlastIsBetter; + else if (f.overrides(m.lastf)) + goto LfIsBetter; + + /* Try to disambiguate using template-style partial ordering rules. + * In essence, if f() and g() are ambiguous, if f() can call g(), + * but g() cannot call f(), then pick f(). + * This is because f() is "more specialized." + */ + { + MATCH c1 = f.leastAsSpecialized(m.lastf); + MATCH c2 = m.lastf.leastAsSpecialized(f); + //printf("c1 = %d, c2 = %d\n", c1, c2); + if (c1 > c2) + goto LfIsBetter; + if (c1 < c2) + goto LlastIsBetter; + } + + Lambiguous: + m.nextf = f; + m.count++; + return 0; + + LfIsBetter: + m.last = match; + m.lastf = f; + m.count = 1; + return 0; + + LlastIsBetter: + return 0; + } + } + return 0; + } +} + +struct Param1 +{ + Type t; // type to match + FuncDeclaration f; // return value + + int fp1(FuncDeclaration f) + { + if (t.equals(f.type)) + { + this.f = f; + return 1; + } + + version (DMDV2) { + /* Allow covariant matches, if it's just a const conversion + * of the return type + */ + if (t.ty == Tfunction) + { + TypeFunction tf = cast(TypeFunction)f.type; + if (tf.covariant(t) == 1 && + tf.nextOf().implicitConvTo(t.nextOf()) >= MATCHconst) + { + this.f = f; + return 1; + } + } + } + return 0; + } +} + +void overloadResolveX(Match* m, FuncDeclaration fstart, Expression ethis, Expressions arguments) +{ + Param2 p; + p.m = m; + p.ethis = ethis; + p.arguments = arguments; + overloadApply(fstart, &p.fp2); +} + +void templateResolve(Match* m, TemplateDeclaration td, Scope sc, Loc loc, Objects targsi, Expression ethis, Expressions arguments) +{ + FuncDeclaration fd; + + assert(td); + fd = td.deduceFunctionTemplate(sc, loc, targsi, ethis, arguments); + if (!fd) + return; + m.anyf = fd; + if (m.last >= MATCH.MATCHexact) + { + m.nextf = fd; + m.count++; + } + else + { + m.last = MATCH.MATCHexact; + m.lastf = fd; + m.count = 1; + } +} + +/****************************** + * Perform semantic() on an array of Expressions. + */ + +void arrayExpressionSemantic(Expressions exps, Scope sc) +{ + if (exps) + { + for (size_t i = 0; i < exps.dim; i++) + { + Expression e = cast(Expression)exps.data[i]; + + e = e.semantic(sc); + exps.data[i] = cast(void*)e; + } + } +} + +/**************************************** + * Preprocess arguments to function. + */ + +void preFunctionArguments(Loc loc, Scope sc, Expressions exps) +{ + if (exps) + { + expandTuples(exps); + + for (size_t i = 0; i < exps.dim; i++) + { + Expression arg = cast(Expression)exps.data[i]; + + if (!arg.type) + { +debug { + if (!global.gag) + writef("1: \n"); +} + arg.error("%s is not an expression", arg.toChars()); + arg = new IntegerExp(arg.loc, 0, Type.tint32); + } + + arg = resolveProperties(sc, arg); + exps.data[i] = cast(void*) arg; + + //arg.rvalue(); +static if (false) { + if (arg.type.ty == TY.Tfunction) + { + arg = new AddrExp(arg.loc, arg); + arg = arg.semantic(sc); + exps.data[i] = cast(void*) arg; + } +} + } + } +} + +/************************************************************* + * Given var, we need to get the + * right 'this' pointer if var is in an outer class, but our + * existing 'this' pointer is in an inner class. + * Input: + * e1 existing 'this' + * ad struct or class we need the correct 'this' for + * var the specific member of ad we're accessing + */ + +Expression getRightThis(Loc loc, Scope sc, AggregateDeclaration ad, Expression e1, Declaration var) +{ + //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars()); + L1: + Type t = e1.type.toBasetype(); + //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars()); + + /* If e1 is not the 'this' pointer for ad + */ + if (ad && !(t.ty == TY.Tpointer && t.nextOf().ty == TY.Tstruct && (cast(TypeStruct)t.nextOf()).sym == ad) && !(t.ty == TY.Tstruct && (cast(TypeStruct)t).sym == ad)) + { + ClassDeclaration cd = ad.isClassDeclaration(); + ClassDeclaration tcd = t.isClassHandle(); + + /* e1 is the right this if ad is a base class of e1 + */ + if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null))) + { + /* Only classes can be inner classes with an 'outer' + * member pointing to the enclosing class instance + */ + if (tcd && tcd.isNested()) + { + /* e1 is the 'this' pointer for an inner class: tcd. + * Rewrite it as the 'this' pointer for the outer class. + */ + + e1 = new DotVarExp(loc, e1, tcd.vthis); + e1.type = tcd.vthis.type; + // Do not call checkNestedRef() + //e1 = e1.semantic(sc); + + // Skip up over nested functions, and get the enclosing + // class type. + int n = 0; + Dsymbol s; + for (s = tcd.toParent(); s && s.isFuncDeclaration(); s = s.toParent()) + { + FuncDeclaration f = s.isFuncDeclaration(); + if (f.vthis) + { + //printf("rewriting e1 to %s's this\n", f.toChars()); + n++; + e1 = new VarExp(loc, f.vthis); + } + } + if (s && s.isClassDeclaration()) + { + e1.type = s.isClassDeclaration().type; + if (n > 1) + e1 = e1.semantic(sc); + } + else + e1 = e1.semantic(sc); + goto L1; + } + /* Can't find a path from e1 to ad + */ + e1.error("this for %s needs to be type %s not type %s", var.toChars(), ad.toChars(), t.toChars()); + } + } + return e1; +} + +/******************************************* + * Given a symbol that could be either a FuncDeclaration or + * a function template, resolve it to a function symbol. + * sc instantiation scope + * loc instantiation location + * targsi initial list of template arguments + * ethis if !null, the 'this' pointer argument + * fargs arguments to function + * flags 1: do not issue error message on no match, just return null + */ + +FuncDeclaration resolveFuncCall(Scope sc, Loc loc, Dsymbol s, + Objects tiargs, + Expression ethis, + Expressions arguments, + int flags) +{ + if (!s) + return null; // no match + FuncDeclaration f = s.isFuncDeclaration(); + if (f) + f = f.overloadResolve(loc, ethis, arguments); + else + { + TemplateDeclaration td = s.isTemplateDeclaration(); + assert(td); + f = td.deduceFunctionTemplate(sc, loc, tiargs, null, arguments, flags); + } + return f; +} + +/**************************************** + * Now that we know the exact type of the function we're calling, + * the arguments[] need to be adjusted: + * 1. implicitly convert argument to the corresponding parameter type + * 2. add default arguments for any missing arguments + * 3. do default promotions on arguments corresponding to ... + * 4. add hidden _arguments[] argument + * 5. call copy constructor for struct value arguments + */ + +void functionArguments(Loc loc, Scope sc, TypeFunction tf, Expressions arguments) +{ + uint n; + + //printf("functionArguments()\n"); + assert(arguments); + size_t nargs = arguments ? arguments.dim : 0; + size_t nparams = Argument.dim(tf.parameters); + + if (nargs > nparams && tf.varargs == 0) + error(loc, "expected %zu arguments, not %zu for non-variadic function type %s", nparams, nargs, tf.toChars()); + + n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams) + + int done = 0; + for (size_t i = 0; i < n; i++) + { + Expression arg; + + if (i < nargs) + arg = cast(Expression)arguments.data[i]; + else + arg = null; + + Type tb; + + if (i < nparams) + { + Argument p = Argument.getNth(tf.parameters, i); + + if (!arg) + { + if (!p.defaultArg) + { + if (tf.varargs == 2 && i + 1 == nparams) + goto L2; + + error(loc, "expected %d function arguments, not %d", nparams, nargs); + break; + } + arg = p.defaultArg; +version (DMDV2) { + if (arg.op == TOK.TOKdefault) + { + DefaultInitExp de = cast(DefaultInitExp)arg; + arg = de.resolve(loc, sc); + } + else + { + arg = arg.copy(); + } +} else { + arg = arg.copy(); +} + arguments.push(cast(void*)arg); + nargs++; + } + + if (tf.varargs == 2 && i + 1 == nparams) + { + //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars()); + if (arg.implicitConvTo(p.type)) + { + if (nargs != nparams) + error(loc, "expected %zu function arguments, not %zu", nparams, nargs); + goto L1; + } + L2: + tb = p.type.toBasetype(); /// + Type tret = p.isLazyArray(); + switch (tb.ty) + { + case TY.Tsarray: + case TY.Tarray: + { // Create a static array variable v of type arg.type +version (IN_GCC) { + /* GCC 4.0 does not like zero length arrays used like + this; pass a null array value instead. Could also + just make a one-element array. */ + if (nargs - i == 0) + { + arg = new NullExp(loc); + break; + } +} + Identifier id = Lexer.uniqueId("__arrayArg"); + Type t = new TypeSArray((cast(TypeArray)tb).next, new IntegerExp(nargs - i)); + t = t.semantic(loc, sc); + VarDeclaration v = new VarDeclaration(loc, t, id, new VoidInitializer(loc)); + v.semantic(sc); + v.parent = sc.parent; + //sc.insert(v); + + Expression c = new DeclarationExp(Loc(0), v); + c.type = v.type; + + for (size_t u = i; u < nargs; u++) + { + Expression a = cast(Expression)arguments.data[u]; + if (tret && !(cast(TypeArray)tb).next.equals(a.type)) + a = a.toDelegate(sc, tret); + + Expression e = new VarExp(loc, v); + e = new IndexExp(loc, e, new IntegerExp(u + 1 - nparams)); + AssignExp ae = new AssignExp(loc, e, a); + + version (DMDV2) { + ae.op = TOK.TOKconstruct; + } + + if (c) + c = new CommaExp(loc, c, ae); + else + c = ae; + } + + arg = new VarExp(loc, v); + if (c) + arg = new CommaExp(loc, c, arg); + break; + } + + case TY.Tclass: + { /* Set arg to be: + * new Tclass(arg0, arg1, ..., argn) + */ + Expressions args = new Expressions(); + args.setDim(nargs - i); + for (size_t u = i; u < nargs; u++) + args.data[u - i] = arguments.data[u]; + arg = new NewExp(loc, null, null, p.type, args); + break; + } + + default: + if (!arg) + { + error(loc, "not enough arguments"); + return; + } + break; + } + + arg = arg.semantic(sc); + //printf("\targ = '%s'\n", arg.toChars()); + arguments.setDim(i + 1); + done = 1; + } + + L1: + if (!(p.storageClass & STC.STClazy && p.type.ty == TY.Tvoid)) + { + if (p.type != arg.type) + { + //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars()); + arg = arg.implicitCastTo(sc, p.type); + arg = arg.optimize(WANT.WANTvalue); + } + } + if (p.storageClass & STC.STCref) + { + arg = arg.toLvalue(sc, arg); + } + else if (p.storageClass & STC.STCout) + { + arg = arg.modifiableLvalue(sc, arg); + } + + // Convert static arrays to pointers + tb = arg.type.toBasetype(); + if (tb.ty == TY.Tsarray) + { + arg = arg.checkToPointer(); + } +version (DMDV2) { + if (tb.ty == TY.Tstruct && !(p.storageClass & (STC.STCref | STC.STCout))) + { + arg = callCpCtor(loc, sc, arg); + } +} + + // Convert lazy argument to a delegate + if (p.storageClass & STC.STClazy) + { + arg = arg.toDelegate(sc, p.type); + } +version (DMDV2) { + /* Look for arguments that cannot 'escape' from the called + * function. + */ + if (!tf.parameterEscapes(p)) + { + /* Function literals can only appear once, so if this + * appearance was scoped, there cannot be any others. + */ + if (arg.op == TOK.TOKfunction) + { + FuncExp fe = cast(FuncExp)arg; + fe.fd.tookAddressOf = 0; + } + + /* For passing a delegate to a scoped parameter, + * this doesn't count as taking the address of it. + * We only worry about 'escaping' references to the function. + */ + else if (arg.op == TOK.TOKdelegate) + { + DelegateExp de = cast(DelegateExp)arg; + if (de.e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)de.e1; + FuncDeclaration f = ve.var.isFuncDeclaration(); + if (f) + { + f.tookAddressOf--; + //printf("tookAddressOf = %d\n", f.tookAddressOf); + } + } + } + } +} + } + else + { + // If not D linkage, do promotions + if (tf.linkage != LINK.LINKd) + { + // Promote bytes, words, etc., to ints + arg = arg.integralPromotions(sc); + + // Promote floats to doubles + switch (arg.type.ty) + { + case TY.Tfloat32: + arg = arg.castTo(sc, Type.tfloat64); + break; + + case TY.Timaginary32: + arg = arg.castTo(sc, Type.timaginary64); + break; + default: + break; + } + } + + // Convert static arrays to dynamic arrays + tb = arg.type.toBasetype(); + if (tb.ty == TY.Tsarray) + { + TypeSArray ts = cast(TypeSArray)tb; + Type ta = ts.next.arrayOf(); + if (ts.size(arg.loc) == 0) + { + arg = new NullExp(arg.loc); + arg.type = ta; + } + else + { + arg = arg.castTo(sc, ta); + } + } +version (DMDV2) { + if (tb.ty == TY.Tstruct) + { + arg = callCpCtor(loc, sc, arg); + } + + // Give error for overloaded function addresses + if (arg.op == TOK.TOKsymoff) + { + SymOffExp se = cast(SymOffExp)arg; + if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique()) + arg.error("function %s is overloaded", arg.toChars()); + } +} + arg.rvalue(); + } + arg = arg.optimize(WANT.WANTvalue); + arguments.data[i] = cast(void*) arg; + if (done) + break; + } + + // If D linkage and variadic, add _arguments[] as first argument + if (tf.linkage == LINK.LINKd && tf.varargs == 1) + { + Expression e = createTypeInfoArray(sc, cast(Expression*)&arguments.data[nparams], arguments.dim - nparams); + arguments.insert(0, cast(void*)e); + } +} + +/**************************************** + * Expand tuples. + */ + +void expandTuples(Expressions exps) +{ + //printf("expandTuples()\n"); + if (exps) + { + for (size_t i = 0; i < exps.dim; i++) + { + Expression arg = cast(Expression)exps.data[i]; + if (!arg) + continue; + + // Look for tuple with 0 members + if (arg.op == TOK.TOKtype) + { + TypeExp e = cast(TypeExp)arg; + if (e.type.toBasetype().ty == TY.Ttuple) + { + TypeTuple tt = cast(TypeTuple)e.type.toBasetype(); + + if (!tt.arguments || tt.arguments.dim == 0) + { + exps.remove(i); + if (i == exps.dim) + return; + i--; + continue; + } + } + } + + // Inline expand all the tuples + while (arg.op == TOK.TOKtuple) + { + TupleExp te = cast(TupleExp)arg; + + exps.remove(i); // remove arg + exps.insert(i, cast(void*)te.exps); // replace with tuple contents + + if (i == exps.dim) + return; // empty tuple, no more arguments + + arg = cast(Expression)exps.data[i]; + } + } + } +} + +/************************************************** + * Write out argument types to buf. + */ + +void argExpTypesToCBuffer(OutBuffer buf, Expressions arguments, HdrGenState* hgs) +{ + if (arguments) + { + scope OutBuffer argbuf = new OutBuffer(); + + for (size_t i = 0; i < arguments.dim; i++) + { + Expression arg = cast(Expression)arguments.data[i]; + + if (i) + buf.writeByte(','); + + argbuf.reset(); + arg.type.toCBuffer2(argbuf, hgs, MOD.MODundefined); + buf.write(argbuf); + } + } +} + +/**************************************** + * Determine if scope sc has package level access to s. + */ + +bool hasPackageAccess(Scope sc, Dsymbol s) +{ +version (LOG) { + printf("hasPackageAccess(s = '%s', sc = '%p')\n", s.toChars(), sc); +} + + for (; s; s = s.parent) + { + if (s.isPackage() && !s.isModule()) + break; + } +version (LOG) { + if (s) + printf("\tthis is in package '%s'\n", s.toChars()); +} + + if (s && s == sc.module_.parent) + { +version (LOG) { + printf("\ts is in same package as sc\n"); +} + return true; + } + + +version (LOG) { + printf("\tno package access\n"); +} + + return false; +} + +/********************************************* + * Call copy constructor for struct value argument. + */ +version (DMDV2) { + Expression callCpCtor(Loc loc, Scope sc, Expression e) + { + Type tb = e.type.toBasetype(); + assert(tb.ty == Tstruct); + StructDeclaration sd = (cast(TypeStruct)tb).sym; + if (sd.cpctor) + { + /* Create a variable tmp, and replace the argument e with: + * (tmp = e),tmp + * and let AssignExp() handle the construction. + * This is not the most efficent, ideally tmp would be constructed + * directly onto the stack. + */ + Identifier idtmp = Lexer.uniqueId("__tmp"); + VarDeclaration tmp = new VarDeclaration(loc, tb, idtmp, new ExpInitializer(Loc(0), e)); + Expression ae = new DeclarationExp(loc, tmp); + e = new CommaExp(loc, ae, new VarExp(loc, tmp)); + e = e.semantic(sc); + } + return e; + } +} + +/*************************************** + * Create a static array of TypeInfo references + * corresponding to an array of Expression's. + * Used to supply hidden _arguments[] value for variadic D functions. + */ + +Expression createTypeInfoArray(Scope sc, Expression* exps, int dim) +{ + assert(false); +} + +/************************************** + * Evaluate builtin function. + * Return result: null if cannot evaluate it. + */ + +Expression eval_builtin(BUILTIN builtin, Expressions arguments) +{ + assert(false); +} + +Expression fromConstInitializer(int result, Expression e1) +{ + //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars()); + //static int xx; if (xx++ == 10) assert(0); + Expression e = e1; + if (e1.op == TOK.TOKvar) + { + VarExp ve = cast(VarExp)e1; + VarDeclaration v = ve.var.isVarDeclaration(); + e = expandVar(result, v); + if (e) + { + if (e.type != e1.type) + { + // Type 'paint' operation + e = e.copy(); + e.type = e1.type; + } + } + else + { + e = e1; + } + } + return e; +} + +/************************************* + * If variable has a const initializer, + * return that initializer. + */ + +Expression expandVar(int result, VarDeclaration v) +{ + //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v.toChars() : "null"); + + Expression e = null; + if (!v) + return e; + + if (v.isConst() || v.isInvariant() || v.storage_class & STC.STCmanifest) + { + if (!v.type) + { + //error("ICE"); + return e; + } + + Type tb = v.type.toBasetype(); + if (result & WANT.WANTinterpret || v.storage_class & STC.STCmanifest || (tb.ty != TY.Tsarray && tb.ty != TY.Tstruct)) + { + if (v.init) + { + if (v.inuse) + { + if (v.storage_class & STC.STCmanifest) + v.error("recursive initialization of constant"); + goto L1; + } + Expression ei = v.init.toExpression(); + if (!ei) + goto L1; + if (ei.op == TOK.TOKconstruct || ei.op == TOK.TOKblit) + { + AssignExp ae = cast(AssignExp)ei; + ei = ae.e2; + if (ei.isConst() != 1 && ei.op != TOK.TOKstring) + goto L1; + if (ei.type != v.type) + goto L1; + } + if (v.scope_) + { + v.inuse++; + e = ei.syntaxCopy(); + e = e.semantic(v.scope_); + e = e.implicitCastTo(v.scope_, v.type); + // enabling this line causes test22 in test suite to fail + //ei.type = e.type; + v.scope_ = null; + v.inuse--; + } + else if (!ei.type) + { + goto L1; + } + else + // Should remove the copy() operation by + // making all mods to expressions copy-on-write + e = ei.copy(); + } + else + { +static if (true) { + goto L1; +} else { + // BUG: what if const is initialized in constructor? + e = v.type.defaultInit(); + e.loc = e1.loc; +} + } + if (e.type != v.type) + { + e = e.castTo(null, v.type); + } + v.inuse++; + e = e.optimize(result); + v.inuse--; + } + } +L1: + //if (e) printf("\te = %s, e.type = %s\n", e.toChars(), e.type.toChars()); + return e; +} + +/**************************************** + * Check access to d for expression e.d + */ + +void accessCheck(Loc loc, Scope sc, Expression e, Declaration d) +{ +version (LOG) { + if (e) + { + printf("accessCheck(%s . %s)\n", e.toChars(), d.toChars()); + printf("\te.type = %s\n", e.type.toChars()); + } + else + { + //printf("accessCheck(%s)\n", d.toChars()); + } +} + if (!e) + { + if (d.prot() == PROT.PROTprivate && d.getModule() != sc.module_ || + d.prot() == PROT.PROTpackage && !hasPackageAccess(sc, d)) + + error(loc, "%s %s.%s is not accessible from %s", + d.kind(), d.getModule().toChars(), d.toChars(), sc.module_.toChars()); + } + else if (e.type.ty == TY.Tclass) + { + // Do access check + ClassDeclaration cd; + + cd = cast(ClassDeclaration)((cast(TypeClass)e.type).sym); +static if (true) { + if (e.op == TOK.TOKsuper) + { + ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration(); + if (cd2) + cd = cd2; + } +} + cd.accessCheck(loc, sc, d); + } + else if (e.type.ty == TY.Tstruct) + { + // Do access check + StructDeclaration cd = cast(StructDeclaration)((cast(TypeStruct)e.type).sym); + cd.accessCheck(loc, sc, d); + } +} + +/***************************************** + * Given array of arguments and an aggregate type, + * if any of the argument types are missing, attempt to infer + * them from the aggregate type. + */ + +void inferApplyArgTypes(TOK op, Arguments arguments, Expression aggr) +{ + if (!arguments || !arguments.dim) + return; + + /* Return if no arguments need types. + */ + for (size_t u = 0; 1; u++) + { + if (u == arguments.dim) + return; + + Argument arg = cast(Argument)arguments.data[u]; + if (!arg.type) + break; + } + + AggregateDeclaration ad; + + Argument arg = cast(Argument)arguments.data[0]; + Type taggr = aggr.type; + if (!taggr) + return; + Type tab = taggr.toBasetype(); + switch (tab.ty) + { + case TY.Tarray: + case TY.Tsarray: + case TY.Ttuple: + if (arguments.dim == 2) + { + if (!arg.type) + arg.type = Type.tsize_t; // key type + arg = cast(Argument)arguments.data[1]; + } + if (!arg.type && tab.ty != TY.Ttuple) + arg.type = tab.nextOf(); // value type + break; + + case TY.Taarray: + { + TypeAArray taa = cast(TypeAArray)tab; + + if (arguments.dim == 2) + { + if (!arg.type) + arg.type = taa.index; // key type + arg = cast(Argument)arguments.data[1]; + } + if (!arg.type) + arg.type = taa.next; // value type + break; + } + + case TY.Tclass: + ad = (cast(TypeClass)tab).sym; + goto Laggr; + + case TY.Tstruct: + ad = (cast(TypeStruct)tab).sym; + goto Laggr; + + Laggr: + if (arguments.dim == 1) + { + if (!arg.type) + { + /* Look for a head() or rear() overload + */ + Identifier id = (op == TOK.TOKforeach) ? Id.Fhead : Id.Ftoe; + Dsymbol s = search_function(ad, id); + FuncDeclaration fd = s ? s.isFuncDeclaration() : null; + if (!fd) + { + if (s && s.isTemplateDeclaration()) + break; + goto Lapply; + } + arg.type = fd.type.nextOf(); + } + break; + } + + Lapply: + { /* Look for an + * int opApply(int delegate(ref Type [, ...]) dg); + * overload + */ + Dsymbol s = search_function(ad, (op == TOK.TOKforeach_reverse) ? Id.applyReverse : Id.apply); + if (s) + { + FuncDeclaration fd = s.isFuncDeclaration(); + if (fd) + { + inferApplyArgTypesX(fd, arguments); + break; + } +static if (false) { + TemplateDeclaration td = s.isTemplateDeclaration(); + if (td) + { + inferApplyArgTypesZ(td, arguments); + break; + } +} + } + break; + } + + case TY.Tdelegate: + { + if (0 && aggr.op == TOK.TOKdelegate) + { + DelegateExp de = cast(DelegateExp)aggr; + + FuncDeclaration fd = de.func.isFuncDeclaration(); + if (fd) + inferApplyArgTypesX(fd, arguments); + } + else + { + inferApplyArgTypesY(cast(TypeFunction)tab.nextOf(), arguments); + } + break; + } + + default: + break; // ignore error, caught later + } +} + +struct Param3 +{ + /******************************** + * Recursive helper function, + * analogous to func.overloadResolveX(). + */ + + int fp3(FuncDeclaration f) + { + TypeFunction tf = cast(TypeFunction)f.type; + if (inferApplyArgTypesY(tf, arguments) == 1) + return 0; + + if (arguments.dim == 0) + return 1; + + return 0; + } + + Arguments arguments; +} + +void inferApplyArgTypesX(FuncDeclaration fstart, Arguments arguments) +{ + Param3 p3; + p3.arguments = arguments; + overloadApply(fstart, &p3.fp3); +} + +/****************************** + * Infer arguments from type of function. + * Returns: + * 0 match for this function + * 1 no match for this function + */ + +int inferApplyArgTypesY(TypeFunction tf, Arguments arguments) +{ + size_t nparams; + Argument p; + + if (Argument.dim(tf.parameters) != 1) + goto Lnomatch; + + p = Argument.getNth(tf.parameters, 0); + if (p.type.ty != TY.Tdelegate) + goto Lnomatch; + + tf = cast(TypeFunction)p.type.nextOf(); + assert(tf.ty == TY.Tfunction); + + /* We now have tf, the type of the delegate. Match it against + * the arguments, filling in missing argument types. + */ + nparams = Argument.dim(tf.parameters); + if (nparams == 0 || tf.varargs) + goto Lnomatch; // not enough parameters + if (arguments.dim != nparams) + goto Lnomatch; // not enough parameters + + for (size_t u = 0; u < nparams; u++) + { + Argument arg = cast(Argument)arguments.data[u]; + Argument param = Argument.getNth(tf.parameters, u); + if (arg.type) + { + if (!arg.type.equals(param.type)) + { + /* Cannot resolve argument types. Indicate an + * error by setting the number of arguments to 0. + */ + arguments.dim = 0; + goto Lmatch; + } + continue; + } + arg.type = param.type; + } + + Lmatch: + return 0; + + Lnomatch: + return 1; +} + +/************************************************** + * Write expression out to buf, but wrap it + * in ( ) if its precedence is less than pr. + */ + +void expToCBuffer(OutBuffer buf, HdrGenState* hgs, Expression e, PREC pr) +{ + //if (precedence[e.op] == 0) e.dump(0); + if (precedence[e.op] < pr || + /* Despite precedence, we don't allow a<b<c expressions. + * They must be parenthesized. + */ + (pr == PREC.PREC_rel && precedence[e.op] == pr)) + { + buf.writeByte('('); + e.toCBuffer(buf, hgs); + buf.writeByte(')'); + } + else + e.toCBuffer(buf, hgs); +} + +/************************************************** + * Write out argument list to buf. + */ + +void argsToCBuffer(OutBuffer buf, Expressions arguments, HdrGenState* hgs) +{ + if (arguments) + { + for (size_t i = 0; i < arguments.dim; i++) + { + Expression arg = cast(Expression)arguments.data[i]; + + if (arg) + { + if (i) + buf.writeByte(','); + expToCBuffer(buf, hgs, arg, PREC.PREC_assign); + } + } + } +} \ No newline at end of file