C# 10 converts a lambda's function type to System.MulticastDelegate, its base
classes and its interfaces, and an expression tree's to Expression and
LambdaExpression, so 'Delegate d = (Func<int, int>)((int x) => x);' names a
type the language re-infers. The natural-type annotation now also marks
anonymous functions, and the declaration site drops the redundant cast.
The 'var' shortcut stays method-group-only on purpose: 'var' over an
expression tree infers the delegate that the Expression<> wraps, which would
silently turn a tree into a delegate. Discards are unaffected, since only a
declaration ever unwraps - a discard offers no target type, and function
types are not used in assignments to discards.
Assisted-by: Claude:claude-opus-5[1m]:Claude Code
A delegate construction site can drop the explicit 'new DelegateType(...)'
only when the natural type C# assigns to the emitted method group is
exactly the delegate type the IL constructs; otherwise 'var' (or a
Delegate/object local's initializer) would re-infer a different type or
none at all. MethodGroupNaturalType re-resolves the emitted form and
decides this, mirroring the version-specific rules: C# 13 walks scopes
one at a time (instance members before each extension scope) and prunes
candidates with mismatched arity, violated constraints or the wrong
static/instance form; C# 10 lets every candidate in every scope take
part. Only System.Action/Func (or anonymous delegate) types qualify -
Roslyn never infers a signature-compatible custom delegate type.
CallBuilder annotates qualifying method groups; DeclareVariables uses
the annotation to emit 'var' when the natural type equals the local's
type, and to drop the construction (but keep the declared type) for
Delegate- and object-typed locals. Sites in any other context keep the
explicit construction. Generic groups retry with spelled type
arguments, since a natural type requires them.
Assisted-by: Claude:claude-fable-5:Claude Code
The resolver comments cited section numbers from the C# 4.0 spec (and a
few from C# 9.0 drafts), which no longer match the published ECMA-334
standard. Renumber them against dotnet/csharpstandard draft-v11; every
reference was checked against the actual section headings. The old
'better conversion from type' subclause (7.5.3.4) no longer exists as
such and its rules live in 12.6.4.5-12.6.4.7, so that comment now says
so instead of pointing at a dead number.
Assisted-by: Claude:claude-fable-5:Claude Code
Dynamic member accesses and invocations carried only the member name
(DynamicMemberResolveResult / DynamicInvocationResolveResult), so
GetSymbol returned null and the editor emitted no reference or hover.
Synthesize a member on the target type - a dynamic field for a member
access, a dynamic-returning method for a member invocation - named after
the accessed member and typed from the callsite delegate: each argument
uses its recorded compile-time type when the binder set one (statically
typed or constant arguments), dynamic otherwise, and the declaring type
comes from the receiver's argument info. Route these through GetSymbol;
TextTokenWriter and the hover renderer already turn an IEntity into a
tooltip. The synthesized members have no metadata token, so they render
a signature on hover but are not navigation targets.
Assisted-by: Claude:claude-fable-5:Claude Code
These have special semantics (number of elements in C# vs. number of bytes in IL), and so pointer arithmetic must go through the special HandlePointerArithmetic() code path --> the normal logic in HandleBinaryNumeric must not ever emit pointer arithmetic.