-
Notifications
You must be signed in to change notification settings - Fork 5.4k
Description
In #121697 I'm enabling trimming on the src/tests tree so that we're testing a configuration that is closer to the AOT default that we recommend externally (full trimming with TrimMode=full instead of TrimMode=partial).
I'm seeing the Validate_ProxyTypeMapping test failing.
Validate_ProxyTypeMapping
System.Collections.Generic.KeyNotFoundException: The given key 'C1' was not present in the dictionary.
at System.Runtime.InteropServices.TypeMapLazyDictionary.AssociatedTypeMapDictionary.get_Item(Type) + 0x30
at TypeMap.Validate_ProxyTypeMapping() + 0x34
at __GeneratedMainWrapper.Main() + 0x12
runtime/src/tests/Interop/TypeMap/TypeMapApp.cs
Lines 141 to 178 in 6a06e66
| [Fact] | |
| public static void Validate_ProxyTypeMapping() | |
| { | |
| Console.WriteLine(nameof(Validate_ProxyTypeMapping)); | |
| IReadOnlyDictionary<Type, Type> map = TypeMapping.GetOrCreateProxyTypeMapping<TypicalUseCase>(); | |
| Assert.Equal(typeof(C1), map[typeof(C1)]); | |
| Assert.Equal(typeof(S1), map[typeof(S1)]); | |
| Assert.Equal(typeof(C1), map[typeof(Guid)]); | |
| Assert.Equal(typeof(S1), map[typeof(string)]); | |
| Assert.Equal(typeof(C1), map[typeof(List<int>)]); | |
| Assert.Equal(typeof(S1), map[typeof(List<>)]); | |
| Assert.Equal(typeof(C1), map[typeof(C1.I1)]); | |
| Assert.Equal(typeof(S1), map[typeof(C1.I2<int>)]); | |
| Assert.Equal(typeof(C1), map[typeof(C2<int>)]); | |
| Assert.Equal(typeof(S1), map[typeof(C2<>)]); | |
| Assert.Equal(typeof(C1), map[typeof(int[])]); | |
| Assert.Equal(typeof(S1), map[typeof(int*)]); | |
| Assert.True(map.TryGetValue(typeof(C1), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(S1), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(Guid), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(string), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(List<int>), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(List<>), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(C1.I1), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(C1.I2<int>), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(C2<int>), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(C2<>), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(int[]), out Type? _)); | |
| Assert.True(map.TryGetValue(typeof(int*), out Type? _)); | |
| // Validate strict type mapping, no implicit conversions. | |
| Assert.False(map.TryGetValue(typeof(object), out Type? _)); | |
| Assert.False(map.TryGetValue(typeof(void*), out Type? _)); | |
| Assert.False(map.TryGetValue(typeof(IntPtr), out Type? _)); | |
| } |
From my read of the TypeMap trimming behavior spec, this looks like a test bug, not a product bug.
runtime/docs/design/features/typemap.md
Lines 205 to 222 in 6a06e66
| An entry in the Proxy Type Map is included when the "source type" is referenced in one of the following ways: | |
| - The argument to the `ldtoken` IL instruction when `DynamicallyAccessedMembersAttribute` is specified with one of the flags that preserves constructors for the storage location. | |
| - Calls to `Type.GetType` with a constant string representing the type name when `DynamicallyAccessedMembersAttribute` is specified with one of the flags that preserves constructors for the storage location. | |
| - The type of a method argument to the `newobj` instruction. | |
| - The generic argument to the `Activator.CreateInstance<T>` method. | |
| - The argument to the `box` instruction. | |
| - The argument to the `newarr` instruction. | |
| - The argument to the `mkrefany` instruction. | |
| - The argument to the `refanyval` instruction. | |
| If the type is an interface type and the user could possibly see a `RuntimeTypeHandle` for the type as part of a casting or virtual method resolution operation (such as with `System.Runtime.InteropServices.IDynamicInterfaceCastable`), then the following cases also apply: | |
| - The argument to the `isinst` IL instruction. | |
| - The argument to the `castclass` IL instruction. | |
| - The owning type of the method argument to `callvirt`, or `ldvirtftn`. | |
| Finally, if the trimming tool determines that it is impossible to retrieve a `System.Type` instance the represents the "source type" at runtime, then the entry may be omitted from the Proxy Type Map as its existence is unobservable. |
The type is only referenced with a typeof (therefore maps to the ldtoken rule), but there's no annotation to force constructor reflectability (so the rest of the rule is not satisfied). The compiler therefore determines that the type cannot be seen as allocated and generates only limited metadata for it (and that includes not making it present in the TypeMap).
If we determine this is indeed a test bug, I can make a PR that switches the typeof to a new X().GetType() (which should satisfy the heuristic rules).
Otherwise we have a native AOT product bug.
Cc @Sergio0694 @AaronRobinsonMSFT @jkoritzinsky @dotnet/illink
Metadata
Metadata
Assignees
Type
Projects
Status