Bug 20410 – ReplaceTypeUnless replaces enums with their basetype
Status
RESOLVED
Resolution
FIXED
Severity
major
Priority
P1
Component
dmd
Product
D
Version
D2
Platform
x86
OS
All
Creation time
2019-11-21T12:11:29Z
Last change time
2020-06-06T09:20:17Z
Keywords
pull
Assigned to
No Owner
Creator
Sebastiaan Koppe
Comments
Comment #0 by mail — 2019-11-21T12:11:29Z
ReplaceTypeUnless (and probably ReplaceType) decay enums into their base types. This causes issues with e.g. the Sumtype library, which expects its template argument list to contain no duplicates. (internally sumtype uses ReplaceTypeUnless as well, thereby invalidating its own invariant.)
---
import std.meta;
import std.typecons;
import std.traits;
enum Enum : string { foo = "Bar" }
alias seq = AliasSeq!(string, Nullable!string, Enum, Nullable!Enum);
alias replaced = ReplaceTypeUnless!(isBoolean, int, uint, seq);
pragma(msg, seq); // prints: (string, Nullable!string, Enum, Nullable!(Enum)
pragma(msg, replaced); // prints: (string, Nullable!string, string, Nullable!string)
void main() {
}
---
Comment #1 by simen.kjaras — 2019-11-21T12:56:40Z
This is only true where the base type of the enum fits one of the other patterns that ReplaceTypeUnless looks for, e.g. U[], U*, etc. - it will leave regular enums well enough alone, but string enums and the like will decay to their base types. Of course, there is a discussion to be had here - should the type change if I do this?
import std.typecons : ReplaceType;
enum Foo : string { bar = "baz" }
pragma(msg, ReplaceType!(char, int, Foo));
Currently, that'd be immutable(int)[], since Foo is a kind of immutable(char)[], and I've asked to replace char with int.
While there are arguments to be had on both sides of this, I'd go with treating enums as opaque, since it's easier to forcibly decay them than filter them out beforehand.
Should be a simple two lines here: https://github.com/dlang/phobos/blob/58cb6963fbe54e7dc96ae8b48064e84f1eaf818a/std/typecons.d#L8748
else static if (is(T[0] == enum))
alias ReplaceTypeUnless = T;
test case:
@safe unittest
{
enum Enum : string { foo = "Bar" }
assert(is(ReplaceType!(char, int, Enum)[0] == Enum));
}
Comment #2 by snarwin+bugzilla — 2019-11-22T15:21:24Z
Looks like a bug in the is expression. The "true" below ought to be "false":
enum Enum : string { foo = "bar" }
pragma(msg, is(Enum == string)); // false
pragma(msg, is(Enum == T[], T)); // true
pragma(msg, T); // immutable(char)
Comment #3 by dlang-bot — 2020-06-06T01:31:37Z
@pbackus updated dlang/dmd pull request #11235 "Fix 20410 - ReplaceTypeUnless replaces enums with their basetype" fixing this issue:
- Fix issue 20410 - ReplaceTypeUnless replaces enums with their basetype
When matching an enum against a type specialization, a match obtained
using the enum's base type is now correctly considered a match by
implicit conversion rather than an exact match.
https://github.com/dlang/dmd/pull/11235
Comment #4 by dlang-bot — 2020-06-06T09:20:17Z
dlang/dmd pull request #11235 "Fix 20410 - ReplaceTypeUnless replaces enums with their basetype" was merged into master:
- 98259447cd40f28b539574dacd822a11aeb8167c by Paul Backus:
Fix issue 20410 - ReplaceTypeUnless replaces enums with their basetype
When matching an enum against a type specialization, a match obtained
using the enum's base type is now correctly considered a match by
implicit conversion rather than an exact match.
https://github.com/dlang/dmd/pull/11235