Skip to content

Commit 514eae4

Browse files
committed
fix: stop remapping method parameter types in context-bound nested type cloning
Introduce an `IgnoreMethodParameter` mapping flag and apply it across deep method/type mapping and `MemberClonedType`. When adapting compiler-generated nested types to context-bound declaring types, only remap declaring-type-related references and keep method parameter types unchanged. This prevents accidental signature shifts from regular instance types to context types and avoids downstream method resolution errors.
1 parent 98ede6a commit 514eae4

6 files changed

Lines changed: 37 additions & 30 deletions

File tree

src/OTAPI.UnifiedServerProcess/Commons/Structure.cs

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,29 +74,35 @@ public MapOption() {
7474
this.GenericParameterMap = [];
7575
}
7676
public MapOption(
77+
bool ignoreParams,
7778
Dictionary<TypeDefinition, TypeDefinition>? typeReplace = null,
7879
Dictionary<MethodDefinition, MethodDefinition>? methodReplace = null,
7980
Dictionary<IGenericParameterProvider, IGenericParameterProvider>? providers = null,
8081
Dictionary<GenericParameter, TypeReference>? genericParameterMap = null) {
82+
this.IgnoreMethodParameter = ignoreParams;
8183
this.MethodReplaceMap = methodReplace ?? [];
8284
this.TypeReplaceMap = typeReplace ?? [];
8385
this.GenericProvider = providers ?? [];
8486
this.GenericParameterMap = genericParameterMap?.ToDictionary(kv => GenerateKeyForGenericParameter(kv.Key), kv => kv.Value) ?? [];
8587
}
8688
public static MapOption Create(
89+
bool ignoreParams,
8790
(TypeDefinition from, TypeDefinition to)[]? replaceType = null,
8891
(MethodDefinition from, MethodDefinition to)[]? replaceMethod = null,
8992
(IGenericParameterProvider provideFrom, IGenericParameterProvider provideTo)[]? providers = null,
9093
(GenericParameter paramFrom, TypeReference typeTo)[]? genericParameterMap = null) {
9194
return new MapOption(
95+
ignoreParams,
9296
replaceType?.ToDictionary(x => x.from, x => x.to) ?? [],
9397
replaceMethod?.ToDictionary(x => x.from, x => x.to) ?? [],
9498
providers?.ToDictionary(x => x.provideFrom, x => x.provideTo) ?? [],
9599
genericParameterMap?.ToDictionary(x => x.paramFrom, x => x.typeTo) ?? []);
96100
}
97101
public static MapOption CreateGenericProviderMap(
102+
bool ignoreParams = false,
98103
(IGenericParameterProvider provideFrom, IGenericParameterProvider provideTo)[]? providers = null) {
99104
return new MapOption(
105+
ignoreParams,
100106
[],
101107
[],
102108
providers?.ToDictionary(x => x.provideFrom, x => x.provideTo) ?? []);
@@ -105,6 +111,7 @@ public static MapOption CreateGenericProviderMap(
105111
public readonly Dictionary<MethodDefinition, MethodDefinition> MethodReplaceMap;
106112
public readonly Dictionary<IGenericParameterProvider, IGenericParameterProvider> GenericProvider;
107113
public readonly Dictionary<string, TypeReference> GenericParameterMap;
114+
public readonly bool IgnoreMethodParameter;
108115
}
109116
public static GenericInstanceType DeepMapGenericInstanceType(GenericInstanceType instance, MapOption option) {
110117
var pattern = instance.ElementType;
@@ -237,7 +244,12 @@ public static MethodReference DeepMapMethodReference(MethodReference method, Map
237244
declaringType) {
238245
HasThis = method.HasThis
239246
};
240-
mref.Parameters.AddRange(method.Parameters.Select(p => new ParameterDefinition(DeepMapTypeReference(p.ParameterType, option))));
247+
mref.Parameters.AddRange(method.Parameters.Select(p => new ParameterDefinition(
248+
p.Name,
249+
p.Attributes,
250+
option.IgnoreMethodParameter
251+
? p.ParameterType
252+
: DeepMapTypeReference(p.ParameterType, option))));
241253

242254
return mref;
243255
}
@@ -254,7 +266,7 @@ public static MethodDefinition DeepMapMethodDef(MethodDefinition method, MapOpti
254266
if (option.MethodReplaceMap.TryGetValue(method, out var mappedMethod)) {
255267
return mappedMethod;
256268
}
257-
MethodDefinition result = new MethodDefinition(method.Name, method.Attributes, method.Module.TypeSystem.Void);
269+
var result = new MethodDefinition(method.Name, method.Attributes, method.Module.TypeSystem.Void);
258270

259271
result.CustomAttributes.AddRange(method.CustomAttributes.Select(c => c.Clone()));
260272

@@ -278,7 +290,9 @@ public static MethodDefinition DeepMapMethodDef(MethodDefinition method, MapOpti
278290

279291
foreach (var param in method.Parameters) {
280292
var clonedParam = param.Clone();
281-
clonedParam.ParameterType = DeepMapTypeReference(param.ParameterType, option);
293+
if (!option.IgnoreMethodParameter) {
294+
clonedParam.ParameterType = DeepMapTypeReference(param.ParameterType, option);
295+
}
282296
result.Parameters.Add(clonedParam);
283297
}
284298

@@ -424,11 +438,11 @@ Instruction ResolveInstrOff(int off) {
424438

425439
return copied;
426440
}
427-
public static TypeDefinition MemberClonedType(TypeDefinition type, string newName, Dictionary<TypeDefinition, TypeDefinition>? mappedTypes = null, Dictionary<MethodDefinition, MethodDefinition>? mappedMethods = null) {
441+
public static TypeDefinition MemberClonedType(TypeDefinition type, string newName, bool ignoreMethodParameters, Dictionary<TypeDefinition, TypeDefinition>? mappedTypes = null, Dictionary<MethodDefinition, MethodDefinition>? mappedMethods = null) {
428442
mappedTypes ??= [];
429443
mappedMethods ??= [];
430444
Dictionary<TypeDefinition, TypeDefinition> inputTypes = mappedTypes.ToDictionary();
431-
MapOption mapCondition = new MonoModCommon.Structure.MapOption(mappedTypes, mappedMethods, [], []);
445+
var mapCondition = new MapOption(ignoreMethodParameters, mappedTypes, mappedMethods, [], []);
432446

433447
static TypeDefinition ClonedType(TypeDefinition type, string newName, Dictionary<TypeDefinition, TypeDefinition> mappedTypes) {
434448

@@ -456,7 +470,7 @@ static TypeDefinition ClonedType(TypeDefinition type, string newName, Dictionary
456470
return copied;
457471
}
458472
static void ClonedMember(TypeDefinition from,
459-
MonoModCommon.Structure.MapOption mapContext) {
473+
MapOption mapContext) {
460474
var copied = mapContext.TypeReplaceMap[from];
461475

462476
foreach (var interfaceImpl in from.Interfaces) {
@@ -548,7 +562,7 @@ public static MethodReference CreateInstantiatedMethod(MethodReference impl) {
548562
return impl;
549563
}
550564

551-
MapOption option = new MapOption(genericParameterMap: map);
565+
MapOption option = new MapOption(false, genericParameterMap: map);
552566
return DeepMapMethodReference(patten, option);
553567
}
554568
/// <summary>
@@ -575,7 +589,7 @@ public static MethodReference CreateInstantiatedMethod(MethodDefinition methodDe
575589
return methodDef;
576590
}
577591

578-
MapOption option = new MapOption(genericParameterMap: map);
592+
var option = new MapOption(false, genericParameterMap: map);
579593
return DeepMapMethodReference(methodDef, option);
580594
}
581595
}

src/OTAPI.UnifiedServerProcess/Core/Patching/DataModels/ClosureData.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public void Apply(TypeDefinition declaringType, MethodDefinition containingMetho
5151
foreach (ClosureCaptureData capture in Captures) {
5252
capture.CaptureField.FieldType = MonoModCommon.Structure.DeepMapTypeReference(
5353
capture.CaptureField.FieldType,
54-
MonoModCommon.Structure.MapOption.Create(providers: [(declaringType, ClosureType)]));
54+
MonoModCommon.Structure.MapOption.Create(true, providers: [(declaringType, ClosureType)]));
5555
ClosureType.Fields.Add(capture.CaptureField);
5656
}
5757
}
@@ -175,7 +175,7 @@ private static void CreateClosureParam(PatcherArguments arguments, TypeDefinitio
175175
foreach (ClosureCaptureData capture in captures) {
176176
capture.CaptureField.FieldType = MonoModCommon.Structure.DeepMapTypeReference(
177177
capture.CaptureField.FieldType,
178-
MonoModCommon.Structure.MapOption.Create(providers: [(declaringType, closureTypeDef)]));
178+
MonoModCommon.Structure.MapOption.Create(true, providers: [(declaringType, closureTypeDef)]));
179179
closureTypeDef.Fields.Add(capture.CaptureField);
180180
}
181181
}

src/OTAPI.UnifiedServerProcess/Core/Patching/GeneralPatching/Arguments/DelegatePlaceholderProcessor.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -503,7 +503,7 @@ public static DelegateSignature Capture(TypeReference delegateType) {
503503
for (int i = 0; i < git.GenericArguments.Count; i++) {
504504
map.Add(git.ElementType.GenericParameters[i], git.GenericArguments[i]);
505505
}
506-
option = new MonoModCommon.Structure.MapOption(genericParameterMap: map);
506+
option = new MonoModCommon.Structure.MapOption(false, genericParameterMap: map);
507507
}
508508

509509
TypeReference ret = MonoModCommon.Structure.DeepMapTypeReference(invoke.ReturnType, option);

src/OTAPI.UnifiedServerProcess/Core/Patching/GeneralPatching/DelegateWithCtxParamPatcher.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,7 @@ public override void Patch(PatcherArguments arguments) {
5252
continue;
5353
}
5454

55-
var originalId = targetRef.GetIdentifier(
56-
withDeclaring: false,
57-
typeNameMap: arguments.OriginalToContextType.ToDictionary(kv => kv.Value.ContextTypeDef.FullName, kv => kv.Key));
55+
var originalId = targetRef.GetIdentifier(withDeclaring: false);
5856

5957
targetRef.Parameters.Insert(0, new ParameterDefinition(Constants.RootContextParamName, ParameterAttributes.None, arguments.RootContextDef));
6058
targetDef = targetRef.TryResolve();

src/OTAPI.UnifiedServerProcess/Core/Patching/GeneralPatching/EnumeratorCtxAdaptPatcher.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,9 @@ void ProcessMethod(PatcherArguments arguments,
9292
}
9393

9494
if (caller.DeclaringType.FullName != enumeratorDef.DeclaringType.FullName) {
95-
var option = new MonoModCommon.Structure.MapOption(typeReplace: new() { { enumeratorDef.DeclaringType, caller.DeclaringType } });
95+
var option = new MonoModCommon.Structure.MapOption(true, typeReplace: new() { { enumeratorDef.DeclaringType, caller.DeclaringType } });
9696
TypeDefinition oldEnumeratorDef = enumeratorDef;
97-
enumeratorDef = MonoModCommon.Structure.MemberClonedType(enumeratorDef, enumeratorDef.Name, option.TypeReplaceMap);
97+
enumeratorDef = MonoModCommon.Structure.MemberClonedType(enumeratorDef, enumeratorDef.Name, option.IgnoreMethodParameter, option.TypeReplaceMap);
9898

9999
static IEnumerable<(TypeDefinition otype, TypeDefinition ntype)> GetTypeReplacePairs(TypeDefinition oldTypeDef, TypeDefinition newTypeDef) {
100100
yield return (oldTypeDef, newTypeDef);
@@ -264,7 +264,7 @@ private void ProcessEnumeratorMethod(
264264
private void HandleMethodCall(Instruction methodCallInstruction, MethodDefinition enumeratorMethod, PatcherArguments arguments, ContextBoundMethodMap mappedMethods, FieldDefinition captureContextField, FieldReference captureContextFieldRef) {
265265
var calleeRef = (MethodReference)methodCallInstruction.Operand;
266266

267-
var option = MonoModCommon.Structure.MapOption.Create(providers: [(enumeratorMethod.DeclaringType.DeclaringType, enumeratorMethod.DeclaringType)]);
267+
var option = MonoModCommon.Structure.MapOption.Create(true, providers: [(enumeratorMethod.DeclaringType.DeclaringType, enumeratorMethod.DeclaringType)]);
268268
calleeRef = MonoModCommon.Structure.DeepMapMethodReference(calleeRef, option);
269269
if (!this.AdjustMethodReferences(arguments, mappedMethods, ref calleeRef, out MethodDefinition? contextBoundMethodDef, out MethodReference? vanillaCallee, out ContextTypeData? contextProvider)) {
270270
return;

src/OTAPI.UnifiedServerProcess/Core/Patching/GeneralPatching/InvocationCtxAdaptPatcher.cs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,10 @@ x is Instruction {
293293
var typeMap = new Dictionary<TypeDefinition, TypeDefinition>() {
294294
{ closureType.DeclaringType, containingType }
295295
};
296-
var option = new MonoModCommon.Structure.MapOption(typeMap);
296+
var option = new MonoModCommon.Structure.MapOption(true, typeMap);
297297

298298
TypeDefinition oldClosureType = closureType;
299-
closureType = MonoModCommon.Structure.MemberClonedType(closureType, closureType.Name, typeMap);
299+
closureType = MonoModCommon.Structure.MemberClonedType(closureType, closureType.Name, option.IgnoreMethodParameter, typeMap);
300300

301301
static IEnumerable<(TypeDefinition otype, TypeDefinition ntype)> GetTypeReplacePairs(TypeDefinition oldTypeDef, TypeDefinition newTypeDef) {
302302
yield return (oldTypeDef, newTypeDef);
@@ -313,12 +313,7 @@ x is Instruction {
313313
continue;
314314
}
315315
MethodDefinition omethod = otype.Methods.Single(
316-
m =>
317-
m.GetIdentifier(withDeclaring: false)
318-
==
319-
method.GetIdentifier(
320-
withDeclaring: false,
321-
typeNameMap: arguments.OriginalToContextType.ToDictionary(kv => kv.Value.ContextTypeDef.FullName, kv => kv.Key)));
316+
m => m.GetIdentifier(withDeclaring: false) == method.GetIdentifier(withDeclaring: false));
322317
mappedMethods.contextBoundMethods.Add(method.GetIdentifier(), method);
323318
mappedMethods.originalToContextBound.Add(omethod.GetIdentifier(), method);
324319
}
@@ -343,7 +338,7 @@ x is Instruction {
343338

344339
((MethodReference)oldCreateClosure.Operand).DeclaringType = closureVariable.VariableType;
345340

346-
option = new(typeReplace: new() { { oldClosureType, closureType } });
341+
option = new(true, typeReplace: new() { { oldClosureType, closureType } });
347342

348343
foreach (Instruction? inst in userMethod.Body.Instructions) {
349344
if (inst.Operand is TypeReference typeRef) {
@@ -546,7 +541,7 @@ x is Instruction {
546541
Collection<Instruction> generatedMethodBody = generatedMethod.Body.Instructions;
547542

548543
FieldDefinition closureField = closureObjData.Captures.First().CaptureField;
549-
var mapOption = MonoModCommon.Structure.MapOption.Create(providers: [(closureObjData.ClosureType.DeclaringType, closureObjData.ClosureType)]);
544+
var mapOption = MonoModCommon.Structure.MapOption.Create(true, providers: [(closureObjData.ClosureType.DeclaringType, closureObjData.ClosureType)]);
550545
TypeReference fieldType = MonoModCommon.Structure.DeepMapTypeReference(closureField.FieldType, mapOption);
551546
TypeReference declaringTypeRef = MonoModCommon.Structure.DeepMapTypeReference(closureObjData.Closure.VariableType, mapOption);
552547
var fieldRef = new FieldReference(closureField.Name, fieldType, declaringTypeRef);
@@ -899,7 +894,7 @@ x is Instruction {
899894
FieldDefinition thisField = closureObjData.Captures[1].CaptureField;
900895

901896

902-
var mapOption = MonoModCommon.Structure.MapOption.Create(providers: [(closureObjData.ClosureType.DeclaringType, closureObjData.ClosureType)]);
897+
var mapOption = MonoModCommon.Structure.MapOption.Create(true, providers: [(closureObjData.ClosureType.DeclaringType, closureObjData.ClosureType)]);
903898
TypeReference declaringTypeRef = MonoModCommon.Structure.DeepMapTypeReference(closureObjData.Closure.VariableType, mapOption);
904899

905900
var contextFieldTypeRef = new FieldReference(contextField.Name, contextField.FieldType, declaringTypeRef);
@@ -1144,7 +1139,7 @@ static bool IsNormal(Instruction checkBegin,
11441139

11451140
MethodDefinition generatedMethod = MonoModCommon.Structure.DeepMapMethodDef(
11461141
compilerGeneratedMethodOrig,
1147-
MonoModCommon.Structure.MapOption.Create([(compilerGeneratedMethodOrig.DeclaringType.Resolve(), closureObjData.ClosureType)]),
1142+
MonoModCommon.Structure.MapOption.Create(true, [(compilerGeneratedMethodOrig.DeclaringType.Resolve(), closureObjData.ClosureType)]),
11481143
true);
11491144
foreach (ParameterDefinition? param in generatedMethod.Parameters) {
11501145
param.HasConstant = false;
@@ -1215,7 +1210,7 @@ static bool IsNormal(Instruction checkBegin,
12151210
void HandleMethodCall(Instruction methodCallInstruction, MethodDefinition caller, PatcherArguments arguments, ContextBoundMethodMap mappedMethods, ClosureData closureObjData, ClosureDataCache cachedClosureObjs, ref bool anyModified) {
12161211
var calleeRef = (MethodReference)methodCallInstruction.Operand;
12171212

1218-
var option = MonoModCommon.Structure.MapOption.Create(providers: [(closureObjData.ClosureType.DeclaringType, closureObjData.ClosureType)]);
1213+
var option = MonoModCommon.Structure.MapOption.Create(true, providers: [(closureObjData.ClosureType.DeclaringType, closureObjData.ClosureType)]);
12191214
calleeRef = MonoModCommon.Structure.DeepMapMethodReference(calleeRef, option);
12201215
if (!this.AdjustMethodReferences(arguments, mappedMethods, ref calleeRef, out MethodDefinition? contextBound, out MethodReference? vanillaCallee, out ContextTypeData? contextProvider)) {
12211216
return;

0 commit comments

Comments
 (0)