'this' and 'base' both read the 'this' parameter of the function being
decompiled, but their resolve result did not say so: consumers that key on
ILVariableResolveResult (local-reference output, highlighting, hover) could
not connect the keyword to the variable, and the qualified/unqualified
spellings of the same access carried differently shaped annotations.
The resolver has no ILFunction and thus no variable to put into a
ThisResolveResult, so it stops synthesizing one: LookInCurrentType looks
the name up against the (self-parameterized) current type, which grants
the same protected access, and the annotation of an unqualified field
access is built from the translated target instead. ResolveThisReference
and ResolveBaseReference had no callers left and are removed.
Assisted-by: Claude:claude-fable-5:Claude Code
Walks the inference algorithm of the standard (draft-v11, 12.6.3) and
adds a test per rule that the revived NRefactory suite did not already
exercise: exact inference for ref parameters and its non-applicability
of the base-type walk, explicit lambda parameter types, exact/upper
bound inference through arrays, nullables and variance nesting, the
unique-base-type restriction, value-type elements forcing exact
inference, conflicting exact bounds, and best common type.
Two rules are pinned as ignored tests because the implementation does
not follow the standard yet: a value argument to an 'in' parameter
infers no bound (12.6.3.7 wants a lower-bound inference), and tuple
literals are not inferred elementwise (12.6.3.7/12.6.3.8). Both tests
assert the csc-verified result and should go green when the rules are
implemented.
Nullable unwrapping in exact and upper-bound inferences needs no
dedicated code path in this implementation: T? is represented as the
constructed type Nullable<T>, so the constructed-type case already
produces the elementwise exact inference the standard asks for; the
new tests pin that equivalence. Function-pointer inference rules and
the explicit-return-type inference of 12.6.3.15 remain untested: the
former needs a MetadataModule to construct FunctionPointerType, the
latter is not representable in LambdaResolveResult.
Assisted-by: Claude:claude-fable-5:Claude Code
The direct unit tests for TypeInference were lost when the NRefactory
sources were replaced by the NuGet package (e88120cb4); since then the
class had no dedicated coverage and ConversionTests still pointed to a
test that no longer existed. Ported to the current type system API and
NUnit constraint asserts. The two tests NRefactory ignored on .NET 4.5
now pin the covariant IReadOnlyList<T> results, since the test
compilation uses the 4.5-era reference mscorlib; the common-subtype list
test gains the ReadOnlyCollectionBuilder<T> candidates contributed by
System.Core, which the NRefactory compilation did not reference.
Also includes the seven tests that only exist in upstream
icsharpcode/NRefactory (async lambdas, NullablePick, CoContraPick,
bug 9300, user-defined-conversion bounds). Upstream wrote them against
its source-based resolver harness, which this repo does not have, so
they are reexpressed as direct InferTypeArguments calls using mock
lambdas and helper types declared in the test assembly. Upstream's
InferFromImplicitAsyncLambda was missing its [Test] attribute and never
actually ran; here it does.
Assisted-by: Claude:claude-fable-5:Claude Code
Dumping the implicit/explicit classification of all pairs from a 120-type
universe and diffing it against what csc actually compiles surfaced two
divergences (16 affected pairs), both proven by a compiling-and-running
snippet and captured here as ignored known-bug tests:
1. Nullable conversions derived from tuple conversions are missing:
csc accepts "(long, object)? a = t;" for t of type (int, string) as
well as the lifted and explicit forms, CSharpConversions returns None.
The ECMA spec's 10.6.1 does not list tuple conversions as liftable,
so this is a case of Roslyn exceeding the spec.
2. An explicit user-defined conversion to a nullable target is rejected
when the operator result additionally needs an explicit numeric
conversion: csc accepts "(int?)new ImplicitToLong()" (operator to
long, then explicit long -> int?), CSharpConversions returns None.
The same sweep confirmed the SByte..Decimal TypeCode range in
ImplicitEnumerationConversion is correct: csc accepts zero constants of
any numeric type (0.0, 0f, 0m) for enum conversion and rejects '\0',
matching the implementation exactly.
Assisted-by: Claude:claude-fable-5:Claude Code
Audit the conversion test suites against the conversions chapter of the
draft-v8 C# standard and add tests for every rule that had none:
exhaustive implicit/explicit numeric conversion matrix, tuple/ValueTuple
and nullable-annotation identity, interpolated-string / throw-expression /
tuple-literal conversions, the boxing rule set including variance-based
boxing and unboxing, delegate-to-System.Delegate and IReadOnlyList<T>
reference conversions, type-parameter variance and effective-base-class
casts, generic method groups (inference, explicit type arguments, no
inference from the return type), the anonymous-function compatibility
checks CSharpConversions performs itself (via a LambdaResolveResult test
double), standard-conversion exclusion of user-defined operators, and
operators declared in base classes of the source type.
Two rules are implementation gaps rather than test gaps and get ignored
placeholder tests naming the gap: default literal conversions (10.2.16)
are an explicit TODO in CSharpConversions, and switch expressions
(10.2.18) have no ResolveResult representation. The full
section-by-section map is in
Analyses/ILSpy/2026-07-24_conversions-spec-coverage.md.
Assisted-by: Claude:claude-fable-5:Claude Code
Convert the commented-out block in ExplicitConversionsTest the same way as
the implicit ConversionTest block: type-parameter casts via
DefaultTypeParameter with cross-referencing constraints, user-defined
operators as fixture types in the test assembly, constant sources via
ConstantResolveResult. The rr.Input asserts of the originals were resolver
artifacts and are dropped; UseDefinedExplicitConversion_Lifted instead
exercises the ResolveResult-based ExplicitConversion entry point.
Also extend PreferAmbiguousConversionOverReferenceConversion with the
overload-resolution half of the original NRefactory test (the ambiguous
conversion must not prevent M(BB) from being chosen over M(object)), which
the first revival pass had reduced to the conversion classification alone.
Assisted-by: Claude:claude-fable-5:Claude Code
The block of tests inherited from NRefactory's ConversionsTest was
commented out because it depended on ResolverTestBase (full AST +
CSharpResolver). Rewrite all of them against CSharpConversions directly:
hand-built MethodGroupResolveResults over fixture types compiled into the
test assembly (extension methods injected via the internal
extensionMethods field), DefaultTypeParameter instances with
cross-referencing constraints, and metadata-backed fixture interfaces for
the ExpansiveInheritance termination test.
Two deviations from the NRefactory originals:
MethodGroupConversion_RefArgumentObjectVsDynamic now expects a valid
conversion, because object/dynamic mismatch in a ref parameter is an
identity conversion and current csc accepts the assignment (verified);
PreferUserDefinedConversionOverReferenceConversion resolved an invocation,
so it is recast as an OverloadResolution test over FakeMethod candidates.
Assisted-by: Claude:claude-fable-5:Claude Code
While support for multi-module assemblies isn't fully working yet; it is clear at this point that we want
to treat each module in a multi-module assembly separately for the purposes of the type system.