https://issues.dlang.org/show_bug.cgi?id=14035
--- Comment #6 from yebblies <[email protected]> --- The type of ln doesn't change. The template expands to something like enum uint ln = 4; enum alice = "{ int t_"~ln~" = 42; }"; As the compiler knows the _value_ for ln, it expands alice's initializer to enum alice = "{ int t_"~4~" = 42; }"; Then, because it knows that 4 can fit in a char, it allows it to become this: enum alice = "{ int t_"~cast(char)4~" = 42; }"; And then the concatenation is semantically valid. As I said in my first comment, range propagation is allowed so that code like this will still work: enum str = "abc" ~ ('a' + 7); Here ('a' + 7) has type int, but because we know the value at compile time and know it will fit in a char, it is allowed to be narrowed. --
