From a42ec6d04f98f676a15318c4c15ff2845ee0c124 Mon Sep 17 00:00:00 2001 From: Ropufu Date: Fri, 8 Jul 2022 15:15:39 -0400 Subject: [PATCH 1/3] Moved call to TryLoadGenericMetaTypeNullability The TryLoadGenericMetaTypeNullability method was called with the same member info but varying nullability across the entire nullability hierarchy. Moved it one level up where nullability and member info are aligned. Added a test to cover this issue. Fix #68461 --- .../Reflection/NullabilityInfoContext.cs | 18 +++++++------- .../Reflection/NullabilityInfoContextTests.cs | 24 +++++++++++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs b/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs index 43d2b65fc218e6..57727d1b0dc3e3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Reflection/NullabilityInfoContext.cs @@ -325,7 +325,14 @@ private static NotAnnotatedStatus PopulateAnnotationInfo(IList customAttributes) diff --git a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs index deb55e01d9b675..8284858f6486e6 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs @@ -1089,6 +1089,20 @@ public void TestNestedGenericInheritanceWithMultipleParameters() Assert.Equal(NullabilityState.NotNull, item3Info.ElementType!.ReadState); Assert.Equal(NullabilityState.NotNull, item3Info.ElementType.WriteState); } + + [Fact] + [SkipOnMono("Nullability attributes trimmed on Mono")] + public void TestNullabilityInfoCreationOnPropertiesWithNestedGenericTypeArguments() + { + Type type = typeof(TypeWithPropertiesNestingItsGenericTypeArgument); + + Assert.NotNull(nullabilityContext.Create(type.GetProperty("Shallow1")!)); + Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep1")!)); + Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep2")!)); + Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep3")!)); + Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep4")!)); + Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep5")!)); + } } #pragma warning disable CS0649, CS0067, CS0414 @@ -1348,4 +1362,14 @@ public DerivesFromTupleOfNestedGenerics(List item1, Dictionary + { + public Tuple? Shallow1 { get; set; } + public Tuple>? Deep1 { get; set; } + public Tuple, int>? Deep2 { get; set; } + public Tuple>? Deep3 { get; set; } + public Tuple>? Deep4 { get; set; } + public Tuple>? Deep5 { get; set; } + } } From ae1279ca249c0a966e88cd275f046c8ba4300159 Mon Sep 17 00:00:00 2001 From: Ropufu Date: Mon, 11 Jul 2022 16:44:20 -0400 Subject: [PATCH 2/3] Added nullability state checks. --- .../Reflection/NullabilityInfoContextTests.cs | 59 +++++++++++++++++-- 1 file changed, 53 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs index 8284858f6486e6..8dda42ee139192 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs @@ -1096,12 +1096,59 @@ public void TestNullabilityInfoCreationOnPropertiesWithNestedGenericTypeArgument { Type type = typeof(TypeWithPropertiesNestingItsGenericTypeArgument); - Assert.NotNull(nullabilityContext.Create(type.GetProperty("Shallow1")!)); - Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep1")!)); - Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep2")!)); - Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep3")!)); - Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep4")!)); - Assert.NotNull(nullabilityContext.Create(type.GetProperty("Deep5")!)); + NullabilityInfo shallow1Info = nullabilityContext.Create(type.GetProperty("Shallow1")!); + NullabilityInfo deep1Info = nullabilityContext.Create(type.GetProperty("Deep1")!); + NullabilityInfo deep2Info = nullabilityContext.Create(type.GetProperty("Deep2")!); + NullabilityInfo deep3Info = nullabilityContext.Create(type.GetProperty("Deep3")!); + NullabilityInfo deep4Info = nullabilityContext.Create(type.GetProperty("Deep4")!); + NullabilityInfo deep5Info = nullabilityContext.Create(type.GetProperty("Deep5")!); + + //public Tuple? Shallow1 { get; set; } + NullabilityInfo info = shallow1Info; + Assert.Equal(1, info.GenericTypeArguments.Length); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[0].ReadState); + + //public Tuple>? Deep1 { get; set; } + info = deep1Info; + Assert.Equal(1, info.GenericTypeArguments.Length); + Assert.Equal(1, info.GenericTypeArguments[0].GenericTypeArguments.Length); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[0].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[0].GenericTypeArguments[0].ReadState); + + //public Tuple, int>? Deep2 { get; set; } + info = deep2Info; + Assert.Equal(2, info.GenericTypeArguments.Length); + Assert.Equal(1, info.GenericTypeArguments[0].GenericTypeArguments.Length); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[0].ReadState); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[1].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[0].GenericTypeArguments[0].ReadState); + + //public Tuple>? Deep3 { get; set; } + info = deep3Info; + Assert.Equal(2, info.GenericTypeArguments.Length); + Assert.Equal(1, info.GenericTypeArguments[1].GenericTypeArguments.Length); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[0].ReadState); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[1].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[1].GenericTypeArguments[0].ReadState); + + //public Tuple>? Deep4 { get; set; } + info = deep4Info; + Assert.Equal(3, info.GenericTypeArguments.Length); + Assert.Equal(1, info.GenericTypeArguments[2].GenericTypeArguments.Length); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[0].ReadState); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[1].ReadState); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[2].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[2].GenericTypeArguments[0].ReadState); + + //public Tuple>? Deep5 { get; set; } + info = deep5Info; + Assert.Equal(3, info.GenericTypeArguments.Length); + Assert.Equal(2, info.GenericTypeArguments[2].GenericTypeArguments.Length); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[0].ReadState); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[1].ReadState); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[2].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[2].GenericTypeArguments[0].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[2].GenericTypeArguments[1].ReadState); } } From da9d9d41166195f0bde1b2ca8777a67a116d25d2 Mon Sep 17 00:00:00 2001 From: Buyaa Namnan Date: Mon, 11 Jul 2022 14:18:07 -0700 Subject: [PATCH 3/3] Apply suggestions from code review --- .../Reflection/NullabilityInfoContextTests.cs | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs index 8dda42ee139192..6146d32190cee3 100644 --- a/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs +++ b/src/libraries/System.Runtime/tests/System/Reflection/NullabilityInfoContextTests.cs @@ -1123,32 +1123,32 @@ public void TestNullabilityInfoCreationOnPropertiesWithNestedGenericTypeArgument Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[1].ReadState); Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[0].GenericTypeArguments[0].ReadState); - //public Tuple>? Deep3 { get; set; } + //public Tuple>? Deep3 { get; set; } info = deep3Info; Assert.Equal(2, info.GenericTypeArguments.Length); Assert.Equal(1, info.GenericTypeArguments[1].GenericTypeArguments.Length); - Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[0].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[0].ReadState); Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[1].ReadState); Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[1].GenericTypeArguments[0].ReadState); - //public Tuple>? Deep4 { get; set; } + //public Tuple>? Deep4 { get; set; } info = deep4Info; Assert.Equal(3, info.GenericTypeArguments.Length); Assert.Equal(1, info.GenericTypeArguments[2].GenericTypeArguments.Length); Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[0].ReadState); - Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[1].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[1].ReadState); Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[2].ReadState); Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[2].GenericTypeArguments[0].ReadState); - //public Tuple>? Deep5 { get; set; } + //public Tuple?>? Deep5 { get; set; } info = deep5Info; Assert.Equal(3, info.GenericTypeArguments.Length); Assert.Equal(2, info.GenericTypeArguments[2].GenericTypeArguments.Length); Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[0].ReadState); Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[1].ReadState); - Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[2].ReadState); + Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[2].ReadState); Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[2].GenericTypeArguments[0].ReadState); - Assert.Equal(NullabilityState.Nullable, info.GenericTypeArguments[2].GenericTypeArguments[1].ReadState); + Assert.Equal(NullabilityState.NotNull, info.GenericTypeArguments[2].GenericTypeArguments[1].ReadState); } } @@ -1415,8 +1415,8 @@ public class TypeWithPropertiesNestingItsGenericTypeArgument public Tuple? Shallow1 { get; set; } public Tuple>? Deep1 { get; set; } public Tuple, int>? Deep2 { get; set; } - public Tuple>? Deep3 { get; set; } - public Tuple>? Deep4 { get; set; } - public Tuple>? Deep5 { get; set; } + public Tuple>? Deep3 { get; set; } + public Tuple>? Deep4 { get; set; } + public Tuple?>? Deep5 { get; set; } } }