To elaborate on what others have said, this issue arises because there are two different "ways" to get a value of type Optional<Any> from the value Optional<String>.none. One is to do the covariant optional-optional conversion (since String is a subtype of Any) to turn Optional<String>.none into Optional<Any>.none. The other is to interpret Optional<String>.none as a value of type Any and then perform the value-to-optional conversion to obtain a value of type Optional<Any> (containing .some(Optional<String>.none as Any)).
I'll echo @anon9791410 in saying that Any? is a pretty awful type to work with in general, especially when the underlying concrete type is some sort of optional (as it is with dictionaries). I would avoid it at all costs, or you'll constantly be fighting the language and specifying explicit type coercions to avoid the implicit rules that (usually) make it much more ergonomic to work with optionals.
Thanks all for the replies. I think I’m getting closer to understanding. Let me see if I’m getting this right:
In dict1, the assigned value must be interpreted as Optional<Optional<Any>>.none
In dict2, the assigned value must be interpreted as Optional<Optional<Any>>.some(.none). This is a result of optional promotion since the type specified is Optional<Any>.
In this specific example, how do we get from Optional<String>.none to Optional<Optional<Any>>.none?
Is String a subtype of Optional<Any>? Is optional promotion applied to the generic parameter String to obtain Optional<Optional<String>> which is then converted to Optional<Optional<Any>>? Neither of these seem right to me, so I think there must be another answer that I’m not seeing.
The interesting stuff begins at optional_evaluation_expr (since that is the left-hand side of the assignment). If you just look at the type declarations you can see that the Optional<String> is converted into Any?? via the following process (proceeding from inside to outside):
Convert from Optional<String> to String via bind_optional_expr.
This generally corresponds to the presence of an optional-chaining ?, but in this place it's implicit in the optional-optional conversion. A bind_optional_expr always has a corresponding outer optional_evaluation_expr. If the bind_optional_expr fails to find a value, the optional_evaluation_expr immediately evaluates to .none.
Convert String to Any via erasure_expr (i.e., existential conversion).
Convert Any to Any? via inject_into_optional (i.e., wrap it in .some(...)).
Convert Any? to Any?? via inject_into_optional.
So, in the case where we are converting Optional<String>.none to type Optional<Optional<Any>>, we follow the process in the bullet point below (1), i.e., the bind_optional_expr fails and the optional_evaluation_expr immediately evaluates to .none. Since the type of the optional_evaluation_expr is Optional<Optional<Any>>, so we end up with the value Optional<Optional<Any>>.none.
As for why we end up with this type-checked expression, when solving the left-hand side, we have to convert from Optional<String> (the type of Optional<String>.none) to Optional<Optional<Any>> (the type expected by the subscript). Optional-optional conversion is permitted when we can convert the wrapped types, so we try to convert String to Optional<Any>. This conversion is permitted when the non-optional type is convertible to the optional's wrapped type, so we try to convert String to Any, which straightforwardly succeeds (since anything can convert to Any).