Consider the following code:
bool x;
bool? y = null;
x = y?? true;
Assigning a bool? to a bool is a compile-time error, but the above code succeeds both at compile and run-time. Why? Although the 3rd statement ensures we never assign null to x, in case y is not null, we're still assigning a bool? to a bool, so it should be an error from compiler's POV, no?
Or is it that C# compiler is smart enough to find out that a particular piece of code cannot possibly create a situation where a null would be assigned to x?

The type of this expression:
y ?? true
is bool, not bool?.
From section 7.13 of the C# 5 spec:
The type of the expression
a ?? bdepends on which implicit conversions are available on the operands. In order of preference, the type ofa ?? bis A0, A, or B, where A is the type of a (provided that a has a type), B is the type of b (provided that b has a type), and A0 is the underlying type of A if A is a nullable type, or A otherwise. Specifically,a ?? bis processed as follows:
- If A exists and is not a nullable type or a reference type, a compile-time error occurs.
- If
bis a dynamic expression, the result type is dynamic. At run-time,ais first evaluated. Ifais not null,ais converted to dynamic, and this becomes the result. Otherwise,bis evaluated, and this becomes the result.- Otherwise, if A exists and is a nullable type and an implicit conversion exists from
bto A0, the result type is A0. At run-time,ais first evaluated. Ifais not null,ais unwrapped to type A0, and this becomes the result. Otherwise,bis evaluated and converted to type A0, and this becomes the result.- Otherwise, if A exists and an implicit conversion exists from
bto A, the result type is A. At run-time,ais first evaluated. Ifais not null,abecomes the result. Otherwise,bis evaluated and converted to type A, and this becomes the result.- Otherwise, if
bhas a type B and an implicit conversion exists from a to B, the result type is B. At run-time,ais first evaluated. Ifais not null,ais unwrapped to type A0 (if A exists and is nullable) and converted to type B, and this becomes the result. Otherwise,bis evaluated and becomes the result.- Otherwise,
aandbare incompatible, and a compile-time error occurs.
In your case, we're in the third bullet:
bool?boolbool... so the result type is bool, and you can assign that to a variable of type bool.
See more on this question at Stackoverflow