Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions compiler/src/dmd/dcast.d
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,28 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
return implicitCastTo(result, sc, t);
}

// Try opImplicitCast
if (t.ty != Terror && e.type.ty != Terror)
{
import dmd.id : Id;
AggregateDeclaration ad = isAggregate(e.type);

if (ad)
{
if (Dsymbol fd = search_function(ad, Id.opImplicitCast))
{
// Rewrite as: e.opImplicitCast!(t)()
auto tiargs = new Objects();
tiargs.push(t);
Expression ex = new DotTemplateInstanceExp(e.loc, e, fd.ident, tiargs);
ex = new CallExp(e.loc, ex);
ex = ex.expressionSemantic(sc);
if (!ex.isErrorExp())
return ex;
}
}
}

if (t.ty == Terror || e.type.ty == Terror)
return ErrorExp.get();

Expand Down
1 change: 1 addition & 0 deletions compiler/src/dmd/id.d
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ immutable Msgtable[] msgtable =
{ "opSliceAssign" },
{ "opCall" },
{ "opCast" },
{ "opImplicitCast" },
{ "opDispatch" },
{ "opDollar" },
{ "opUnary" },
Expand Down
30 changes: 30 additions & 0 deletions compiler/src/dmd/typesem.d
Original file line number Diff line number Diff line change
Expand Up @@ -2301,6 +2301,36 @@ extern (D) MATCH callMatch(FuncDeclaration fd, TypeFunction tf, Type tthis, Argu
buf.reset();
buf.writestring(failMessage);
}
// Try opImplicitCast if direct match failed
if (m == MATCH.nomatch && sc && !sc.traitsCompiles && sc.intypeof != 1)
{
AggregateDeclaration ad = isAggregate(arg.type);
if (ad)
{
if (Dsymbol castFn = search_function(ad, Id.opImplicitCast))
{
// Rewrite as: arg.opImplicitCast!(p.type)()
auto tiargs = new Objects();
tiargs.push(p.type);
Expression ex = new DotTemplateInstanceExp(arg.loc, arg, castFn.ident, tiargs);
ex = new CallExp(arg.loc, ex);

// Sema to avoid error message spam
uint errors = global.startGagging();
ex = ex.expressionSemantic(sc);
if (!global.endGagging(errors) && !ex.isErrorExp())
{
// Retry match with the converted expression
m = argumentMatchParameter(fd, tf, p, ex, wildmatch, flag, sc, pMessage);
if (m != MATCH.nomatch)
{
// Update the argument for the actual call
args[u] = ex;
}
}
}
}
}
}
else if (p.defaultArg)
continue;
Expand Down
114 changes: 114 additions & 0 deletions compiler/test/fail_compilation/opimplicitcast.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// REQUIRED_ARGS: -o-

/*
TEST_OUTPUT:
---
fail_compilation/opimplicitcast.d(18): Error: cannot implicitly convert expression `s` of type `NoCastStruct` to `int`
---
*/
// No matching opImplicitCast
struct NoCastStruct
{
int value;
}

void testNoCast()
{
NoCastStruct s;
int x = s;
}

/*
TEST_OUTPUT:
---
fail_compilation/opimplicitcast.d(45): Error: template instance `opimplicitcast.WrongReturnStruct.opImplicitCast!int` does not match template declaration `opImplicitCast(T)()`
with `T = int`
must satisfy the following constraint:
` __traits(isSame, T, string)`
fail_compilation/opimplicitcast.d(45): Error: cannot implicitly convert expression `s` of type `WrongReturnStruct` to `int`
---
*/
// opImplicitCast with wrong constraint
struct WrongReturnStruct
{
int value;

T opImplicitCast(T)() if (__traits(isSame, T, string))
{
return "hello";
}
}

void testWrongReturn()
{
WrongReturnStruct s;
int x = s;
}

/*
TEST_OUTPUT:
---
fail_compilation/opimplicitcast.d(63): Error: cannot implicitly convert expression `c` of type `opimplicitcast.NoCastClass` to `int`
---
*/
// Class without opImplicitCast
class NoCastClass
{
int value;
}

void testClassNoCast()
{
NoCastClass c = new NoCastClass();
int x = c;
}

/*
TEST_OUTPUT:
---
fail_compilation/opimplicitcast.d(79): Error: undefined identifier `NonExistent`
fail_compilation/opimplicitcast.d(86): Error: template instance `opimplicitcast.ErrorCastStruct.opImplicitCast!int` error instantiating
fail_compilation/opimplicitcast.d(86): Error: cannot implicitly convert expression `s` of type `ErrorCastStruct` to `int`
---
*/
// opImplicitCast with semantic error
struct ErrorCastStruct
{
T opImplicitCast(T)() if (__traits(isSame, T, int))
{
return NonExistent.value;
}
}

void testErrorCast()
{
ErrorCastStruct s;
int x = s;
}

/*
TEST_OUTPUT:
---
fail_compilation/opimplicitcast.d(113): Error: template instance `opimplicitcast.NoMatchStruct.opImplicitCast!string` does not match template declaration `opImplicitCast(T)()`
with `T = string`
must satisfy the following constraint:
` __traits(isSame, T, int)`
fail_compilation/opimplicitcast.d(113): Error: cannot implicitly convert expression `s` of type `NoMatchStruct` to `string`
---
*/
// opImplicitCast exists but not for requested type
struct NoMatchStruct
{
int value;

T opImplicitCast(T)() if (__traits(isSame, T, int))
{
return value;
}
}

void testNoMatch()
{
NoMatchStruct s;
string x = s;
}
Loading
Loading