D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 7069 - Variant Doesn't Handle Const or Immutable Contents
Summary: Variant Doesn't Handle Const or Immutable Contents
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P2 major
Assignee: No Owner
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2011-12-05 21:52 UTC by Andrew Wiley
Modified: 2014-02-15 14:21 UTC (History)
3 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Andrew Wiley 2011-12-05 21:52:07 UTC
Example code:
--------
import std.variant;

class Bob {}

void main() {
	immutable(Bob) bob = new immutable(Bob)();
	Variant v = bob;
	
	immutable(Bob) bob2 = v.get!(immutable(Bob))();
}
--------
Runtime Error:
core.exception.AssertError@C:\D\dmd2\windows\bin\..\..\src\phobos\std\variant.d(286): immutable(Bob)

This comes from here in std.variant:
--------
static if (is(typeof(*cast(T*) target = *src)))
{
    auto zat = cast(T*) target;
    if (src)
    {
        assert(target, "target must be non-null");
        *zat = *src;
    }
}
else
{
    // type is not assignable
    if (src) assert(false, A.stringof); // <-- line 286
}
--------

In this case, T is of type immutable(Bob). The check for assignability fails for any immutable type (or any type that contains immutable values) even though technically this code is initializing an immutable value and should be legal.

One way to make this work is to rewrite the above code to this:
--------
static if (is(typeof(*cast(T*) target = *src)))
{
    auto zat = cast(T*) target;
    if (src)
    {
        assert(target, "target must be non-null");
        *zat = *src;
    }
}
else static if (is(T V == const(U), U) || is(T V == immutable(U), U))
{
	auto zat = cast(U*) target;
	if (src)
	{
		assert(target, "target must be non-null");
		*zat = *(cast(U*) (src));
	}
}
else
{
    // type is not assignable
    if (src) assert(false, A.stringof);
}
--------

Which is basically casting away immutability to copy the reference.
This sort of situation makes a compelling argument for the idea of a tail const reference, or a mutable reference to const or immutable data.
Comment 1 Rob Jacques 2011-12-06 16:32:22 UTC
I've added this to my test suite for improving variant. It causes compile-time errors in my current code base, but I will work on a fix.
Comment 2 Dicebot 2013-11-12 04:59:01 UTC
This bug prevents std.concurrency from working as advertised (can't send immutable messages) : http://forum.dlang.org/post/faxtweqqvpkcgolxzwzs@forum.dlang.org

Raising importance to "major" because of that.
Comment 3 Kapps 2014-02-15 14:21:53 UTC
This appears to have been fixed in git master: https://github.com/D-Programming-Language/phobos/commit/6e7eabbd42a7f2e3e555081e1b17893c3c18b6f8

import std.variant, std.stdio;

class Bob {}

void main() {
    immutable(Bob) bob = new immutable(Bob)();
    writeln(cast(void*)bob);
    Variant v = bob;

    immutable(Bob) bob2 = v.get!(immutable(Bob))();
    writeln(cast(void*)bob2);
}

Prints out

1091E4FF0
1091E4FF0