Skip to content

Commit 1045ec8

Browse files
PhysShellclaude
andcommitted
feat(s2-step11): green — positive runtime-incompat predicate in bind (K3)
WRAPPER_RUNTIME_UNSUPPORTED is now returned ONLY when a deterministic positive predicate holds: the wrapper assembly references a core framework assembly (System.Runtime / System.Private.CoreLib / netstandard / mscorlib) at a version STRICTLY NEWER than the one the selected probe runtime provides to the bind compilation (via System.Object's containing assembly). A shape-correct single-candidate wrapper whose callsite merely fails to bind for another reason (argument-conversion failure, method-group ambiguity, source-compilation failure) is CALLSITE_BINDING; a wrong frozen shape stays WRAPPER_BINDING; ambiguous / multiple candidate assemblies stay CALLSITE_BINDING. A clean IMethodSymbol is still required for success and CandidateSymbols remain diagnostic-only. A net9 wrapper still refuses WRAPPER_RUNTIME_UNSUPPORTED, now positively established. Tier B 54/54. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01JxKjqdGEFzq4UzZupw379G
1 parent 964507c commit 1045ec8

1 file changed

Lines changed: 31 additions & 9 deletions

File tree

  • frontend/roslyn/OwnSharp.WeakTargetProbe

frontend/roslyn/OwnSharp.WeakTargetProbe/Program.cs

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -319,11 +319,12 @@ private static string ReadMvid(string dllPath)
319319
}
320320

321321
// Symbol == null: choose the refusal category WITHOUT ever promoting a candidate to the bound
322-
// symbol. With exactly one candidate wrapper slot: a wrong frozen shape is WRAPPER_BINDING; a
323-
// shape that is correct by name yet still fails to bind means the wrapper's metadata/types do
324-
// NOT unify with the fixed probe runtime (e.g. a net9 / .NET-Framework-only wrapper), which is
325-
// WRAPPER_RUNTIME_UNSUPPORTED (never TARGET_RETAINS). Anything else — ambiguous, multiple, or
326-
// otherwise unresolved — is CALLSITE_BINDING.
322+
// symbol. With exactly one candidate wrapper slot: a wrong frozen shape is WRAPPER_BINDING;
323+
// WRAPPER_RUNTIME_UNSUPPORTED is returned ONLY when a POSITIVE predicate establishes the wrapper
324+
// targets a core framework NEWER than the selected probe runtime (metadata/runtime
325+
// incompatibility) — never inferred from "one candidate + correct textual shape". Every other
326+
// unresolved callsite (argument conversion failure, method-group ambiguity, multiple / ambiguous
327+
// assemblies, source-compilation failure) is CALLSITE_BINDING.
327328
private static int RefuseUnbound(string fid, SymbolInfo si, CSharpCompilation comp,
328329
Dictionary<string, References.Slot> slotByPath, string target)
329330
{
@@ -338,14 +339,35 @@ private static int RefuseUnbound(string fid, SymbolInfo si, CSharpCompilation co
338339
{
339340
var path = (comp.GetMetadataReference(asms[0]) as PortableExecutableReference)?.FilePath ?? "";
340341
if (slotByPath.ContainsKey(path))
341-
return TargetBinding.Validate(asms[0], target) is not null
342-
? Refuse("WRAPPER_BINDING", $"{fid}: the wrapper target has the wrong frozen shape")
343-
: Refuse("WRAPPER_RUNTIME_UNSUPPORTED",
344-
$"{fid}: the wrapper target does not unify with the selected probe runtime");
342+
{
343+
if (TargetBinding.Validate(asms[0], target) is not null)
344+
return Refuse("WRAPPER_BINDING", $"{fid}: the wrapper target has the wrong frozen shape");
345+
if (RuntimeIncompatible(comp, asms[0]))
346+
return Refuse("WRAPPER_RUNTIME_UNSUPPORTED",
347+
$"{fid}: the wrapper targets a core framework newer than the selected probe runtime");
348+
}
345349
}
346350
return Refuse("CALLSITE_BINDING", $"{fid}: the invocation does not bind to a single wrapper symbol");
347351
}
348352

353+
// The POSITIVE runtime-incompatibility predicate (K3): the wrapper assembly references a core
354+
// framework assembly at a version STRICTLY NEWER than the one the selected probe runtime provides
355+
// to this compilation. This is a deterministic metadata comparison, not an inference from a
356+
// failed overload — a shape-correct wrapper that merely fails to bind for another reason is NOT
357+
// runtime-incompatible.
358+
private static readonly HashSet<string> CoreFramework = new(StringComparer.OrdinalIgnoreCase)
359+
{ "System.Runtime", "System.Private.CoreLib", "netstandard", "mscorlib" };
360+
361+
private static bool RuntimeIncompatible(CSharpCompilation comp, IAssemblySymbol wrapperAsm)
362+
{
363+
var compCore = comp.GetSpecialType(SpecialType.System_Object).ContainingAssembly.Identity.Version;
364+
foreach (var mod in wrapperAsm.Modules)
365+
foreach (var r in mod.ReferencedAssemblies)
366+
if (CoreFramework.Contains(r.Name) && r.Version > compCore)
367+
return true;
368+
return false;
369+
}
370+
349371
private static int Refuse(string category, string message)
350372
{
351373
Console.Error.WriteLine($"{category}: {message}");

0 commit comments

Comments
 (0)