public bool IsAssignableFrom(Type target, NullabilityTypeKind targetNullability, Type from, NullabilityTypeKind fromNullability) { if (from == null) { throw new ArgumentNullException(nameof(from)); } if (target == null) { throw new ArgumentNullException(nameof(target)); } // A non nullable cannot be assigned from a nullable. if (!targetNullability.IsNullable() && fromNullability.IsNullable()) { return(false); } return(target == from || target.IsAssignableFrom(from) || (AllInterfaces.TryGetValue(target, out var tP) && AllInterfaces.TryGetValue(from, out var fP) && tP.Root == fP.Root)); }
static NullableTypeTree GetNullableTypeTreeWithProfile(Type t, IEnumerator <byte> annotations, NullabilityTypeKind known, INullableTypeTreeBuilder?builder) { if (t.DeclaringType != null && t.DeclaringType.IsGenericType) { throw new ArgumentException($"Type '{t.Name}' is nested in a generic type ({t.DeclaringType.ToCSharpName()}). Only nested types in non generic types are supported.", nameof(t)); } NullableTypeTree[] sub = Array.Empty <NullableTypeTree>(); bool isInside; if (isInside = (known == NullabilityTypeKind.None)) { known = t.GetNullabilityKind(); } if (known.IsNullableValueType()) { // Lift the Nullable<T>. t = Nullable.GetUnderlyingType(t) !; } if (isInside && !known.IsNonGenericValueType()) { // Consume our annotation. if (!annotations.MoveNext()) { throw new InvalidOperationException($"Byte annotations too short."); } var thisOne = annotations.Current; // Annotations only apply to reference types. Only 1 (not null!) is of interest. if (thisOne == 1 && known.IsReferenceType()) { Debug.Assert(known.IsNullable()); known &= ~NullabilityTypeKind.IsNullable; } } Type[]? genArgs = null; if (t.HasElementType) { Debug.Assert(known.IsReferenceType()); sub = new[] { GetNullableTypeTreeWithProfile(t.GetElementType() !, annotations, default, builder) };