Q:

Inconsistent "possible lossy conversion from int to byte" compile-time error

Examine the following code snippets:
Snippet #1
int a=20;
int b=30;
byte c= (a>b)? 20:30;

Error:
incompatible types: possible lossy conversion from int to byte
byte c= (a>b)? 20:30;

Snippet #2
int a=20;
int b=30;
byte h1=70;
byte c= (a>b)? 20:h1;

Snippet #3
int a=20;
int b=30;
byte h1=70;
byte h2=89;
byte c= (a>b)? h1:h2;

Snippet #4
byte c= (true)? 20:30;

All of these compile fine except for Snippet #1. How is this behavior justified? If Snippet #1 produces the "possible lossy conversion" error, Snippets #2 and 4 should also, given that they still contain literals of type int. Why do they compile successfully?

A:

J.L.S 15.25. explains this behavior.
Snippet #1:

If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression

Both the second and third operands are int literals, so the type of the expression is also int, which cannot be assigned to a byte variable without explicit cast. Hence the compilation error.
Snippet #2:

If one of the operands is of type T where T is byte, short, or char, and the other operand is a constant expression (§15.28) of type int whose value is representable in type T, then the type of the conditional expression is T.

One operand is a byte and the other is an int literal whose value can be represented as byte, so the type of the expression is byte, which can be assigned to a byte variable.
Snippet #3:

If the second and third operands have the same type (which may be the null type), then that is the type of the conditional expression

Both the second and third operands are byte, so the type of the expression is byte, which can be assigned to a byte variable.
Snippet #4:
Since all 3 operands are constant, the entire ternary expression is a constant expression, so the compiler treats this expression as a simple assignment - byte c = 20; - which is valid.

A:

This behaviour is described in the language spec.

Case 1 and 3 are described by the same point:

If the second and third operands have the same type, then that is the type of the conditional expression.

In case 1, the operands are of type int, so the overall expression is of type int, so it is incompatible. In case 3, the operands of of type byte, hence the result is compatible.

Case 2 is surprising to me: I would have expected that to fail as well, because the int operand would cause the conditional expression to be of int type.
However, this behaviour is described in the following point:

If one of the operands is of type T where Tis byte, short, or char, and the other operand is a constant expression (§15.28) of type int whose value is representable in type T, then the type of the conditional expression is T.

The 20 is a constant expression which fits in byte, hence the result is a byte.

Case 4 is also described by the "operands of the same type rule" used for cases 1 and 3; however, the fact that the condition is now constant makes it a constant expressions.
A constant expressions of int type is implicitly narrowed when assigning to a variable of narrower type, as described in Assignment contexts:

A narrowing primitive conversion may be used if the variable is of type byte, short, or char, and the value of the constant expression is representable in the type of the variable.

