diff --git a/src/aliasthis.d b/src/aliasthis.d index e2350762f18f..5a9971bec41f 100644 --- a/src/aliasthis.d +++ b/src/aliasthis.d @@ -130,17 +130,18 @@ extern (C++) Expression resolveAliasThis(Scope* sc, Expression e, bool gag = fal { if (e.op == TOKvar) { - if (auto fd = (cast(VarExp)e).var.isFuncDeclaration()) + auto ve = cast(VarExp)e; + if (auto fd = ve.var.isFuncDeclaration()) { // Bugzilla 13009: Support better match for the overloaded alias this. - bool hasOverloads; - if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads)) + auto f = fd.overloadModMatch(loc, tthis, ve.hasOverloads); + if (!f && !ve.hasOverloads) // no match + e = new ErrorExp(); + else { - if (!hasOverloads) - fd = f; // use exact match - e = new VarExp(loc, fd, hasOverloads); - e.type = f.type; - e = new CallExp(loc, e); + ve.var = !ve.hasOverloads ? f : fd; + ve.type = f ? f.type : Type.tambig; + e = new CallExp(loc, ve); goto L1; } } diff --git a/src/dcast.d b/src/dcast.d index 30ac707f6c3d..ac30396e4fef 100644 --- a/src/dcast.d +++ b/src/dcast.d @@ -140,6 +140,34 @@ extern (C++) Expression implicitCastTo(Expression e, Scope* sc, Type t) semanticTypeInfo(sc, (cast(TypeDArray)tb).next); } + override void visit(SymOffExp e) + { + visit(cast(Expression)e); + if (!e.hasOverloads) + return; + + if (result.op == TOKsymoff) + { + auto se = cast(SymOffExp)result; + if (!se.hasOverloads) + se.checkDeprecated(sc, se.var); + } + } + + override void visit(DelegateExp e) + { + visit(cast(Expression)e); + if (!e.hasOverloads) + return; + + if (result.op == TOKdelegate) + { + auto de = cast(DelegateExp)result; + if (!de.hasOverloads) + de.checkDeprecated(sc, de.func); + } + } + override void visit(SliceExp e) { visit(cast(Expression)e); @@ -2116,12 +2144,12 @@ extern (C++) Expression castTo(Expression e, Scope* sc, Type t) } // Look for pointers to functions where the functions are overloaded. - if (e.hasOverloads && - typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && + if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction && (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction) { - FuncDeclaration f = e.var.isFuncDeclaration(); - f = f ? f.overloadExactMatch(tb.nextOf()) : null; + auto f = e.var.isFuncDeclaration(); + if (f && e.hasOverloads) + f = f.overloadExactMatch(tb.nextOf()); if (f) { if (tb.ty == Tdelegate) diff --git a/src/declaration.d b/src/declaration.d index 8e87647b029d..41c12c99adff 100644 --- a/src/declaration.d +++ b/src/declaration.d @@ -638,6 +638,13 @@ public: error("cannot alias an expression %s", e.toChars()); t = Type.terror; } + else if (e.op == TOKvar) + { + auto ve = cast(VarExp)e; + auto f = s.isFuncDeclaration(); + if (!ve.hasOverloads && f && !f.isFuncAliasDeclaration()) + s = new FuncAliasDeclaration(ident, f, false); + } } type = t; } @@ -1076,6 +1083,13 @@ public: type = _init.toExpression().type; if (needctfe) sc = sc.endCTFE(); + + if (type.isAmbiguous()) + { + type = Type.terror; + return; + } + inuse--; inferred = 1; /* This is a kludge to support the existing syntax for RAII diff --git a/src/declaration.h b/src/declaration.h index 8297739facee..975434286614 100644 --- a/src/declaration.h +++ b/src/declaration.h @@ -593,6 +593,7 @@ class FuncDeclaration : public Declaration void semantic2(Scope *sc); void semantic3(Scope *sc); bool functionSemantic(); + bool functionSemantic(Loc loc); bool functionSemantic3(); // called from semantic3 VarDeclaration *declareThis(Scope *sc, AggregateDeclaration *ad); diff --git a/src/dmangle.d b/src/dmangle.d index 5e524383a61e..be4668525f37 100644 --- a/src/dmangle.d +++ b/src/dmangle.d @@ -197,6 +197,12 @@ public: override void visit(TypeFunction t) { + if (t.isAmbiguous()) + { + buf.writestring("_ambiguous_"); + return; + } + //printf("TypeFunction.toDecoBuffer() t = %p %s\n", t, t.toChars()); //static int nest; if (++nest == 50) *(char*)0=0; mangleFuncType(t, t, t.mod, t.next); @@ -829,14 +835,17 @@ extern (C++) const(char)* mangle(Dsymbol s) */ extern (C++) const(char)* mangleExact(FuncDeclaration fd) { - if (!fd.mangleString) + const(char)* s = fd.mangleString; + if (!s) { OutBuffer buf; scope Mangler v = new Mangler(&buf); v.mangleExact(fd); - fd.mangleString = buf.extractString(); + s = buf.extractString(); + if (!fd.flags) + fd.mangleString = s; } - return fd.mangleString; + return s; } extern (C++) void mangleToBuffer(Type t, OutBuffer* buf) diff --git a/src/e2ir.c b/src/e2ir.c index c56b4dad9160..e01ab06162c8 100644 --- a/src/e2ir.c +++ b/src/e2ir.c @@ -3423,6 +3423,14 @@ elem *toElem(Expression *e, IRState *irs) int directcall = 0; //printf("DelegateExp::toElem() '%s'\n", de->toChars()); + if (de->hasOverloads) + { + assert(de->type->ty == Tdelegate); + de->func = de->func->overloadExactMatch(de->type->nextOf()); + } + else + de->func = de->func->toAliasFunc(); + if (de->func->semanticRun == PASSsemantic3done) { // Bug 7745 - only include the function if it belongs to this module diff --git a/src/expression.d b/src/expression.d index 09ebfe747e83..aea19fba02b7 100644 --- a/src/expression.d +++ b/src/expression.d @@ -1430,7 +1430,7 @@ extern (C++) bool functionParameters(Loc loc, Scope* sc, TypeFunction tf, Type t // If inferring return type, and semantic3() needs to be run if not already run if (!tf.next && fd.inferRetType) { - fd.functionSemantic(); + fd.functionSemantic(loc); } else if (fd && fd.parent) { @@ -3999,7 +3999,7 @@ public: if (auto f = s.isFuncDeclaration()) { f = f.toAliasFunc(); - if (!f.functionSemantic()) + if (!f.functionSemantic(loc)) return new ErrorExp(); if (!hasOverloads && f.checkForwardRef(loc)) @@ -4007,7 +4007,8 @@ public: auto fd = s.isFuncDeclaration(); fd.type = f.type; - return new VarExp(loc, fd, hasOverloads); + e = new VarExp(loc, fd, hasOverloads); + return e.semantic(sc); } if (OverDeclaration od = s.isOverDeclaration()) { @@ -6402,14 +6403,20 @@ public: if (!type) type = var.type.pointerTo(); - if (auto v = var.isVarDeclaration()) + if (auto vd = var.isVarDeclaration()) { - if (v.checkNestedReference(sc, loc)) + if (vd.checkNestedReference(sc, loc)) return new ErrorExp(); } - else if (auto f = var.isFuncDeclaration()) + else if (auto fd = var.isFuncDeclaration()) { - if (f.checkNestedReference(sc, loc)) + if (hasOverloads) + { + hasOverloads = !fd.isUnique(); + if (hasOverloads) + type = Type.tambig.pointerTo(); + } + if (fd.checkNestedReference(sc, loc)) return new ErrorExp(); } @@ -6473,7 +6480,7 @@ public: if (auto fd = var.isFuncDeclaration()) { //printf("L%d fd = %s\n", __LINE__, f->toChars()); - if (!fd.functionSemantic()) + if (!fd.functionSemantic(loc)) return new ErrorExp(); } @@ -6504,6 +6511,20 @@ public: // Maybe here should be moved in CallExp, or AddrExp for functions. if (fd.checkNestedReference(sc, loc)) return new ErrorExp(); + + auto f = fd; + if (hasOverloads) + { + /* A function context might be supplied in later, + * so don't modify yet this.hasOverloads and this.var in here. + * Instead, just get a function type based on the match level. + */ + bool hasOverloads; + f = fd.overloadModMatch(loc, null, hasOverloads); + if (!f && !hasOverloads) // no match + return new ErrorExp(); + } + type = (f ? f.type : Type.tambig); } else if (auto od = var.isOverDeclaration()) { @@ -7399,6 +7420,17 @@ public: goto Lno; // errors, so condition is false targ = t; + if (targ.isAmbiguous()) + { + // Even if is(typeof(func)) is OK, is(typeof(func) Sym) could be NG + if (id) + error("cannot take ambiguous type"); + if (id || tspec || (tok2 != TOKreserved && tok2 != TOKfunction)) + { + tded = Type.terror; + goto Lno; + } + } if (tok2 != TOKreserved) { switch (tok2) @@ -8475,38 +8507,46 @@ public: { // symbol.mangleof Dsymbol ds; + bool hasOverloads = true; switch (e1.op) { - case TOKscope: - ds = (cast(ScopeExp)e1).sds; - goto L1; case TOKvar: ds = (cast(VarExp)e1).var; + hasOverloads = (cast(VarExp)e1).hasOverloads; goto L1; case TOKdotvar: ds = (cast(DotVarExp)e1).var; + hasOverloads = (cast(DotVarExp)e1).hasOverloads; goto L1; case TOKoverloadset: ds = (cast(OverExp)e1).vars; goto L1; case TOKtemplate: - { - TemplateExp te = cast(TemplateExp)e1; - ds = te.fd ? cast(Dsymbol)te.fd : te.td; - } + auto te = cast(TemplateExp)e1; + ds = te.fd ? cast(Dsymbol)te.fd : te.td; + hasOverloads = (te.fd is null); + goto L1; + case TOKscope: + ds = (cast(ScopeExp)e1).sds; L1: + assert(ds); + auto f = ds.isFuncDeclaration(); + if (f) { - assert(ds); - if (auto f = ds.isFuncDeclaration()) + if (f.checkForwardRef(loc)) + return new ErrorExp(); + if (hasOverloads && !e1.type.isAmbiguous()) { - if (f.checkForwardRef(loc)) - return new ErrorExp(); + f = f.overloadExactMatch(e1.type); + if (f) // get the "better match" function + hasOverloads = false; } - const(char)* s = mangle(ds); - Expression e = new StringExp(loc, cast(void*)s, strlen(s)); - e = e.semantic(sc); - return e; } + const char* s = (f && !hasOverloads ? mangleExact(f.toAliasFunc()) + : mangle(ds)); + Expression e = new StringExp(loc, cast(void*)s, strlen(s)); + e = e.semantic(sc); + return e; default: break; } @@ -8688,7 +8728,7 @@ public: if (f) { //printf("it's a function\n"); - if (!f.functionSemantic()) + if (!f.functionSemantic(loc)) return new ErrorExp(); if (f.needThis()) { @@ -8944,10 +8984,23 @@ public: Type t1 = e1.type; - if (FuncDeclaration fd = var.isFuncDeclaration()) + if (auto fd = var.isFuncDeclaration()) { - // for functions, do checks after overload resolution - if (!fd.functionSemantic()) + auto f = fd; // better or exact match + if (hasOverloads) + { + f = fd.overloadModMatch(loc, e1.type, hasOverloads); + if (!f && !hasOverloads) // no match + return new ErrorExp(); + if (f) // better or exact match + fd = f; + if (!hasOverloads) // exact match + { + var = f; + checkDeprecated(sc, f); + } + } + if (!fd.functionSemantic(loc)) return new ErrorExp(); /* Bugzilla 13843: If fd obviously has no overloads, we should @@ -8956,14 +9009,14 @@ public: if (fd.isNested() || fd.isFuncLiteralDeclaration()) { // (e1, fd) - auto e = DsymbolExp.resolve(loc, sc, fd, false); + auto e = DsymbolExp.resolve(loc, sc, f, false); return Expression.combine(e1, e); } - type = fd.type; - assert(type); + type = f ? f.type : Type.tambig; + type = type.semantic(loc, sc); } - else if (OverDeclaration od = var.isOverDeclaration()) + else if (auto od = var.isOverDeclaration()) { type = Type.tvoid; // ambiguous type? } @@ -9353,12 +9406,40 @@ public: e1 = e1.semantic(sc); - type = new TypeDelegate(func.type); + auto fd = func; + auto f = fd; + if (hasOverloads) + { + f = func.overloadModMatch(loc, e1.type, hasOverloads); + if (!f && !hasOverloads) // no match + return new ErrorExp(); + if (f) // better or exact match + fd = f; + if (!hasOverloads) // exact match + { + func = f; + checkDeprecated(sc, f); + } + } + else + { + f = fd = f.toAliasFunc(); + if (!MODmethodConv(e1.type.mod, f.type.mod)) + { + OutBuffer thisBuf, funcBuf; + MODMatchToBuffer(&thisBuf, e1.type.mod, f.type.mod); + MODMatchToBuffer(&funcBuf, f.type.mod, e1.type.mod); + error("cannot access %sfunction through %sobject", + funcBuf.peekString(), thisBuf.peekString()); + return new ErrorExp(); + } + } + type = f ? f.type : Type.tambig; + type = new TypeDelegate(type); // function to delegate type = type.semantic(loc, sc); - FuncDeclaration f = func.toAliasFunc(); - AggregateDeclaration ad = f.toParent().isAggregateDeclaration(); - if (f.needThis()) + auto ad = fd.toParent().isAggregateDeclaration(); + if (!hasOverloads && f.needThis()) e1 = getRightThis(loc, sc, ad, e1, f); if (ad && ad.isClassDeclaration() && ad.type != e1.type) { @@ -10101,6 +10182,12 @@ public: } else if (t1.ty == Tdelegate) { + if (t1.isAmbiguous() && e1.op == TOKdelegate) + { + auto de = cast(DelegateExp)e1; + e1 = new DotVarExp(de.e1.loc, de.e1, de.func, de.hasOverloads); + goto Lagain; + } TypeDelegate td = cast(TypeDelegate)t1; assert(td.next.ty == Tfunction); tf = cast(TypeFunction)td.next; @@ -10108,6 +10195,12 @@ public: } else if (t1.ty == Tpointer && (cast(TypePointer)t1).next.ty == Tfunction) { + if (t1.isAmbiguous() && e1.op == TOKsymoff) + { + auto se = cast(SymOffExp)e1; + e1 = new VarExp(se.loc, se.var, se.hasOverloads); + goto Lagain; + } tf = cast(TypeFunction)(cast(TypePointer)t1).next; p = "function pointer"; } @@ -10448,22 +10541,22 @@ public: if (type) return this; - if (Expression ex = unaSemantic(sc)) - return ex; + if (auto e = unaSemantic(sc)) + return e; int wasCond = e1.op == TOKquestion; if (e1.op == TOKdotti) { - DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1; - TemplateInstance ti = dti.ti; + auto dti = cast(DotTemplateInstanceExp)e1; + auto ti = dti.ti; { //assert(ti.needsTypeInference(sc)); ti.semantic(sc); if (!ti.inst || ti.errors) // if template failed to expand return new ErrorExp(); - Dsymbol s = ti.toAlias(); - FuncDeclaration f = s.isFuncDeclaration(); + auto s = ti.toAlias(); + auto f = s.isFuncDeclaration(); if (f) { e1 = new DotVarExp(e1.loc, dti.e1, f); @@ -10473,15 +10566,15 @@ public: } else if (e1.op == TOKscope) { - TemplateInstance ti = (cast(ScopeExp)e1).sds.isTemplateInstance(); + auto ti = (cast(ScopeExp)e1).sds.isTemplateInstance(); if (ti) { //assert(ti.needsTypeInference(sc)); ti.semantic(sc); if (!ti.inst || ti.errors) // if template failed to expand return new ErrorExp(); - Dsymbol s = ti.toAlias(); - FuncDeclaration f = s.isFuncDeclaration(); + auto s = ti.toAlias(); + auto f = s.isFuncDeclaration(); if (f) { e1 = new VarExp(e1.loc, f); @@ -10525,81 +10618,103 @@ public: // See if this should really be a delegate if (e1.op == TOKdotvar) { - DotVarExp dve = cast(DotVarExp)e1; - FuncDeclaration f = dve.var.isFuncDeclaration(); - if (f) + auto dve = cast(DotVarExp)e1; + if (auto fd = dve.var.isFuncDeclaration()) { - f = f.toAliasFunc(); // FIXME, should see overlods - Bugzilla 1983 if (!dve.hasOverloads) - f.tookAddressOf++; + fd.tookAddressOf++; Expression e; - if (f.needThis()) - e = new DelegateExp(loc, dve.e1, f, dve.hasOverloads); + if (dve.hasOverloads || fd.needThis()) + e = new DelegateExp(loc, dve.e1, fd, dve.hasOverloads); else // It is a function pointer. Convert &v.f() --> (v, &V.f()) - e = new CommaExp(loc, dve.e1, new AddrExp(loc, new VarExp(loc, f, dve.hasOverloads))); + e = new CommaExp(loc, dve.e1, new AddrExp(loc, new VarExp(loc, fd, dve.hasOverloads))); e = e.semantic(sc); return e; } } else if (e1.op == TOKvar) { - VarExp ve = cast(VarExp)e1; - VarDeclaration v = ve.var.isVarDeclaration(); - if (v) + auto ve = cast(VarExp)e1; + if (auto vd = ve.var.isVarDeclaration()) { - if (!v.canTakeAddressOf()) + if (!vd.canTakeAddressOf()) { error("cannot take address of %s", e1.toChars()); return new ErrorExp(); } - if (sc.func && !sc.intypeof && !v.isDataseg()) + if (sc.func && !sc.intypeof && !vd.isDataseg()) { if (sc.func.setUnsafe()) { - const(char)* p = v.isParameter() ? "parameter" : "local"; - error("cannot take address of %s %s in @safe function %s", p, v.toChars(), sc.func.toChars()); + const(char)* p = vd.isParameter() ? "parameter" : "local"; + error("cannot take address of %s %s in @safe function %s", + p, vd.toChars(), sc.func.toChars()); } } - ve.checkPurity(sc, v); + ve.checkPurity(sc, vd); } - FuncDeclaration f = ve.var.isFuncDeclaration(); - if (f) + if (auto fd = ve.var.isFuncDeclaration()) { /* Because nested functions cannot be overloaded, * mark here that we took its address because castTo() * may not be called with an exact match. + * TODO: If a nested function is mixed-in, it could have overloads. */ - if (!ve.hasOverloads || f.isNested()) - f.tookAddressOf++; - if (f.isNested()) + if (!ve.hasOverloads || fd.isNested()) + fd.tookAddressOf++; + if (fd.isNested()) { - if (f.isFuncLiteralDeclaration()) + if (fd.isFuncLiteralDeclaration()) { - if (!f.FuncDeclaration.isNested()) + if (!fd.FuncDeclaration.isNested()) { /* Supply a 'null' for a this pointer if no this is available */ - Expression e = new DelegateExp(loc, new NullExp(loc, Type.tnull), f, ve.hasOverloads); + Expression e = new DelegateExp(loc, new NullExp(loc, Type.tnull), fd, ve.hasOverloads); e = e.semantic(sc); return e; } } - Expression e = new DelegateExp(loc, e1, f, ve.hasOverloads); + Expression e = new DelegateExp(loc, e1, fd, ve.hasOverloads); e = e.semantic(sc); return e; } - if (f.needThis() && hasThis(sc)) + if (fd.needThis() && hasThis(sc)) { /* Should probably supply 'this' after overload resolution, * not before. */ Expression ethis = new ThisExp(loc); - Expression e = new DelegateExp(loc, ethis, f, ve.hasOverloads); + Expression e = new DelegateExp(loc, ethis, fd, ve.hasOverloads); e = e.semantic(sc); return e; } + + /* In here, unlike VarExp.semantic(), it's known that + * var doesn't need 'this' expression. + * So, we can find exact or better match from overload list. + */ + if (ve.hasOverloads) + { + bool hasOverloads2; + auto f = fd.overloadModMatch(loc, null, hasOverloads2); + if (!f && !hasOverloads2) // no match + return new ErrorExp(); + auto t = f ? f.type : Type.tambig; + + ve = cast(VarExp)ve.copy(); + ve.type = t.semantic(loc, sc); + ve.hasOverloads = hasOverloads2; + e1 = ve; + if (!hasOverloads2) // exact match + { + ve.var = f; + checkDeprecated(sc, f); + } + type = e1.type.pointerTo(); + } } } else if (wasCond) @@ -10620,7 +10735,8 @@ public: ce.e2.type = null; ce.e2 = ce.e2.semantic(sc); } - return optimize(WANTvalue); + auto e = optimize(WANTvalue); + return e.semantic(sc); } override void accept(Visitor v) @@ -11124,6 +11240,12 @@ public: Type t1b = e1.type.toBasetype(); Type tob = to.toBasetype(); + if (t1b.isAmbiguous() && e1.implicitConvTo(to) <= MATCHnomatch) + { + error("cannot cast ambiguous expression %s to %s", e1.toChars(), to.toChars()); + return new ErrorExp(); + } + if (tob.ty == Tstruct && !tob.equals(t1b)) { /* Look to replace: diff --git a/src/func.d b/src/func.d index 849a4da95bdf..1049eb1b1bb9 100644 --- a/src/func.d +++ b/src/func.d @@ -2405,9 +2405,22 @@ public: * Returns false if any errors exist in the signature. */ final bool functionSemantic() + { + return functionSemantic(loc); + } + final bool functionSemantic(Loc loc) { if (!_scope) + { + // Keep diagnostic for: fail_compilation/fail113.d, + // fail114.d, fail126.d, fail139.d, and fail333.d + if (!type.deco) + { + .error(loc, "forward reference to '%s'", toChars()); + errors = true; + } return !errors; + } if (!originalType) // semantic not yet run { @@ -2491,7 +2504,7 @@ public: */ final bool checkForwardRef(Loc loc) { - if (!functionSemantic()) + if (!functionSemantic(loc)) return true; /* No deco means the functionSemantic() call could not resolve @@ -2817,31 +2830,39 @@ public: * 1. If the 'tthis' matches only one candidate, it's an "exact match". * Returns the function and 'hasOverloads' is set to false. * eg. If 'tthis" is mutable and there's only one mutable method. - * 2. If there's two or more match candidates, but a candidate function will be + * 2. If there's two or more match candidates, but a candidate function can be * a "better match". * Returns the better match function but 'hasOverloads' is set to true. * eg. If 'tthis' is mutable, and there's both mutable and const methods, * the mutable method will be a better match. - * 3. If there's two or more match candidates, but there's no better match, + * 3. If there's two or more match candidates, but there's no better match. * Returns null and 'hasOverloads' is set to true to represent "ambiguous match". * eg. If 'tthis' is mutable, and there's two or more mutable methods. - * 4. If there's no candidates, it's "no match" and returns null with error report. + * 4. If there's no candidates, it's "no match". + * Returns null and 'hasOverloads' is set to false, with error report. * e.g. If 'tthis' is const but there's no const methods. + * + * If one or more TemplateDeclaration is in the list, it's always ambiguous match. */ final FuncDeclaration overloadModMatch(Loc loc, Type tthis, ref bool hasOverloads) { //printf("FuncDeclaration::overloadModMatch('%s')\n", toChars()); + //if (tthis) printf("\ttthis = %s\n", tthis.toChars()); + Match m; m.last = MATCHnomatch; - overloadApply(this, (Dsymbol s) + auto r = overloadApply(this, (Dsymbol s) { + if (s.isTemplateDeclaration()) + return 1; + auto f = s.isFuncDeclaration(); if (!f || f == m.lastf) // skip duplicates return 0; m.anyf = f; auto tf = cast(TypeFunction)f.type; - //printf("tf = %s\n", tf->toChars()); + //printf("tf = %s\n", tf.toChars()); MATCH match; if (tthis) // non-static functions are preferred than static ones @@ -2876,7 +2897,6 @@ public: LlastIsBetter: //printf("\tlastbetter\n"); - m.count++; // count up return 0; LcurrIsBetter: @@ -2893,17 +2913,27 @@ public: return 0; }); + if (r) // ambiguous match + { + hasOverloads = true; + return null; + } + if (m.count == 1) // exact match { hasOverloads = false; + //printf("\tcount == 1, lastf = %s\n", m.lastf.type.toChars()); } else if (m.count > 1) // better or ambiguous match { hasOverloads = true; + if (m.nextf) // ambiguous match + m.lastf = null; + //printf("\tcount > 1, lastf = %s\n", m.lastf ? m.lastf.type.toChars() : null); } else // no match { - hasOverloads = true; + hasOverloads = false; auto tf = cast(TypeFunction)this.type; assert(tthis); assert(!MODimplicitConv(tthis.mod, tf.mod)); // modifier mismatch @@ -4224,7 +4254,7 @@ extern (C++) int overloadApply(Dsymbol fstart, void* param, int function(void*, return overloadApply(fstart, s => (*fp)(param, s)); } -extern (C++) static void MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod) +extern (C++) void MODMatchToBuffer(OutBuffer* buf, ubyte lhsMod, ubyte rhsMod) { bool bothMutable = ((lhsMod & rhsMod) == 0); bool sharedMismatch = ((lhsMod ^ rhsMod) & MODshared) != 0; @@ -4296,7 +4326,7 @@ extern (C++) FuncDeclaration resolveFuncCall(Loc loc, Scope* sc, Dsymbol s, if (m.count == 1) // exactly one match { if (!(flags & 1)) - m.lastf.functionSemantic(); + m.lastf.functionSemantic(loc); return m.lastf; } if ((flags & 2) && !tthis && m.lastf.needThis()) diff --git a/src/hdrgen.d b/src/hdrgen.d index 7f86c0c08342..3d8a8dcd584a 100644 --- a/src/hdrgen.d +++ b/src/hdrgen.d @@ -787,6 +787,12 @@ public: override void visit(TypeFunction t) { + if (t.isAmbiguous()) + { + buf.writestring("_ambiguous_"); + return; + } + //printf("TypeFunction::toCBuffer2() t = %p, ref = %d\n", t, t->isref); visitFuncIdentWithPostfix(t, null); } @@ -908,6 +914,12 @@ public: override void visit(TypeDelegate t) { + if (t.isAmbiguous()) + { + buf.writestring("_ambiguous_"); + return; + } + visitFuncIdentWithPostfix(cast(TypeFunction)t.next, "delegate"); } @@ -3171,6 +3183,12 @@ extern (C++) const(char)* protectionToChars(PROTKIND kind) // Print the full function signature with correct ident, attributes and template args extern (C++) void functionToBufferFull(TypeFunction tf, OutBuffer* buf, Identifier ident, HdrGenState* hgs, TemplateDeclaration td) { + if (tf.isAmbiguous()) + { + buf.writestring("_ambiguous_"); + return; + } + //printf("TypeFunction::toCBuffer() this = %p\n", this); scope PrettyPrintVisitor v = new PrettyPrintVisitor(buf, hgs); v.visitFuncIdentWithPrefix(tf, ident, td, true); diff --git a/src/init.d b/src/init.d index 435bb4421a2b..70ffceba4974 100644 --- a/src/init.d +++ b/src/init.d @@ -776,8 +776,8 @@ public: exp = resolveProperties(sc, exp); if (exp.op == TOKscope) { - ScopeExp se = cast(ScopeExp)exp; - TemplateInstance ti = se.sds.isTemplateInstance(); + auto se = cast(ScopeExp)exp; + auto ti = se.sds.isTemplateInstance(); if (ti && ti.semanticRun == PASSsemantic && !ti.aliasdecl) se.error("cannot infer type from %s %s, possible circular dependency", se.sds.kind(), se.toChars()); else @@ -791,7 +791,7 @@ public: { if (f.checkForwardRef(loc)) return new ErrorInitializer(); - if (hasOverloads && !f.isUnique()) + if (exp.type.isAmbiguous()) { exp.error("cannot infer type from overloaded function symbol %s", exp.toChars()); return new ErrorInitializer(); @@ -799,7 +799,7 @@ public: } if (exp.op == TOKaddress) { - AddrExp ae = cast(AddrExp)exp; + auto ae = cast(AddrExp)exp; if (ae.e1.op == TOKoverloadset) { exp.error("cannot infer type from overloaded function symbol %s", exp.toChars()); diff --git a/src/mtype.d b/src/mtype.d index c6b785351a19..34d431447a29 100644 --- a/src/mtype.d +++ b/src/mtype.d @@ -530,6 +530,7 @@ public: extern (C++) static __gshared Type twstring; // immutable(wchar)[] extern (C++) static __gshared Type tdstring; // immutable(dchar)[] extern (C++) static __gshared Type tvalist; // va_list alias + extern (C++) static __gshared Type tambig; extern (C++) static __gshared Type terror; // for error recovery extern (C++) static __gshared Type tnull; // for null type @@ -897,6 +898,9 @@ public: twstring = twchar.immutableOf().arrayOf(); tdstring = tdchar.immutableOf().arrayOf(); tvalist = Target.va_listType(); + tambig = new TypeFunction(null, null, 0, LINKd); + tambig.deco = cast(char*)"@".ptr; + if (global.params.isLP64) { Tsize_t = Tuns64; @@ -947,7 +951,8 @@ public: Type t = semantic(loc, sc); if (global.endGagging(errors) || t.ty == Terror) // if any errors happened { - t = null; + if (!t.isAmbiguous()) + t = null; } //printf("-trySemantic(%s) %d\n", toChars(), global.errors); return t; @@ -1121,6 +1126,11 @@ public: return true; } + bool isAmbiguous() + { + return false; + } + /************************** * Returns true if T can be converted to boolean value. */ @@ -2216,9 +2226,13 @@ public: */ MATCH implicitConvTo(Type to) { + if (isAmbiguous()) + return MATCHnomatch; + //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to); //printf("from: %s\n", toChars()); //printf("to : %s\n", to->toChars()); + if (this.equals(to)) return MATCHexact; return MATCHnomatch; @@ -2994,6 +3008,11 @@ public: this.next = next; } + override bool isAmbiguous() + { + return next && next.isAmbiguous(); + } + override final void checkDeprecated(Loc loc, Scope* sc) { Type.checkDeprecated(loc, sc); @@ -4745,7 +4764,11 @@ public: override MATCH implicitConvTo(Type to) { + if (isAmbiguous()) + return MATCHnomatch; + //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); + if (to.ty == Tarray) { TypeDArray ta = cast(TypeDArray)to; @@ -5021,6 +5044,9 @@ public: override MATCH implicitConvTo(Type to) { + if (isAmbiguous()) + return MATCHnomatch; + //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); if (equals(to)) return MATCHexact; @@ -5386,6 +5412,9 @@ public: override MATCH implicitConvTo(Type to) { + if (isAmbiguous()) + return MATCHnomatch; + //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to->toChars(), toChars()); if (equals(to)) return MATCHexact; @@ -5501,6 +5530,9 @@ public: override MATCH implicitConvTo(Type to) { + if (isAmbiguous()) + return MATCHnomatch; + //printf("TypePointer::implicitConvTo(to = %s) %s\n", to->toChars(), toChars()); if (equals(to)) return MATCHexact; @@ -5805,6 +5837,11 @@ public: return t; } + override bool isAmbiguous() + { + return this == tambig || TypeNext.isAmbiguous(); + } + override Type semantic(Loc loc, Scope* sc) { if (deco) // if semantic() already run @@ -6722,6 +6759,9 @@ public: override MATCH implicitConvTo(Type to) { + if (isAmbiguous()) + return MATCHnomatch; + //printf("TypeDelegate::implicitConvTo(this=%p, to=%p)\n", this, to); //printf("from: %s\n", toChars()); //printf("to : %s\n", to->toChars()); @@ -7570,6 +7610,14 @@ public: error(loc, "expression (%s) has no type", exp.toChars()); goto Lerr; } + if (t.isAmbiguous()) + { + //printf("typeof exp = %s -> t = %s\n", exp.toChars(), t.toChars()); + error(loc, "expression (%s) has ambiguous type", exp.toChars()); + *pt = Type.tambig; + inuse--; + return; + } if (t.ty == Ttypeof) { error(loc, "forward reference to %s", toChars()); diff --git a/src/mtype.h b/src/mtype.h index 1a92d70be156..5d608d443a5f 100644 --- a/src/mtype.h +++ b/src/mtype.h @@ -197,6 +197,7 @@ class Type : public RootObject static Type *twstring; // immutable(wchar)[] static Type *tdstring; // immutable(dchar)[] static Type *tvalist; // va_list alias + static Type *tambig; static Type *terror; // for error recovery static Type *tnull; // for null type @@ -267,6 +268,7 @@ class Type : public RootObject virtual bool isscope(); virtual bool isString(); virtual bool isAssignable(); + virtual bool isAmbiguous(); virtual bool isBoolean(); virtual void checkDeprecated(Loc loc, Scope *sc); bool isConst() const { return (mod & MODconst) != 0; } @@ -369,6 +371,7 @@ class TypeNext : public Type Type *next; TypeNext(TY ty, Type *next); + bool isAmbiguous(); void checkDeprecated(Loc loc, Scope *sc); int hasWild() const; Type *nextOf(); @@ -619,6 +622,7 @@ class TypeFunction : public TypeNext const char *kind(); Type *syntaxCopy(); Type *semantic(Loc loc, Scope *sc); + bool isAmbiguous(); void purityLevel(); bool hasLazyParameters(); bool parameterEscapes(Parameter *p); diff --git a/src/statement.d b/src/statement.d index 71c3729082b7..cc8c4eaf2a0a 100644 --- a/src/statement.d +++ b/src/statement.d @@ -4426,7 +4426,13 @@ public: { if (!tret) { - tf.next = exp.type; + if (exp.type.isAmbiguous()) + { + error("cannot infer return type from ambiguous expression %s", exp.toChars()); + tf.next = Type.terror; + } + else + tf.next = exp.type; } else if (tret.ty != Terror && !exp.type.equals(tret)) { diff --git a/test/compilable/test7322.d b/test/compilable/test7322.d new file mode 100644 index 000000000000..66a7b69f5606 --- /dev/null +++ b/test/compilable/test7322.d @@ -0,0 +1,79 @@ +// PERMUTE_ARGS: +/* +TEST_OUTPUT: +--- +compilable/test7322.d(29): Deprecation: function test7322.S7322.baz7322 is deprecated +compilable/test7322.d(42): Deprecation: function test7322.foo7322 is deprecated +compilable/test7322.d(49): Deprecation: function test7322.S7322.bar7322 is deprecated +compilable/test7322.d(53): Deprecation: function test7322.S7322.baz7322 is deprecated +--- +*/ + +deprecated +int foo7322(real a) { return 1; } +int foo7322(long a) { return 0; } + +struct S7322 +{ + deprecated + int bar7322(real a) { return 1; } + int bar7322(long a) { return 0; } + + deprecated + int baz7322(real a) { return 1; } + int baz7322(long a) immutable { return 0; } + + // DelegateExp::semantic(!func->isNested() && hasOverloads) + void test1() + { + auto dg = &baz7322; // deprecated! + static assert(is(typeof(dg) == int delegate(real))); + } + void test2() immutable + { + auto dg = &baz7322; + static assert(is(typeof(dg) == int delegate(long) immutable)); + } +} + +void test7322a() +{ + // SymOffExp::implicitCastTo() + int function(real) fp1 = &foo7322; // deprecated! + int function(long) fp2 = &foo7322; + + S7322 sm; + immutable S7322 si; + + // DelegateExp::implicitCastTo() + int delegate(real) dg1 = &sm.bar7322; // deprecated! + int delegate(long) dg2 = &sm.bar7322; + + // DotVarExp::semantic(var->isFuncDeclaration() && hasOverloads) + auto dg3 = &sm.baz7322; // deprecated! + static assert(is(typeof(dg3) == int delegate(real))); + + auto dg4 = &si.baz7322; + static assert(is(typeof(dg4) == int delegate(long) immutable)); +} + +deprecated void test7322b() +{ + // SymOffExp::implicitCastTo() + int function(real) fp1 = &foo7322; // deprecated! + int function(long) fp2 = &foo7322; + + S7322 sm; + immutable S7322 si; + + // DelegateExp::implicitCastTo() + int delegate(real) dg1 = &sm.bar7322; // deprecated! + int delegate(long) dg2 = &sm.bar7322; + + // DotVarExp::semantic(var->isFuncDeclaration() && hasOverloads) + auto dg3 = &sm.baz7322; // deprecated! + static assert(is(typeof(dg3) == int delegate(real))); + + auto dg4 = &si.baz7322; + static assert(is(typeof(dg4) == int delegate(long) immutable)); +} diff --git a/test/fail_compilation/depmsg.d b/test/fail_compilation/depmsg.d index 186576a5473d..5ecc5b1744ba 100644 --- a/test/fail_compilation/depmsg.d +++ b/test/fail_compilation/depmsg.d @@ -52,13 +52,18 @@ void main() /* TEST_OUTPUT: --- -fail_compilation/depmsg.d(94): Deprecation: function depmsg.test12954.Foo.bar1 is deprecated - [C] Use Foo.bar42 instead -fail_compilation/depmsg.d(95): Deprecation: function depmsg.test12954.Foo.bar2 is deprecated - [E] Use Foo.bar42 instead -fail_compilation/depmsg.d(96): Deprecation: function depmsg.test12954.Foo.bar3 is deprecated - [S] Use Foo.bar42 instead -fail_compilation/depmsg.d(97): Deprecation: function depmsg.test12954.Foo.bar4 is deprecated - [F] Use Foo.bar42 instead -fail_compilation/depmsg.d(98): Deprecation: variable depmsg.test12954.Foo.v2 is deprecated - Forward reference -fail_compilation/depmsg.d(105): Deprecation: class depmsg.test12954.Obsolete is deprecated -fail_compilation/depmsg.d(105): Deprecation: function depmsg.test12954.Obsolete.obs is deprecated - Function is obsolete +fail_compilation/depmsg.d(99): Deprecation: function depmsg.test12954.Foo.bar1 is deprecated - [C] Use Foo.bar42 instead +fail_compilation/depmsg.d(99): Deprecation: function depmsg.test12954.Foo.bar1 is deprecated - [C] Use Foo.bar42 instead +fail_compilation/depmsg.d(100): Deprecation: function depmsg.test12954.Foo.bar2 is deprecated - [E] Use Foo.bar42 instead +fail_compilation/depmsg.d(100): Deprecation: function depmsg.test12954.Foo.bar2 is deprecated - [E] Use Foo.bar42 instead +fail_compilation/depmsg.d(101): Deprecation: function depmsg.test12954.Foo.bar3 is deprecated - [S] Use Foo.bar42 instead +fail_compilation/depmsg.d(101): Deprecation: function depmsg.test12954.Foo.bar3 is deprecated - [S] Use Foo.bar42 instead +fail_compilation/depmsg.d(102): Deprecation: function depmsg.test12954.Foo.bar4 is deprecated - [F] Use Foo.bar42 instead +fail_compilation/depmsg.d(102): Deprecation: function depmsg.test12954.Foo.bar4 is deprecated - [F] Use Foo.bar42 instead +fail_compilation/depmsg.d(103): Deprecation: variable depmsg.test12954.Foo.v2 is deprecated - Forward reference +fail_compilation/depmsg.d(110): Deprecation: class depmsg.test12954.Obsolete is deprecated +fail_compilation/depmsg.d(110): Deprecation: function depmsg.test12954.Obsolete.obs is deprecated - Function is obsolete +fail_compilation/depmsg.d(110): Deprecation: function depmsg.test12954.Obsolete.obs is deprecated - Function is obsolete --- */ void test12954() diff --git a/test/fail_compilation/diag8101b.d b/test/fail_compilation/diag8101b.d index a3baa272fae1..18aa13f732ae 100644 --- a/test/fail_compilation/diag8101b.d +++ b/test/fail_compilation/diag8101b.d @@ -5,13 +5,13 @@ fail_compilation/diag8101b.d(26): Error: none of the overloads of 'foo' are call fail_compilation/diag8101b.d(17): diag8101b.S.foo(int _param_0) fail_compilation/diag8101b.d(18): diag8101b.S.foo(int _param_0, int _param_1) fail_compilation/diag8101b.d(28): Error: function diag8101b.S.bar (int _param_0) is not callable using argument types (double) -fail_compilation/diag8101b.d(31): Error: none of the overloads of 'foo' are callable using a const object, candidates are: -fail_compilation/diag8101b.d(17): diag8101b.S.foo(int _param_0) -fail_compilation/diag8101b.d(18): diag8101b.S.foo(int _param_0, int _param_1) +fail_compilation/diag8101b.d(31): Error: mutable method diag8101b.S.foo is not callable using a const object fail_compilation/diag8101b.d(33): Error: mutable method diag8101b.S.bar is not callable using a const object --- */ + + struct S { void foo(int) { } diff --git a/test/fail_compilation/fail7549.d b/test/fail_compilation/fail7549.d new file mode 100644 index 000000000000..e10fd20af639 --- /dev/null +++ b/test/fail_compilation/fail7549.d @@ -0,0 +1,49 @@ +void foo() {} +void foo(int) {} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail7549.d(13): Error: expression (foo) has ambiguous type +--- +*/ +void test1() +{ + static assert(is(typeof(foo))); // OK + typeof(foo)* func_ptr; // error +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail7549.d(30): Error: expression (&c.fun) has ambiguous type +--- +*/ +void test2() +{ + class C + { + int fun(string) { return 1; } + int fun() { return 1; } + } + auto c = new C; + auto s = typeof(&c.fun).stringof; +} + +/* +TEST_OUTPUT: +--- +fail_compilation/fail7549.d(42): Error: cannot infer type from overloaded function symbol & foo +fail_compilation/fail7549.d(46): Error: cannot infer return type from ambiguous expression & foo +--- +*/ +void test3() +{ + auto val1 = &foo; // should be ambiguous + auto val2 = cast(void function(int))&foo; // works + void function(int) val3 = &foo; // works + + auto bar1() { return &foo; } // should be ambiguous + auto bar2() { return cast(void function(int))&foo; } // works + void function(int) bar3() { return &foo; } // works +} diff --git a/test/fail_compilation/fail9027.d b/test/fail_compilation/fail9027.d new file mode 100644 index 000000000000..5852b560d1f9 --- /dev/null +++ b/test/fail_compilation/fail9027.d @@ -0,0 +1,29 @@ +/* +TEST_OUTPUT: +--- +fail_compilation/fail9027.d(26): Error: cannot cast ambiguous expression & f2 to void function(int) +fail_compilation/fail9027.d(27): Error: cannot cast ambiguous expression & f3 to void function(int) +fail_compilation/fail9027.d(28): Error: cannot cast ambiguous expression & f4 to void function() +--- +*/ + +void f1() { } +void f1(int) { } +extern(C) void f1(int) { } + +void f2() { } +extern(C) void f2(int) { } + +extern(C) void f3(int) { } +void f3() { } + +extern(Windows) void f4(long) { } +extern(C) void f4(long) { } + +void main() +{ + auto fp1 = cast(void function(int)) &f1; + auto fp2 = cast(void function(int)) &f2; + auto fp3 = cast(void function(int)) &f3; + auto fp4 = cast(void function()) &f4; +} diff --git a/test/runnable/overload.d b/test/runnable/overload.d index f8fa7d5cdda2..2d646b30adea 100644 --- a/test/runnable/overload.d +++ b/test/runnable/overload.d @@ -11,6 +11,628 @@ template TypeTuple(T...){ alias T TypeTuple; } template Id( T){ alias T Id; } template Id(alias A){ alias A Id; } +/***************************************************/ + +void test1() +{ + static class C1 + { + void f1() {} + const void f1() {} + + void f2() {} + + auto f3() { return &f1; } + const auto f3() { return &f1; } + } + static class C2 + { + const void f1() {} + void f1() {} + + void f2() {} + + const auto f3() { return &f1; } + auto f3() { return &f1; } + } + + // FIX: the tolerance against C's member function declaration order + foreach (C; TypeTuple!(C1, C2)) + { + auto mc = new C; + + auto dg1 = &mc.f1; + static assert(is(typeof(dg1) == void delegate())); + + auto dg2 = &mc.f2; + static assert(is(typeof(dg2) == void delegate())); + + auto dg3 = &mc.f3; + static assert(is(typeof(dg3) : void delegate() delegate())); + } + foreach (C; TypeTuple!(C1, C2)) + { + const cc = new C; + + auto dg1 = &cc.f1; + static assert(is(typeof(dg1) == void delegate() const)); + + static assert(!is(typeof(&cc.f2))); + + auto dg3 = &cc.f3; + static assert(is(typeof(dg3) : void delegate() const delegate() const)); + } +} + +/***************************************************/ + +void test2() +{ + static class C1 + { + bool f() const { return true; } + void f(bool v) {} + + const void g1() {} + shared const void g1() {} + + const int g2(int m) { return 1; } + shared const int g2(int m, int n) { return 2; } + } + static class C2 + { + void f(bool v) {} + bool f() const { return true; } + + shared const void g1() {} + const void g1() {} + + shared const int g2(int m, int n) { return 2; } + const int g2(int m) { return 1; } + } + static bool g(bool v) { return v; } + + foreach (C; TypeTuple!(C1, C2)) + { + auto mc = new C(); + assert(g(mc.f)); + + auto ic = new immutable(C)(); + static assert(is(typeof(&ic.g1))); + static assert(!__traits(compiles, typeof(&ic.g1))); + + assert(ic.g2(0) == 1); + assert(ic.g2(0,0) == 2); + + alias C.f foo; + static assert(is(typeof(foo))); + static assert(!__traits(compiles, typeof(foo))); + } +} + +/***************************************************/ + +void test3() +{ + static class C + { + void f() {} + void f(int n) {} + + // dummy functions to get type of f + void f1() {} + void f2(int n) {} + } + + alias TypeTuple!(__traits(getOverloads, C, "f")) Fs; + alias Fs[0] F1; + alias Fs[1] F2; + static assert(is(typeof(F1) == typeof(C.f1))); + static assert(is(typeof(F2) == typeof(C.f2))); + + static assert(is(typeof(Id!F1) == typeof(C.f1))); + static assert(is(typeof(Id!F2) == typeof(C.f2))); + // ovrload resolution keeps through template alias parameter. + + foreach (i, F; __traits(getOverloads, C, "f")) + { + static if (i==0) static assert(is(typeof(F) == typeof(C.f1))); + static if (i==1) static assert(is(typeof(F) == typeof(C.f2))); + + static if (i==0) static assert(is(typeof(Id!F) == typeof(C.f1))); + static if (i==1) static assert(is(typeof(Id!F) == typeof(C.f2))); + } +} + +/***************************************************/ + +static int g(int n) { return 1; } +static int g(int n, int m) { return 2; } + +void test4() +{ + static class C + { + int f(int n) { return 1; } + int f(int n, int m) { return 2; } + } + auto c = new C(); + static assert(!__traits(compiles, (&c.f)())); + assert((&c.f)(0) == 1); + assert((&c.f)(0,1) == 2); + + static assert(!__traits(compiles, (&g)())); + assert((&g)(0) == 1); + assert((&g)(0,1) == 2); +} + +/***************************************************/ + +struct Test5S +{ + void f() {} + void f(int n) {} + void g() + { + // mtype.c L7107 TODO -> resloved + //pragma(msg, typeof(Test5S.f)); + static assert(is(typeof(Test5S.f))); + static assert(!__traits(compiles, typeof(Test5S.f))); + } + + void h() {} + void h(int n) {} +} +class Test5C +{ + void f() {} + void f(int n) {} + void g() + { + // mtype.c L7646 TODO -> resolved + //pragma(msg, typeof(Test5C.f)); + static assert(is(typeof(Test5C.f))); + static assert(!__traits(compiles, typeof(Test5C.f))); + } + + class N + { + void x() + { + // mtype.c L7660 TODO -> resolved + //pragma(msg, typeof(Test5C.f)); + static assert(is(typeof(Test5C.f))); + static assert(!__traits(compiles, typeof(Test5C.f))); + } + } + +} +void test5() +{ + Test5S s; + s.g(); + // mtype.c L7145 TODO -> resolved + //pragma(msg, typeof(s.h)); + static assert(is(typeof(s.h))); + static assert(!__traits(compiles, typeof(s.h))); + + Test5C c = new Test5C(); + c.g(); + // mtype.c L7694 TODO -> resolved + //pragma(msg, typeof(c.h)); + static assert(is(typeof(c.f))); + static assert(!__traits(compiles, typeof(c.f))); +} + +/***************************************************/ + +void test6() +{ + static class C + { + void f() {} + void f(int n) {} + + void f1() {} + void f2(int n) {} + } + alias C.f Fun; + alias TypeTuple!(__traits(getOverloads, C, "f")) FunSeq; + + /* + When template instantiates, overloaded symbol passed by FuncDeclaratioin. + By the side, non overloaded symbol is passed by VarExp(var=fd, hasOverloads=0), + and its type is same as fd->type. + */ + + static assert(is(typeof(C.f))); + static assert(!__traits(compiles, typeof(C.f))); + // direct + + static assert(is(typeof(Id!(C.f)))); + static assert(!__traits(compiles, typeof(Id!(C.f)))); + // direct -> through template alias parameter + + static assert(is(typeof(Fun))); + static assert(!__traits(compiles, typeof(Fun))); + // indirect(through alias) + + static assert(is(typeof(Id!(Fun)))); + static assert(!__traits(compiles, typeof(Id!(Fun)))); + // indirect -> through template alias parameter + + static assert(is(typeof(FunSeq[0]) == typeof(C.f1))); + static assert(is(typeof(FunSeq[1]) == typeof(C.f2))); + // direct(tuple element) + + static assert(is(typeof(Id!(FunSeq[0])) == typeof(C.f1))); + static assert(is(typeof(Id!(FunSeq[1])) == typeof(C.f2))); + // direct(tuple element) -> through template alias parameter +} + +/***************************************************/ + +void test7() +{ + static class C + { + static int f() { return 1; } + static int f(int n) { return 2; } + + int f1() { return 1; } + int f2(int n) { return 2; } + } + alias C.f Fun; + alias TypeTuple!(__traits(getOverloads, C, "f")) FunSeq; + + assert(C.f( ) == 1); + assert(C.f(0) == 2); + + assert(Id!(C.f)( ) == 1); + assert(Id!(C.f)(0) == 2); + + assert(FunSeq[0]( ) == 1); + assert(FunSeq[1](0) == 2); + static assert(!__traits(compiles, FunSeq[0](0) == 1)); + static assert(!__traits(compiles, FunSeq[1]( ) == 2)); + + assert(Id!(FunSeq[0])( ) == 1); + assert(Id!(FunSeq[1])(0) == 2); + static assert(!__traits(compiles, Id!(FunSeq[0])(0) == 1)); + static assert(!__traits(compiles, Id!(FunSeq[1])( ) == 2)); +} + +/***************************************************/ + +class A8 +{ + static int f() { return 1; } +} +int g8(int n) { return 2; } +alias A8.f fun8; +alias g8 fun8; +void test8() +{ + assert(fun8( ) == 1); + assert(fun8(0) == 2); +} + +/***************************************************/ + +class A9 +{ + static int f() { return 1; } +} +class B9 +{ + static int g(int n) { return 2; } + alias A9.f fun; + alias g fun; +} + +void test9() +{ + assert(B9.fun( ) == 1); + assert(B9.fun(0) == 2); +} + +/***************************************************/ + +class A10 +{ + static int f() { return 1; } + static int f(int n) { return 2; } + alias TypeTuple!(__traits(getOverloads, A10, "f")) F; + alias F[0] f0; + alias F[1] f1; +} +class B10 +{ + static int g(string s) { return 3; } +} + +// int(), int(int), int(string) +alias A10.f fun10_1; +alias B10.g fun10_1; + +// int(), int(string) +alias A10.F[0] fun10_2; +alias B10.g fun10_2; + +// int(), int(int), int(string) +alias fun10_1 fun10_3; +alias fun10_2 fun10_3; + +void test10() +{ + assert(fun10_1() == 1); + assert(fun10_1(0) == 2); + assert(fun10_1("s") == 3); + + assert(fun10_2() == 1); + static assert(!__traits(compiles, fun10_2(0))); + assert(fun10_2("s") == 3); + + assert(A10.f0() == 1); + static assert(!__traits(compiles, A10.f0(0))); + + static assert(!__traits(compiles, A10.f1())); + assert(A10.f1(0) == 2); + + assert(fun10_3() == 1); + assert(fun10_3(0) == 2); + assert(fun10_3("s") == 3); +} + +/***************************************************/ + +void test11() +{ + static class C + { + static int f() { return 1; } + static int f(int n) { return 2; } + + alias TypeTuple!(f) L; + alias L[0] F; + // Keep overloads through template tuple parameter + } + + alias C.L L; + assert(L[0](0) == 2); + assert(L[0]( ) == 1); + static assert(!__traits(compiles, typeof(L[0]) )); + static assert( __traits(compiles, is(typeof(L[0])))); + // L[0] keeps overloaded f + + alias C.F F; + assert(F(0) == 2); + assert(F( ) == 1); + static assert(!__traits(compiles, typeof(F) )); + static assert( __traits(compiles, is(typeof(F)))); + // F keeps overloaded f + + alias TypeTuple!(__traits(getOverloads, C, "F")) Fs; + assert(Fs[0]( ) == 1); + assert(Fs[1](0) == 2); + static assert(!__traits(compiles, Fs[0](0))); + static assert(!__traits(compiles, Fs[1]( ))); + // separate overloads from C.F <- C.L[0] <- TypeTuple!(C.f)[0] +} + +/***************************************************/ + +void test12() +{ + // C.f prefers static functions, and c.f prefers virtual functions. + + int f1() { return 0; } alias typeof(f1) F1; + int f2(int) { return 0; } alias typeof(f2) F2; + int f3(string) { return 0; } alias typeof(f3) F3; + int f4(int[]) { return 0; } alias typeof(f4) F4; + + static class C1 + { + int f() { return 1; } + int f(int) { return 2; } + } + auto c1 = new C1(); + static assert(!__traits(compiles, C1.f ( ))); + static assert(!__traits(compiles, C1.f (100))); + static assert(!__traits(compiles, Id!(C1.f) ( ))); + static assert(!__traits(compiles, Id!(C1.f) (100))); + static assert(!__traits(compiles, TypeTuple!(C1.f)[0]( ))); + static assert(!__traits(compiles, TypeTuple!(C1.f)[0](100))); + static assert(is(typeof(c1.f)) && !__traits(compiles, typeof(c1.f))); // virtual ambiguous + static assert(is(typeof(C1.f)) && !__traits(compiles, typeof(C1.f))); // virtual ambiguous + + static class C2 + { + int f() { return 1; } + int f(int) { return 2; } + static int f(string) { return 3; } + } + auto c2 = new C2(); + static assert(!__traits(compiles, C2.f ( ) )); + static assert(!__traits(compiles, C2.f (100) )); + assert( C2.f ("a") == 3); + static assert(!__traits(compiles, Id!(C2.f) ( ) )); + static assert(!__traits(compiles, Id!(C2.f) (100) )); + assert( Id!(C2.f) ("a") == 3); + static assert(!__traits(compiles, TypeTuple!(C2.f)[0]( ) )); + static assert(!__traits(compiles, TypeTuple!(C2.f)[0](100) )); + assert( TypeTuple!(C2.f)[0]("a") == 3); + static assert(is(typeof(c2.f)) && !__traits(compiles, typeof(c2.f))); // virtual ambiguous + static assert(is(typeof(C2.f) == F3)); // static disambiguous + + static class C31 + { + int f() { return 1; } + static int f(string) { return 3; } + } + auto c31 = new C31(); + static assert(!__traits(compiles, C31.f (100) )); + assert( C31.f ("a") == 3); + static assert(!__traits(compiles, Id!(C31.f) (100) )); + assert( Id!(C31.f) ("a") == 3); + static assert(!__traits(compiles, TypeTuple!(C31.f)[0](100) )); + assert( TypeTuple!(C31.f)[0]("a") == 3); + static assert(is(typeof(c31.f) == F1)); // virtual disambiguous + static assert(is(typeof(C31.f) == F3)); // static disambiguous + + static class C32 + { + int f() { return 1; } + int f(int) { return 2; } + static int f(string) { return 3; } + static int f(int[]) { return 4; } + } + auto c32 = new C32(); + static assert(!__traits(compiles, C32.f ( ) )); + static assert(!__traits(compiles, C32.f (100) )); + assert( C32.f ("a") == 3); + assert( C32.f ([0]) == 4); + static assert(!__traits(compiles, Id!(C32.f) ( ) )); + static assert(!__traits(compiles, Id!(C32.f) (100) )); + assert( Id!(C32.f) ("a") == 3); + assert( Id!(C32.f) ([0]) == 4); + static assert(!__traits(compiles, TypeTuple!(C32.f)[0]( ) )); + static assert(!__traits(compiles, TypeTuple!(C32.f)[0](100) )); + assert( TypeTuple!(C32.f)[0]("a") == 3); + assert( TypeTuple!(C32.f)[0]([0]) == 4); + static assert(is(typeof(c32.f)) && !__traits(compiles, typeof(c32.f))); // virtual ambiguous + static assert(is(typeof(C32.f)) && !__traits(compiles, typeof(C32.f))); // static ambiguous + + static class C4 + { + int f() { return 1; } + static int f(string) { return 3; } + static int f(int[]) { return 4; } + } + auto c4 = new C4(); + static assert(!__traits(compiles, C4.f ( ) )); + assert( C4.f ("a") == 3); + assert( C4.f ([0]) == 4); + static assert(!__traits(compiles, Id!(C4.f) ( ) )); + assert( Id!(C4.f) ("a") == 3); + assert( Id!(C4.f) ([0]) == 4); + static assert(!__traits(compiles, TypeTuple!(C4.f)[0]( ) )); + assert( TypeTuple!(C4.f)[0]("a") == 3); + assert( TypeTuple!(C4.f)[0]([0]) == 4); + static assert(is(typeof(c4.f) == F1)); // virtual disambiguous + static assert(is(typeof(C4.f)) && !__traits(compiles, typeof(C4.f))); // static ambiguous + + static class C5 + { + static int f(string) { return 3; } + static int f(int[]) { return 4; } + } + auto c5 = new C5(); + static assert(!__traits(compiles, C5.f ( ) )); + static assert(!__traits(compiles, C5.f (100) )); + static assert(!__traits(compiles, Id!(C5.f) ( ) )); + static assert(!__traits(compiles, Id!(C5.f) (100) )); + static assert(!__traits(compiles, TypeTuple!(C5.f)[0]( ) )); + static assert(!__traits(compiles, TypeTuple!(C5.f)[0](100) )); + static assert(is(typeof(c5.f)) && !__traits(compiles, typeof(c5.f))); // virtual ambiguous + static assert(is(typeof(C5.f)) && !__traits(compiles, typeof(C5.f))); // virtual ambiguous +} + +/***************************************************/ + +class E13 : Exception +{ + this() { super(""); } +} + +/***************************************************/ + +template isFunction14(func...) +{ + enum isFunction14 = is(typeof(func[0]) == function); +} +template hasReturnType14(func...) +{ + enum isFunction14 = is(typeof(func[0]) == return); +} +template FunctionTypeOf14(func...) +{ + static if (is(typeof(&func[0]) Fsym : Fsym*)) + { + alias Fsym FunctionTypeOf14; + } +} + +void foo14() {} +void foo14(int) {} +static assert( isFunction14!foo14); +static assert(!__traits(compiles, hasReturn14!foo14)); +static assert(!__traits(compiles, FunctionTypeOf14!foo14)); + +/***************************************************/ + +void test15() +{ + static struct S + { + void func(long) {} + void func(string) const {} + } + + // VarExp.mangleof + static assert(S.func.mangleof[$-6..$] == "S4func"); + static assert(__traits(getOverloads, S, "func")[0].mangleof[$-11..$] == "S4funcMFlZv"); + static assert(__traits(getOverloads, S, "func")[1].mangleof[$-14..$] == "S4funcMxFAyaZv"); + + // DotVarExp.mangleof + S ms; + const S cs; + static assert(ms.func .mangleof[$-11..$] == "S4funcMFlZv"); + static assert(cs.func .mangleof[$-14..$] == "S4funcMxFAyaZv"); + static assert(__traits(getOverloads, ms, "func")[0].mangleof[$-11..$] == "S4funcMFlZv"); + static assert(__traits(getOverloads, ms, "func")[1].mangleof[$-14..$] == "S4funcMxFAyaZv"); + static assert(__traits(getOverloads, cs, "func").length == 1); + static assert(__traits(getOverloads, cs, "func")[0].mangleof[$-14..$] == "S4funcMxFAyaZv"); +} + +/***************************************************/ +// 8868 + +void test8868() +{ + struct S + { + static int g1() { return 7; } + int g1(int n) { return 3; } + + int g2(int n) { return 3; } + static int g2() { return 7; } + } + S s; + S func() { return s; } + + auto a1 = &(func()).g1; + auto a2 = &(func()).g2; + auto b1 = &s.g1; + auto b2 = &s.g2; + auto c1 = &S.g1; + auto c2 = &S.g2; + + static assert(is(typeof(a1) == int delegate(int))); + static assert(is(typeof(a2) == int delegate(int))); + static assert(is(typeof(b1) == int delegate(int))); + static assert(is(typeof(b2) == int delegate(int))); + static assert(is(typeof(c1) == int function())); + static assert(is(typeof(c2) == int function())); + + assert(a1(1) == 3); + assert(a2(1) == 3); + assert(b1(1) == 3); + assert(b2(1) == 3); + assert(c1() == 7); + assert(c2() == 7); +} + /***************************************************/ // 1528 @@ -1215,6 +1837,19 @@ void test14965() int main() { + test1(); + test2(); + test3(); + test4(); + test5(); + test6(); + test7(); + test8(); + test9(); + test10(); + test11(); + test12(); + test8868(); test1528a(); test1528b(); test1528c(); diff --git a/test/runnable/testconst.d b/test/runnable/testconst.d index 3c2c8f2e405c..412cc3cc7b05 100644 --- a/test/runnable/testconst.d +++ b/test/runnable/testconst.d @@ -2148,18 +2148,19 @@ void test5473() class C { int b; - void f(){} + void f() const {} static int x; static void g(){}; } struct S { int b; - void f(){} + void f() const {} static int x; static void g(){}; } + alias void VoidConstFunc() const; void dummy(){} alias typeof(dummy) VoidFunc; @@ -2171,12 +2172,12 @@ void test5473() alias typeof(a) A; static assert(is(typeof(a.b) == const int)); // const(int) - static assert(is(typeof(a.f) == VoidFunc)); + static assert(is(typeof(a.f) == VoidConstFunc)); static assert(is(typeof(a.x) == int)); static assert(is(typeof(a.g) == VoidFunc)); static assert(is(typeof((const A).b) == const int)); // int, should be const(int) - static assert(is(typeof((const A).f) == VoidFunc)); + static assert(is(typeof((const A).f) == VoidConstFunc)); static assert(is(typeof((const A).x) == int)); static assert(is(typeof((const A).g) == VoidFunc)); } diff --git a/test/runnable/xtest46.d b/test/runnable/xtest46.d index 1bafd4209b61..a47439bf7aed 100644 --- a/test/runnable/xtest46.d +++ b/test/runnable/xtest46.d @@ -4898,17 +4898,17 @@ void test5696() /***************************************************/ // 5933 -int dummyfunc5933(); +int dummyfunc5933() pure nothrow @nogc @safe; alias typeof(dummyfunc5933) FuncType5933; struct S5933a { auto x() { return 0; } } static assert(is(typeof(&S5933a.init.x) == int delegate() pure nothrow @nogc @safe)); struct S5933b { auto x() { return 0; } } -//static assert(is(typeof(S5933b.init.x) == FuncType5933)); +static assert(is(typeof(S5933b.init.x) == FuncType5933)); struct S5933c { auto x() { return 0; } } -static assert(is(typeof(&S5933c.x) == int function())); +static assert(is(typeof(&S5933c.x) == int function() pure nothrow @nogc @safe)); struct S5933d { auto x() { return 0; } } static assert(is(typeof(S5933d.x) == FuncType5933)); @@ -4918,10 +4918,10 @@ class C5933a { auto x() { return 0; } } static assert(is(typeof(&(new C5933b()).x) == int delegate() pure nothrow @nogc @safe)); class C5933b { auto x() { return 0; } } -//static assert(is(typeof((new C5933b()).x) == FuncType5933)); +static assert(is(typeof((new C5933b()).x) == FuncType5933)); class C5933c { auto x() { return 0; } } -static assert(is(typeof(&C5933c.x) == int function())); +static assert(is(typeof(&C5933c.x) == int function() pure nothrow @nogc @safe)); class C5933d { auto x() { return 0; } } static assert(is(typeof(C5933d.x) == FuncType5933));