Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implicit stuff #47

Merged
merged 3 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
37 changes: 37 additions & 0 deletions compiler/src/dmd/aggregate.d
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,43 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
return ok ? structsize : SIZE_INVALID;
}

extern (D) final bool hasImplicitConstructor()
{
auto ctor = searchCtor();
if (ctor is null)
return false;

int overloadcount = 0;
Dsymbol funcRootEncountered;
Dsymbol getNextOverload(Dsymbol what) {
overloadcount++;
if(overloadcount > 200) {
import core.stdc.stdlib;
abort();
}
if (auto fd = what.isTemplateDeclaration()) {
if (fd.overnext)
return fd.overnext;
if (fd.funcroot && fd.funcroot !is funcRootEncountered) {
return funcRootEncountered = fd.funcroot;
}
return null;
}
if (auto fd = what.isFuncDeclaration())
return fd.overnext;
return null;
}

auto next = ctor;
while (next) {
if (hasImplicitAttr(next))
return true;
next = getNextOverload(next);
}

return false;
}

/***************************************
* Calculate field[i].overlapped and overlapUnsafe, and check that all of explicit
* field initializers have unique memory space on instance.
Expand Down
63 changes: 63 additions & 0 deletions compiler/src/dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,69 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
return implicitCastTo(result, sc, t);
}

if (t.ty != Terror && e.type.ty != Terror)
{

AggregateDeclaration ad = isAggregate(t);

if (ad) {
import dmd.identifier;
import dmd.id;
auto tmp = new VarDeclaration(e.loc, t, Identifier.generateId("__ictorcmp"), null);
tmp.dsymbolSemantic(sc);

Expression ve = new VarExp(e.loc, tmp);
Expression e2 = new DotIdExp(e.loc, ve, Id.ctor);
auto ce = new CallExp(e.loc, e2, e);
e2 = ce;
if (sc && .trySemantic(e2, sc)) {
if (hasImplicitAttr(ce.f)) {
result = e2.expressionSemantic(sc);
// printf("implicit construction of %s @ %s\n", t.toChars(), e.loc.toChars());
return result;
}
}
}
}

if (t.ty != Terror && e.type.ty != Terror)
{
// printf("------\n");
// printf("MOJO %s %s \n", e.type.toPrettyChars(true), t.toPrettyChars(true));

import dmd.id : Id;
AggregateDeclaration ad = isAggregate(e.type);

if (ad) {
// try opImplicitCast
Dsymbol fd = null;
fd = search_function(ad, Id._cast_impl);

if (fd) {
auto tiargs = new Objects();
tiargs.push(t);
auto dti = new DotTemplateInstanceExp(e.loc, e, fd.ident, tiargs);
auto ce = new CallExp(e.loc, dti);
if (sc && .trySemantic(ce, sc)) {
result = ce.expressionSemantic(sc);
return result;
} else {
if (auto td = dti.ti.tempdecl.isTemplateDeclaration) {
const(char)* extra;
if(td.constraintFailed) {
// the constraint didn't match, the error can stay silent

// printf("constraint no match\n");
} else {
// constraint matched, forward the error
error(e.loc, "`%s.opImplicitCast!(%s)` attempted and matched constraint but suffered instantiation failure, try explicitly doing it yourself in your program for details", e.toChars(), t.toChars());
}
}
}
}
}
}

if (t.ty != Terror && e.type.ty != Terror)
{
if (!t.deco)
Expand Down
18 changes: 18 additions & 0 deletions compiler/src/dmd/dsymbol.d
Original file line number Diff line number Diff line change
Expand Up @@ -2009,3 +2009,21 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy

return collision();
}

bool hasImplicitAttr(Dsymbol sym)
{
import dmd.attrib : foreachUdaNoSemantic;
import dmd.errors : error;
import dmd.id : Id;

bool result = false;
foreachUdaNoSemantic(sym, (exp) {
if (isEnumAttribute(exp, Id.udaImplicit)) // FIXME
result = true;
return 0;
});

return result;
}


3 changes: 3 additions & 0 deletions compiler/src/dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ version (IN_LLVM)
const(char)* intrinsicName;
}

bool constraintFailed; // tries to tell if there ever was a constraint that failed, even if it got gagged...
private Expression lastConstraint; /// the constraint after the last failed evaluation
private Array!Expression lastConstraintNegs; /// its negative parts
private Objects* lastConstraintTiargs; /// template instance arguments for `lastConstraint`
Expand Down Expand Up @@ -907,6 +908,7 @@ else
fd.declareThis(scx);
}

constraintFailed = true;
lastConstraint = constraint.syntaxCopy();
lastConstraintTiargs = ti.tiargs;
lastConstraintNegs.setDim(0);
Expand All @@ -919,6 +921,7 @@ else
const bool result = evalStaticCondition(scx, constraint, lastConstraint, errors, &lastConstraintNegs);
if (result || errors)
{
constraintFailed = false;
lastConstraint = null;
lastConstraintTiargs = null;
lastConstraintNegs.setDim(0);
Expand Down
2 changes: 2 additions & 0 deletions compiler/src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ immutable Msgtable[] msgtable =
{ "sliceass", "opSliceAssign" },
{ "call", "opCall" },
{ "_cast", "opCast" },
{ "_cast_impl", "opImplicitCast" }, // NOTE: Maybe just opImplicitCast?
{ "opIn" },
{ "opIn_r" },
{ "opStar" },
Expand Down Expand Up @@ -530,6 +531,7 @@ immutable Msgtable[] msgtable =
{ "udaSelector", "selector" },
{ "udaOptional", "optional"},
{ "udaMustUse", "mustuse" },
{ "udaImplicit", "implicit" },
{ "udaStandalone", "standalone" },
{ "udaMutableRefInit", "mutableRefInit" },

Expand Down
78 changes: 78 additions & 0 deletions compiler/src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,84 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
if (!arg)
continue; // default argument
m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);

if (m == MATCH.nomatch) {
// Try implicit construction
//Dsymbol fd = null;

if (auto ad = isAggregate(p.type))
if (ad.hasImplicitConstructor()) {
auto tmp = new VarDeclaration(arg.loc, p.type, Identifier.generateId("__ictorcmp"), null);
tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
tmp.dsymbolSemantic(sc);

Expression ve = new VarExp(arg.loc, tmp);
Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
auto ce = new CallExp(arg.loc, e, arg);
e = ce;

//printf("%s to %s @ %s in %llx dddddddd\n", e.toChars(), p.type.toChars(), arg.loc.toChars(), cast(ulong)sc);
if (sc && .trySemantic(e, sc)) {
if (hasImplicitAttr(ce.f)) {
auto cast_m = argumentMatchParameter(tf, p, e, wildmatch, flag, sc, pMessage);
if (cast_m == MATCH.exact) {
// printf("ctor complete %s(%s) @ %s\n", p.type.toChars(), arg.toChars(), arg.loc.toChars());
m = MATCH.convert;
}
}
}
}
}

if (m == MATCH.nomatch) {
AggregateDeclaration ad = isAggregate(arg.type);
// still no match...
if (ad) {
// Try opImplicitCast
Dsymbol fd = null;
fd = search_function(ad, Id._cast_impl);

if (fd) {
auto tiargs = new Objects();
tiargs.push(p.type);

Expression opCastExp = new DotTemplateInstanceExp(arg.loc, arg, fd.ident, tiargs);
opCastExp = new CallExp(arg.loc, opCastExp);

// NOTE: trySemantic but explicit
{
uint errors = global.startGagging();
Expression e = opCastExp.expressionSemantic(sc);
if (global.endGagging(errors))
{
opCastExp = null;
}
else {
opCastExp = e;
}
}

// printf("1\n");
// if (opCastExp.trySemantic(sc)) {
// opCastExp = opCastExp.expressionSemantic(sc);
// }

//printf("2\n");

if (opCastExp) {
auto cast_m = argumentMatchParameter(tf, p, opCastExp, wildmatch, flag, sc, pMessage);
//printf("3\n");

if (cast_m == MATCH.exact) {
//printf("MOJO: Exact match on implicit cast.\n");
//printf("MOJO: %s\n", opCastExp.toChars());
// args[u] = opCastExp;
m = MATCH.convert;
}
}
}
}
}
}
else if (p.defaultArg)
continue;
Expand Down
5 changes: 5 additions & 0 deletions druntime/src/core/attribute.d
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,8 @@ enum standalone;
* Use this attribute to indicate that you wish to initialize a field with a mutable reference type.
*/
enum mutableRefInit;

/++
Use this to mark a constructor as usable for implicit calls.
+/
enum implicit;