Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit332cae9

Browse files
committed
Match generic and private methods upon runtime reload
1 parent640e97b commit332cae9

File tree

5 files changed

+160
-63
lines changed

5 files changed

+160
-63
lines changed

‎CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ Instead, `PyIterable` does that.
103103
- Providing an invalid type parameter to a generic type or method produces a helpful Python error
104104
- Empty parameter names (as can be generated from F#) do not cause crashes
105105
- Unicode strings with surrogates were truncated when converting from Python
106+
-`Reload` mode now supports generic methods (previously Python would stop seeing them after reload)
106107

107108
###Removed
108109

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
usingSystem.IO;
2+
usingSystem.Reflection;
3+
4+
usingNUnit.Framework;
5+
6+
usingPython.Runtime;
7+
8+
namespacePython.EmbeddingTest.StateSerialization;
9+
10+
publicclassMethodSerialization
11+
{
12+
[Test]
13+
publicvoidGenericRoundtrip()
14+
{
15+
varmethod=typeof(MethodTestHost).GetMethod(nameof(MethodTestHost.Generic));
16+
varmaybeMethod=newMaybeMethodBase<MethodBase>(method);
17+
varrestored=SerializationRoundtrip(maybeMethod);
18+
Assert.IsTrue(restored.Valid);
19+
Assert.AreEqual(method,restored.Value);
20+
}
21+
22+
staticTSerializationRoundtrip<T>(Titem)
23+
{
24+
usingvarbuf=newMemoryStream();
25+
varformatter=RuntimeData.CreateFormatter();
26+
formatter.Serialize(buf,item);
27+
buf.Position=0;
28+
return(T)formatter.Deserialize(buf);
29+
}
30+
}
31+
32+
publicclassMethodTestHost
33+
{
34+
publicvoidGeneric<T>(Titem,T[]array,refT@ref){}
35+
}

‎src/runtime/Reflection/ParameterHelper.cs

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
usingSystem;
22
usingSystem.Collections.Generic;
3+
usingSystem.Diagnostics;
4+
usingSystem.Linq;
35
usingSystem.Reflection;
46

57
namespacePython.Runtime.Reflection;
68

79
[Serializable]
8-
structParameterHelper:IEquatable<ParameterInfo>
10+
classParameterHelper:IEquatable<ParameterInfo>
911
{
1012
publicreadonlystringTypeName;
1113
publicreadonlyParameterModifierModifier;
14+
publicreadonlyParameterHelper[]?GenericArguments;
1215

13-
publicParameterHelper(ParameterInfotp)
16+
publicParameterHelper(ParameterInfotp):this(tp.ParameterType)
1417
{
15-
TypeName=tp.ParameterType.AssemblyQualifiedName;
1618
Modifier=ParameterModifier.None;
1719

1820
if(tp.IsIn&&tp.ParameterType.IsByRef)
@@ -29,12 +31,55 @@ public ParameterHelper(ParameterInfo tp)
2931
}
3032
}
3133

34+
publicParameterHelper(Typetype)
35+
{
36+
TypeName=type.AssemblyQualifiedName;
37+
if(TypeNameisnull)
38+
{
39+
if(type.IsByRef||type.IsArray)
40+
{
41+
TypeName=type.IsArray?"[]":"&";
42+
GenericArguments=new[]{newParameterHelper(type.GetElementType())};
43+
}
44+
else
45+
{
46+
Debug.Assert(type.ContainsGenericParameters);
47+
TypeName=$"{type.Assembly}::{type.Namespace}/{type.Name}";
48+
GenericArguments=type.GenericTypeArguments.Select(t=>newParameterHelper(t)).ToArray();
49+
}
50+
}
51+
}
52+
53+
publicboolIsSpecialType=>TypeName=="&"||TypeName=="[]";
54+
3255
publicboolEquals(ParameterInfoother)
3356
{
3457
returnthis.Equals(newParameterHelper(other));
3558
}
3659

3760
publicboolMatches(ParameterInfoother)=>this.Equals(other);
61+
62+
publicboolEquals(ParameterHelperother)
63+
{
64+
if(otherisnull)returnfalse;
65+
66+
if(!(other.TypeName==TypeName&&other.Modifier==Modifier))
67+
returnfalse;
68+
69+
if(GenericArguments==other.GenericArguments)returntrue;
70+
71+
if(GenericArgumentsis notnull&&other.GenericArgumentsis notnull)
72+
{
73+
if(GenericArguments.Length!=other.GenericArguments.Length)returnfalse;
74+
for(intarg=0;arg<GenericArguments.Length;arg++)
75+
{
76+
if(!GenericArguments[arg].Equals(other.GenericArguments[arg]))returnfalse;
77+
}
78+
returntrue;
79+
}
80+
81+
returnfalse;
82+
}
3883
}
3984

4085
enumParameterModifier

‎src/runtime/StateSerialization/MaybeMethodBase.cs

Lines changed: 75 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
usingSystem;
2+
usingSystem.Diagnostics;
23
usingSystem.Diagnostics.CodeAnalysis;
34
usingSystem.Reflection;
45
usingSystem.Runtime.Serialization;
@@ -17,8 +18,9 @@ internal struct MaybeMethodBase<T> : ISerializable where T: MethodBase
1718
conststringSerializationType="t";
1819
// Fhe parameters of the MethodBase
1920
conststringSerializationParameters="p";
20-
conststringSerializationIsCtor="c";
2121
conststringSerializationMethodName="n";
22+
conststringSerializationGenericParamCount="G";
23+
conststringSerializationFlags="V";
2224

2325
publicstaticimplicitoperatorMaybeMethodBase<T>(T?ob)=>new(ob);
2426

@@ -62,6 +64,7 @@ public MaybeMethodBase(T? mi)
6264
{
6365
info=mi;
6466
name=mi?.ToString();
67+
Debug.Assert(name!=null||info==null);
6568
deserializationException=null;
6669
}
6770

@@ -82,75 +85,60 @@ internal MaybeMethodBase(SerializationInfo serializationInfo, StreamingContext c
8285
{
8386
thrownewSerializationException($"The underlying type{typeName} can't be found");
8487
}
88+
89+
varflags=(MaybeMethodFlags)serializationInfo.GetInt32(SerializationFlags);
90+
intgenericCount=serializationInfo.GetInt32(SerializationGenericParamCount);
91+
8592
// Get the method's parameters types
8693
varfield_name=serializationInfo.GetString(SerializationMethodName);
8794
varparam=(ParameterHelper[])serializationInfo.GetValue(SerializationParameters,typeof(ParameterHelper[]));
88-
Type[]types=newType[param.Length];
89-
boolhasRefType=false;
90-
for(inti=0;i<param.Length;i++)
91-
{
92-
varparamTypeName=param[i].TypeName;
93-
types[i]=Type.GetType(paramTypeName);
94-
if(types[i]==null)
95-
{
96-
thrownewSerializationException($"The parameter of type{paramTypeName} can't be found");
97-
}
98-
elseif(types[i].IsByRef)
99-
{
100-
hasRefType=true;
101-
}
102-
}
10395

104-
MethodBase?mb=null;
105-
if(serializationInfo.GetBoolean(SerializationIsCtor))
106-
{
107-
// We never want the static constructor.
108-
mb=tp.GetConstructor(ClassManager.BindingFlags&(~BindingFlags.Static),binder:null,types:types,modifiers:null);
109-
}
110-
else
111-
{
112-
mb=tp.GetMethod(field_name,ClassManager.BindingFlags,binder:null,types:types,modifiers:null);
113-
}
114-
115-
if(mb!=null&&hasRefType)
116-
{
117-
mb=CheckRefTypes(mb,param);
118-
}
119-
120-
// Do like in ClassManager.GetClassInfo
121-
if(mb!=null&&ClassManager.ShouldBindMethod(mb))
122-
{
123-
info=mb;
124-
}
96+
info=ScanForMethod(tp,field_name,genericCount,flags,param);
12597
}
12698
catch(Exceptione)
12799
{
128100
deserializationException=e;
129101
}
130102
}
131103

132-
MethodBase?CheckRefTypes(MethodBasemb,ParameterHelper[]ph)
104+
staticMethodBaseScanForMethod(TypedeclaringType,stringname,intgenericCount,MaybeMethodFlagsflags,ParameterHelper[]parameters)
133105
{
134-
// One more step: Changing:
135-
// void MyFn (ref int a)
136-
// to:
137-
// void MyFn (out int a)
138-
// will still find the function correctly as, `in`, `out` and `ref`
139-
// are all represented as a reference type. Query the method we got
140-
// and validate the parameters
141-
if(ph.Length!=0)
142-
{
143-
foreach(variteminEnumerable.Zip(ph,mb.GetParameters(),(orig,current)=>new{orig,current}))
144-
{
145-
if(!item.current.Equals(item.orig))
146-
{
147-
// False positive
148-
returnnull;
149-
}
150-
}
151-
}
106+
varbindingFlags=ClassManager.BindingFlags;
107+
if(flags.HasFlag(MaybeMethodFlags.Constructor))bindingFlags&=~BindingFlags.Static;
152108

153-
returnmb;
109+
varalternatives=declaringType.GetMember(name,
110+
flags.HasFlag(MaybeMethodFlags.Constructor)
111+
?MemberTypes.Constructor
112+
:MemberTypes.Method,
113+
bindingFlags);
114+
115+
if(alternatives.Length==0)
116+
thrownewMissingMethodException($"{declaringType}.{name}");
117+
118+
varvisibility=flags&MaybeMethodFlags.Visibility;
119+
120+
varresult=alternatives.Cast<MethodBase>().FirstOrDefault(m
121+
=>MatchesGenericCount(m,genericCount)&&MatchesSignature(m,parameters)
122+
&&(Visibility(m)==visibility||ClassManager.ShouldBindMethod(m)));
123+
124+
if(resultisnull)
125+
thrownewMissingMethodException($"Matching overload not found for{declaringType}.{name}");
126+
127+
returnresult;
128+
}
129+
130+
staticboolMatchesGenericCount(MethodBasemethod,intgenericCount)
131+
=>method.ContainsGenericParameters
132+
?method.GetGenericArguments().Length==genericCount
133+
:genericCount==0;
134+
135+
staticboolMatchesSignature(MethodBasemethod,ParameterHelper[]parameters)
136+
{
137+
varcurr=method.GetParameters();
138+
if(curr.Length!=parameters.Length)returnfalse;
139+
for(inti=0;i<curr.Length;i++)
140+
if(!parameters[i].Matches(curr[i]))returnfalse;
141+
returntrue;
154142
}
155143

156144
publicvoidGetObjectData(SerializationInfoserializationInfo,StreamingContextcontext)
@@ -159,11 +147,39 @@ public void GetObjectData(SerializationInfo serializationInfo, StreamingContext
159147
if(Valid)
160148
{
161149
serializationInfo.AddValue(SerializationMethodName,info.Name);
162-
serializationInfo.AddValue(SerializationType,info.ReflectedType.AssemblyQualifiedName);
150+
serializationInfo.AddValue(SerializationGenericParamCount,
151+
info.ContainsGenericParameters?info.GetGenericArguments().Length:0);
152+
serializationInfo.AddValue(SerializationFlags,(int)Flags(info));
153+
string?typeName=info.ReflectedType.AssemblyQualifiedName;
154+
Debug.Assert(typeName!=null);
155+
serializationInfo.AddValue(SerializationType,typeName);
163156
ParameterHelper[]parameters=(frompininfo.GetParameters()selectnewParameterHelper(p)).ToArray();
164157
serializationInfo.AddValue(SerializationParameters,parameters,typeof(ParameterHelper[]));
165-
serializationInfo.AddValue(SerializationIsCtor,info.IsConstructor);
166158
}
167159
}
160+
161+
staticMaybeMethodFlagsFlags(MethodBasemethod)
162+
{
163+
varflags=MaybeMethodFlags.Default;
164+
if(method.IsConstructor)flags|=MaybeMethodFlags.Constructor;
165+
if(method.IsStatic)flags|=MaybeMethodFlags.Static;
166+
if(method.IsPublic)flags|=MaybeMethodFlags.Public;
167+
returnflags;
168+
}
169+
170+
staticMaybeMethodFlagsVisibility(MethodBasemethod)
171+
=>Flags(method)&MaybeMethodFlags.Visibility;
172+
}
173+
174+
[Flags]
175+
internalenumMaybeMethodFlags
176+
{
177+
Default=0,
178+
Constructor=1,
179+
Static=2,
180+
181+
// TODO: other kinds of visibility
182+
Public=32,
183+
Visibility=Public,
168184
}
169185
}

‎src/runtime/runtime_data.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ private static void RestoreRuntimeDataObjects(SharedObjectsState storage)
247247
}
248248
}
249249

250-
privatestaticIFormatterCreateFormatter()
250+
internalstaticIFormatterCreateFormatter()
251251
{
252252
returnFormatterType!=null?
253253
(IFormatter)Activator.CreateInstance(FormatterType)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp