D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 19616 - Result type of ternary operator connecting pointers/slices of class handles broken
Summary: Result type of ternary operator connecting pointers/slices of class handles b...
Status: NEW
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 critical
Assignee: No Owner
URL:
Keywords: accepts-invalid, rejects-valid, safe
Depends on:
Blocks:
 
Reported: 2019-01-26 00:52 UTC by Bolpat
Modified: 2024-12-13 19:02 UTC (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Bolpat 2019-01-26 00:52:01 UTC
Connecting two pointers/slices of class handles results in weird error messages and behavior.

    @safe:

    // disables constant folding!
    bool condValue;
    bool cond() { return condValue; };

    class Base { }
    class Derived : Base { }

    Base base;
    Derived derived;

    static this()
    {
        base = new Base;
        derived = new Derived;
        condValue = false;
    }

    Base[] baseArr;
    Derived[] derivedArr;

In this setup, the expression
    auto arr = cond() ? baseArr : derivedArr;
gives the error message
    Error: incompatible types for (baseArr) : (derivedArr): Base[] and Derived[]
while clearly const(Base)[] is the best common type. If this is not liked, void*[] is another option.
Explicitly casting `derivedArr` to `const(Base)[]` solves that.
It hinders type inference and usage of `auto`, but fortunately, it won't do actual harm.

Creating pointers is no issue.

    Base* basePtr = &base;
    Derived* derivedPtr = &derived;

Connecting them in a tenery expression gives an undescriptive error message:
    Error: cannot implicitly convert expression [..] of type Base* to Base*
This is useless while the type should be const(Base)*.

Surprisingly, this statement compiles:

    *(cond() ? basePtr : derivedPtr) = new Base();

Note that cond() returns false, i.e. derivedPtr now points to a Base object.
Note that this is @safe code.
Comment 1 Bolpat 2019-06-06 21:18:23 UTC
The same is true for interfaces:

interface I { }
interface A : I { }
bool condValue;
bool cond() { return condValue; }

pragma(msg, typeof(cond() ? &a : cond() ? &b : &i)); // I*
I* iPtr = cond() ? &a : &i; // fails with error message: cannot assign I* to I*
const(I)* iPtr = cond() ? &a : &i; // succeeds
(cond() ? a : i) = i; // succeeds and breaks @safe
Comment 2 dlangBugzillaToGithub 2024-12-13 19:02:12 UTC
THIS ISSUE HAS BEEN MOVED TO GITHUB

https://github.com/dlang/dmd/issues/19533

DO NOT COMMENT HERE ANYMORE, NOBODY WILL SEE IT, THIS ISSUE HAS BEEN MOVED TO GITHUB