Shortening default(T) is the same problem as removing the redundant cast
around a lambda whose delegate type the context already fixes, so it uses
the same mechanism: ConvertTo makes the explicit type implicit when the
conversion is an identity conversion and the caller allows an implicit
one. The literal keeps the type it was shortened from, so any later
conversion to a different type - or any context that requires an explicit
type, such as an overload resolution recheck falling back to CastArguments
- can spell default(T) out again. That keeps the value intact where the
bare literal would change it, e.g. "object o = default(SomeStruct)", which
boxes a non-null struct while "default" would be null.
Because the shortened literal resolves to DefaultLiteralResolveResult,
CallBuilder's existing overload resolution recheck sees a real default
literal and rejects ambiguous calls on its own; no separate bookkeeping
about which arguments may stay untyped is needed. Only the contexts that
supply no target type at all restore the explicit form: an awaited
expression, and arguments of operator methods, which later become operator
or cast syntax rather than calls.
Assisted-by: Claude:claude-opus-5[1m]:Claude Code
Auditing against the first-class-span-types proposal turned up three
deviations, each now pinned by resolver unit tests whose expectations were
established by compiling probe programs with the C# 14 compiler.
Lower-bound type inference recursed into Span<T> targets as another
lower-bound inference, but Span<T> is invariant and the spec demands an
exact element inference there: M<T>(Span<T>, T) with (Span<string>, object)
must fail inference (CS0411), not unify to T=object.
Better-conversion-target compared ReadOnlySpan element types where the spec
compares the span types, admitting numeric and user-defined element
conversions the span types do not share: overloads taking ReadOnlySpan<int>
and ReadOnlySpan<long> are ambiguous (CS0121), not resolvable. The general
mutual-convertibility rule already implements the spec's span-type test, so
the element-level block is simply removed; the ReadOnlySpan-over-Span
identity rule stays, since it deliberately inverts that general rule.
The explicit span conversion did not exist at all, and with it the rule that
user-defined conversions are not considered between span-convertible types.
The visible consequence: string[] to Span<object> classified as an implicit
user-defined conversion via op_Implicit(object[]) plus array covariance,
where the compiler reports CS0266 - only the explicit span conversion
exists. Span conversions are also no longer considered for extension
receivers during method group conversion (CS0123), while invocations keep
them.
Part of #829.
Assisted-by: Claude:claude-fable-5:Claude Code