未验证 提交 abe0db95 编写于 作者: J Julien Couvreur 提交者: GitHub

Fix nullability check in override/implementation (#49723)

上级 08a2543b
......@@ -750,7 +750,7 @@ private static ImmutableArray<Symbol> PerformCrefOverloadResolution(ArrayBuilder
// CONSIDER: we might want to reuse this method symbol (as long as the MethodKind and Vararg-ness match).
signatureMember = new SignatureOnlyMethodSymbol(
methodKind: candidateMethodKind,
typeParameters: IndexedTypeParameterSymbol.Take(signatureMemberArity),
typeParameters: IndexedTypeParameterSymbol.TakeSymbols(signatureMemberArity),
parameters: parameterSymbols,
// This specific comparer only looks for varargs.
callingConvention: candidateMethodIsVararg ? Microsoft.Cci.CallingConvention.ExtraArguments : Microsoft.Cci.CallingConvention.HasThis,
......
......@@ -743,7 +743,7 @@ private static MethodSymbol SubstituteTypeParameters(MethodSymbol method)
return method;
}
return method.Construct(IndexedTypeParameterSymbol.Take(n).Cast<TypeParameterSymbol, TypeSymbol>());
return method.Construct(IndexedTypeParameterSymbol.Take(n));
}
private bool AreNamedTypesEqual(NamedTypeSymbol type, NamedTypeSymbol other)
......
......@@ -32,5 +32,16 @@ internal enum NullableAnnotation : byte
/// Type is annotated with '?' - string?, T?.
/// </summary>
Annotated,
/// <summary>
/// Used for indexed type parameters and used locally in override/implementation checks.
/// When substituting a type parameter with Ignored annotation into some original type parameter
/// with some other annotation, the result is the annotation from the original symbol.
///
/// T annotated + (T -> U ignored) = U annotated
/// T oblivious + (T -> U ignored) = U oblivious
/// T not-annotated + (T -> U ignored) = U not-annotated
/// </summary>
Ignored,
}
}
......@@ -5,6 +5,7 @@
#nullable disable
using System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
......@@ -25,37 +26,55 @@ internal static class NullableAnnotationExtensions
/// Join nullable annotations from the set of lower bounds for fixing a type parameter.
/// This uses the covariant merging rules. (Annotated wins over Oblivious which wins over NotAnnotated)
/// </summary>
public static NullableAnnotation Join(this NullableAnnotation a, NullableAnnotation b) => (a < b) ? b : a;
public static NullableAnnotation Join(this NullableAnnotation a, NullableAnnotation b)
{
Debug.Assert(a != NullableAnnotation.Ignored);
Debug.Assert(b != NullableAnnotation.Ignored);
return (a < b) ? b : a;
}
/// <summary>
/// Meet two nullable annotations for computing the nullable annotation of a type parameter from upper bounds.
/// This uses the contravariant merging rules. (NotAnnotated wins over Oblivious which wins over Annotated)
/// </summary>
public static NullableAnnotation Meet(this NullableAnnotation a, NullableAnnotation b) => (a < b) ? a : b;
public static NullableAnnotation Meet(this NullableAnnotation a, NullableAnnotation b)
{
Debug.Assert(a != NullableAnnotation.Ignored);
Debug.Assert(b != NullableAnnotation.Ignored);
return (a < b) ? a : b;
}
/// <summary>
/// Return the nullable annotation to use when two annotations are expected to be "compatible", which means
/// they could be the same. These are the "invariant" merging rules. (NotAnnotated wins over Annotated which wins over Oblivious)
/// </summary>
public static NullableAnnotation EnsureCompatible(this NullableAnnotation a, NullableAnnotation b) =>
(a, b) switch
public static NullableAnnotation EnsureCompatible(this NullableAnnotation a, NullableAnnotation b)
{
Debug.Assert(a != NullableAnnotation.Ignored);
Debug.Assert(b != NullableAnnotation.Ignored);
return (a, b) switch
{
(NullableAnnotation.Oblivious, _) => b,
(_, NullableAnnotation.Oblivious) => a,
_ => a < b ? a : b,
};
}
/// <summary>
/// Merges nullability.
/// </summary>
public static NullableAnnotation MergeNullableAnnotation(this NullableAnnotation a, NullableAnnotation b, VarianceKind variance) =>
variance switch
public static NullableAnnotation MergeNullableAnnotation(this NullableAnnotation a, NullableAnnotation b, VarianceKind variance)
{
Debug.Assert(a != NullableAnnotation.Ignored);
Debug.Assert(b != NullableAnnotation.Ignored);
return variance switch
{
VarianceKind.In => a.Meet(b),
VarianceKind.Out => a.Join(b),
VarianceKind.None => a.EnsureCompatible(b),
_ => throw ExceptionUtilities.UnexpectedValue(variance)
};
}
/// <summary>
/// The attribute (metadata) representation of <see cref="NullableAnnotation.NotAnnotated"/>.
......@@ -105,18 +124,25 @@ internal static ImmutableArray<ITypeSymbol> GetPublicSymbols(this ImmutableArray
internal static ImmutableArray<CodeAnalysis.NullableAnnotation> ToPublicAnnotations(this ImmutableArray<TypeWithAnnotations> types) =>
types.SelectAsArray(t => t.ToPublicAnnotation());
internal static CodeAnalysis.NullableAnnotation ToPublicAnnotation(TypeSymbol type, NullableAnnotation annotation) =>
annotation switch
internal static CodeAnalysis.NullableAnnotation ToPublicAnnotation(TypeSymbol type, NullableAnnotation annotation)
{
Debug.Assert(annotation != NullableAnnotation.Ignored);
return annotation switch
{
CSharp.NullableAnnotation.Annotated => CodeAnalysis.NullableAnnotation.Annotated,
CSharp.NullableAnnotation.NotAnnotated => CodeAnalysis.NullableAnnotation.NotAnnotated,
NullableAnnotation.Annotated => CodeAnalysis.NullableAnnotation.Annotated,
NullableAnnotation.NotAnnotated => CodeAnalysis.NullableAnnotation.NotAnnotated,
// A value type may be oblivious or not annotated depending on whether the type reference
// is from source or metadata. (Binding using the #nullable context only when setting the annotation
// to avoid checking IsValueType early.) The annotation is normalized here in the public API.
CSharp.NullableAnnotation.Oblivious when type.IsValueType => CodeAnalysis.NullableAnnotation.NotAnnotated,
CSharp.NullableAnnotation.Oblivious => CodeAnalysis.NullableAnnotation.None,
NullableAnnotation.Oblivious when type.IsValueType => CodeAnalysis.NullableAnnotation.NotAnnotated,
NullableAnnotation.Oblivious => CodeAnalysis.NullableAnnotation.None,
NullableAnnotation.Ignored => CodeAnalysis.NullableAnnotation.None,
_ => throw ExceptionUtilities.UnexpectedValue(annotation)
};
}
internal static CSharp.NullableAnnotation ToInternalAnnotation(this CodeAnalysis.NullableAnnotation annotation) =>
annotation switch
......
......@@ -989,7 +989,7 @@ IEqualityComparer<MethodSymbol> retargetedMethodComparer
retargetedType,
method.MethodKind,
method.CallingConvention,
IndexedTypeParameterSymbol.Take(method.Arity),
IndexedTypeParameterSymbol.TakeSymbols(method.Arity),
targetParamsBuilder.ToImmutableAndFree(),
method.RefKind,
method.IsInitOnly,
......
......@@ -82,7 +82,7 @@ private static void GrowPool(int count)
/// </summary>
/// <param name="count"></param>
/// <returns></returns>
internal static ImmutableArray<TypeParameterSymbol> Take(int count)
internal static ImmutableArray<TypeParameterSymbol> TakeSymbols(int count)
{
if (count > s_parameterPool.Length)
{
......@@ -99,6 +99,23 @@ internal static ImmutableArray<TypeParameterSymbol> Take(int count)
return builder.ToImmutableAndFree();
}
internal static ImmutableArray<TypeWithAnnotations> Take(int count)
{
if (count > s_parameterPool.Length)
{
GrowPool(count);
}
var builder = ArrayBuilder<TypeWithAnnotations>.GetInstance();
for (int i = 0; i < count; i++)
{
builder.Add(TypeWithAnnotations.Create(GetTypeParameter(i), NullableAnnotation.Ignored));
}
return builder.ToImmutableAndFree();
}
public override int Ordinal
{
get { return _index; }
......
......@@ -944,7 +944,7 @@ void checkSingleOverriddenMember(Symbol overridingMember, Symbol overriddenMembe
if (overridingMethod.IsGenericMethod)
{
overriddenMethod = overriddenMethod.Construct(overridingMethod.TypeArgumentsWithAnnotations);
overriddenMethod = overriddenMethod.Construct(TypeMap.TypeParametersAsTypeSymbolsWithIgnoredAnnotations(overridingMethod.TypeParameters));
}
// Check for mismatched byref returns and return type. Ignore custom modifiers, because this diagnostic is based on the C# semantics.
......
......@@ -632,7 +632,7 @@ private static void PartialMethodChecks(SourceOrdinaryMethodSymbol definition, S
{
Debug.Assert(!ReferenceEquals(definition, implementation));
MethodSymbol constructedDefinition = definition.ConstructIfGeneric(implementation.TypeArgumentsWithAnnotations);
MethodSymbol constructedDefinition = definition.ConstructIfGeneric(TypeMap.TypeParametersAsTypeSymbolsWithIgnoredAnnotations(implementation.TypeParameters));
bool returnTypesEqual = constructedDefinition.ReturnTypeWithAnnotations.Equals(implementation.ReturnTypeWithAnnotations, TypeCompareKind.AllIgnoreOptions);
if (!returnTypesEqual
&& !SourceMemberContainerTypeSymbol.IsOrContainsErrorType(implementation.ReturnType)
......
......@@ -20,11 +20,16 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols
/// </summary>
internal sealed class TypeMap : AbstractTypeParameterMap
{
public static readonly System.Func<TypeWithAnnotations, TypeSymbol> AsTypeSymbol = t => t.Type;
public static readonly Func<TypeWithAnnotations, TypeSymbol> AsTypeSymbol = t => t.Type;
internal static ImmutableArray<TypeWithAnnotations> TypeParametersAsTypeSymbolsWithAnnotations(ImmutableArray<TypeParameterSymbol> typeParameters)
{
return typeParameters.SelectAsArray((tp) => TypeWithAnnotations.Create(tp));
return typeParameters.SelectAsArray(static (tp) => TypeWithAnnotations.Create(tp));
}
internal static ImmutableArray<TypeWithAnnotations> TypeParametersAsTypeSymbolsWithIgnoredAnnotations(ImmutableArray<TypeParameterSymbol> typeParameters)
{
return typeParameters.SelectAsArray(static (tp) => TypeWithAnnotations.Create(tp, NullableAnnotation.Ignored));
}
internal static ImmutableArray<TypeSymbol> AsTypeSymbols(ImmutableArray<TypeWithAnnotations> typesOpt)
......
......@@ -1690,10 +1690,12 @@ internal static void CheckNullableReferenceTypeMismatchOnImplementingMember(Type
{
if (arg.isExplicit)
{
// We use ConstructedFrom symbols here and below to not leak methods with Ignored annotations in type arguments
// into diagnostics
diagnostics.Add(topLevel ?
ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnExplicitImplementation :
ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation,
implementingMethod.Locations[0], new FormattedSymbol(implementedMethod, SymbolDisplayFormat.MinimallyQualifiedFormat));
implementingMethod.Locations[0], new FormattedSymbol(implementedMethod.ConstructedFrom, SymbolDisplayFormat.MinimallyQualifiedFormat));
}
else
{
......@@ -1702,7 +1704,7 @@ internal static void CheckNullableReferenceTypeMismatchOnImplementingMember(Type
ErrorCode.WRN_NullabilityMismatchInReturnTypeOnImplicitImplementation,
GetImplicitImplementationDiagnosticLocation(implementedMethod, arg.implementingType, implementingMethod),
new FormattedSymbol(implementingMethod, SymbolDisplayFormat.MinimallyQualifiedFormat),
new FormattedSymbol(implementedMethod, SymbolDisplayFormat.MinimallyQualifiedFormat));
new FormattedSymbol(implementedMethod.ConstructedFrom, SymbolDisplayFormat.MinimallyQualifiedFormat));
}
};
......@@ -1716,7 +1718,7 @@ internal static void CheckNullableReferenceTypeMismatchOnImplementingMember(Type
ErrorCode.WRN_NullabilityMismatchInParameterTypeOnExplicitImplementation,
implementingMethod.Locations[0],
new FormattedSymbol(implementingParameter, SymbolDisplayFormat.ShortFormat),
new FormattedSymbol(implementedMethod, SymbolDisplayFormat.MinimallyQualifiedFormat));
new FormattedSymbol(implementedMethod.ConstructedFrom, SymbolDisplayFormat.MinimallyQualifiedFormat));
}
else
{
......@@ -1726,7 +1728,7 @@ internal static void CheckNullableReferenceTypeMismatchOnImplementingMember(Type
GetImplicitImplementationDiagnosticLocation(implementedMethod, arg.implementingType, implementingMethod),
new FormattedSymbol(implementingParameter, SymbolDisplayFormat.ShortFormat),
new FormattedSymbol(implementingMethod, SymbolDisplayFormat.MinimallyQualifiedFormat),
new FormattedSymbol(implementedMethod, SymbolDisplayFormat.MinimallyQualifiedFormat));
new FormattedSymbol(implementedMethod.ConstructedFrom, SymbolDisplayFormat.MinimallyQualifiedFormat));
}
};
......@@ -1770,7 +1772,7 @@ internal static void CheckNullableReferenceTypeMismatchOnImplementingMember(Type
if (implementedMethod.IsGenericMethod)
{
implementedMethod = implementedMethod.Construct(implementingMethod.TypeArgumentsWithAnnotations);
implementedMethod = implementedMethod.Construct(TypeMap.TypeParametersAsTypeSymbolsWithIgnoredAnnotations(implementingMethod.TypeParameters));
}
SourceMemberContainerTypeSymbol.CheckValidNullableMethodOverride(
......
......@@ -86,6 +86,7 @@ internal static TypeWithAnnotations Create(TypeSymbol typeSymbol, NullableAnnota
return default;
}
Debug.Assert(nullableAnnotation != NullableAnnotation.Ignored || typeSymbol.IsTypeParameter());
switch (nullableAnnotation)
{
case NullableAnnotation.Oblivious:
......@@ -161,11 +162,6 @@ internal bool CanBeAssignedNull
}
}
private static bool IsIndexedTypeParameter(TypeSymbol typeSymbol)
{
return typeSymbol is IndexedTypeParameterSymbol;
}
private static TypeWithAnnotations CreateNonLazyType(TypeSymbol typeSymbol, NullableAnnotation nullableAnnotation, ImmutableArray<CustomModifier> customModifiers)
{
return new TypeWithAnnotations(typeSymbol, nullableAnnotation, Extensions.Create(customModifiers));
......@@ -429,6 +425,9 @@ public bool IsAtLeastAsVisibleAs(Symbol sym, ref HashSet<DiagnosticInfo> useSite
internal TypeWithAnnotations SubstituteTypeCore(AbstractTypeMap typeMap)
{
// Ignored may only appear on a replacement type and will not survive the substitution (ie. the original annotation wins over Ignored)
Debug.Assert(NullableAnnotation != NullableAnnotation.Ignored);
var newCustomModifiers = typeMap.SubstituteCustomModifiers(this.CustomModifiers);
TypeSymbol typeSymbol = this.Type;
var newTypeWithModifiers = typeMap.SubstituteType(typeSymbol);
......@@ -437,6 +436,7 @@ internal TypeWithAnnotations SubstituteTypeCore(AbstractTypeMap typeMap)
{
Debug.Assert(newTypeWithModifiers.NullableAnnotation.IsOblivious() || (typeSymbol.IsNullableType() && newTypeWithModifiers.NullableAnnotation.IsAnnotated()));
Debug.Assert(newTypeWithModifiers.CustomModifiers.IsEmpty);
Debug.Assert(NullableAnnotation != NullableAnnotation.Ignored);
if (typeSymbol.Equals(newTypeWithModifiers.Type, TypeCompareKind.ConsiderEverything) &&
newCustomModifiers == CustomModifiers)
......@@ -457,7 +457,7 @@ internal TypeWithAnnotations SubstituteTypeCore(AbstractTypeMap typeMap)
{
return this; // substitution had no effect on the type or modifiers
}
else if (Is((TypeParameterSymbol)typeSymbol))
else if (Is((TypeParameterSymbol)typeSymbol) && newTypeWithModifiers.NullableAnnotation != NullableAnnotation.Ignored)
{
return newTypeWithModifiers;
}
......@@ -468,14 +468,13 @@ internal TypeWithAnnotations SubstituteTypeCore(AbstractTypeMap typeMap)
}
NullableAnnotation newAnnotation;
Debug.Assert(!IsIndexedTypeParameter(newTypeWithModifiers.Type) || newTypeWithModifiers.NullableAnnotation.IsOblivious());
Debug.Assert(newTypeWithModifiers.Type is not IndexedTypeParameterSymbol || newTypeWithModifiers.NullableAnnotation == NullableAnnotation.Ignored);
if (NullableAnnotation.IsAnnotated() || newTypeWithModifiers.NullableAnnotation.IsAnnotated())
{
newAnnotation = NullableAnnotation.Annotated;
}
else if (IsIndexedTypeParameter(newTypeWithModifiers.Type))
else if (newTypeWithModifiers.NullableAnnotation == NullableAnnotation.Ignored)
{
newAnnotation = NullableAnnotation;
}
......
......@@ -13235,9 +13235,9 @@ class B : IA
var compilation = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue());
compilation.VerifyDiagnostics(
// (23,17): warning CS8613: Nullability of reference types in return type of 'S?[] B.M2<S>()' doesn't match implicitly implemented member 'S[] IA.M2<S>()'.
// (23,17): warning CS8613: Nullability of reference types in return type of 'S?[] B.M2<S>()' doesn't match implicitly implemented member 'T[] IA.M2<T>()'.
// public S?[] M2<S>() where S : class
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnImplicitImplementation, "M2").WithArguments("S?[] B.M2<S>()", "S[] IA.M2<S>()").WithLocation(23, 17),
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnImplicitImplementation, "M2").WithArguments("S?[] B.M2<S>()", "T[] IA.M2<T>()").WithLocation(23, 17),
// (18,22): warning CS8613: Nullability of reference types in return type of 'string?[] B.M1()' doesn't match implicitly implemented member 'string[] IA.M1()'.
// public string?[] M1()
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnImplicitImplementation, "M1").WithArguments("string?[] B.M1()", "string[] IA.M1()").WithLocation(18, 22)
......@@ -13433,22 +13433,22 @@ class B : IA
";
var compilation = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue());
compilation.VerifyDiagnostics(
// (17,6): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
// (17,6): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
// S?[] IA.M2<S>() where S : class
Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(17, 6),
// (17,13): warning CS8616: Nullability of reference types in return type doesn't match implemented member 'S[] IA.M2<S>()'.
// (17,13): warning CS8616: Nullability of reference types in return type doesn't match implemented member 'T[] IA.M2<T>()'.
// S?[] IA.M2<S>() where S : class
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation, "M2").WithArguments("S[] IA.M2<S>()").WithLocation(17, 13),
// (11,11): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation, "M2").WithArguments("T[] IA.M2<T>()").WithLocation(17, 13),
// (11,11): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
// string?[] IA.M1()
Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(11, 11),
// (11,18): warning CS8616: Nullability of reference types in return type doesn't match implemented member 'string[] IA.M1()'.
// string?[] IA.M1()
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation, "M1").WithArguments("string[] IA.M1()").WithLocation(11, 18),
// (13,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
// (13,26): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
// return new string?[] {};
Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(13, 26),
// (19,21): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' context.
// (19,21): warning CS8632: The annotation for nullable reference types should only be used in code within a '#nullable' annotations context.
// return new S?[] {};
Diagnostic(ErrorCode.WRN_MissingNonNullTypesContextForAnnotation, "?").WithLocation(19, 21)
);
......@@ -13519,9 +13519,9 @@ void IA.M2<S>(S[] x)
// (12,13): warning CS8617: Nullability of reference types in type of parameter 'x' doesn't match implemented member 'void IA.M1(string?[] x)'.
// void IA.M1(string[] x) => throw null!;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnExplicitImplementation, "M1").WithArguments("x", "void IA.M1(string?[] x)").WithLocation(12, 13),
// (13,13): warning CS8617: Nullability of reference types in type of parameter 'x' doesn't match implemented member 'void IA.M2<S>(S?[] x)'.
// (13,13): warning CS8617: Nullability of reference types in type of parameter 'x' doesn't match implemented member 'void IA.M2<T>(T?[] x)'.
// void IA.M2<S>(S[] x)
Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnExplicitImplementation, "M2").WithArguments("x", "void IA.M2<S>(S?[] x)").WithLocation(13, 13)
Diagnostic(ErrorCode.WRN_NullabilityMismatchInParameterTypeOnExplicitImplementation, "M2").WithArguments("x", "void IA.M2<T>(T?[] x)").WithLocation(13, 13)
);
}
......@@ -17679,9 +17679,9 @@ class B : IA
var compilation = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue());
compilation.VerifyDiagnostics(
// (23,13): warning CS8616: Nullability of reference types in return type doesn't match implemented member 'S[] IA.M2<S>()'.
// (23,13): warning CS8616: Nullability of reference types in return type doesn't match implemented member 'T[] IA.M2<T>()'.
// S?[] IA.M2<S>() where S : class
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation, "M2").WithArguments("S[] IA.M2<S>()").WithLocation(23, 13),
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation, "M2").WithArguments("T[] IA.M2<T>()").WithLocation(23, 13),
// (18,18): warning CS8616: Nullability of reference types in return type doesn't match implemented member 'string[] IA.M1()'.
// string?[] IA.M1()
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnExplicitImplementation, "M1").WithArguments("string[] IA.M1()").WithLocation(18, 18)
......@@ -37280,8 +37280,6 @@ public class Derived : Base
}
";
var comp = CreateNullableCompilation(new[] { NotNullWhenAttributeDefinition, source });
// Note: we're missing warnings on F1 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
comp.VerifyDiagnostics(
// (12,26): warning CS8765: Type of parameter 't2' doesn't match overridden member because of nullability attributes.
// public override bool F1<T>(T t1, out T t2, ref T t3, in T t4) => throw null!; // t2, t3
......@@ -37366,8 +37364,6 @@ public class Derived : Base
public override void F4<T>(T t1, out T t2, ref T t3, in T t4) where T : struct => throw null!; // t1, t4
}
";
// Note: we're missing warnings on F1 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
var comp = CreateCompilation(new[] { NotNullAttributeDefinition, source });
comp.VerifyDiagnostics(
// (13,26): warning CS8765: Type of parameter 't1' doesn't match overridden member because of nullability attributes.
......@@ -38396,14 +38392,18 @@ public class Derived : Base
public override void F5<T>([MaybeNull]T? t1, [MaybeNull] out T? t2, [MaybeNull] ref T? t3, [MaybeNull] in T? t4) where T : struct => throw null!;
}
";
// Note: we're missing warnings on F1 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
var comp = CreateNullableCompilation(new[] { MaybeNullAttributeDefinition, source });
comp.VerifyDiagnostics(
// (13,26): error CS8762: Type of parameter 't2' doesn't match overridden member because of nullability attributes.
// (12,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override void F1<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t2").WithLocation(12, 26),
// (12,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override void F1<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t3").WithLocation(12, 26),
// (13,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override void F2<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) where T : class => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t2").WithLocation(13, 26),
// (13,26): error CS8762: Type of parameter 't3' doesn't match overridden member because of nullability attributes.
// (13,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override void F2<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) where T : class => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t3").WithLocation(13, 26)
);
......@@ -38435,13 +38435,17 @@ public class Derived2 : Derived
}
";
var comp = CreateNullableCompilation(new[] { MaybeNullWhenAttributeDefinition, source });
// Note: we're missing warnings on F1 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
comp.VerifyDiagnostics(
// (13,26): warning CS8765: Type of parameter 't2' doesn't match overridden member because of nullability attributes.
// (12,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F1<T>([MaybeNullWhen(true)]T t1, [MaybeNullWhen(true)] out T t2, [MaybeNullWhen(true)] ref T t3, [MaybeNullWhen(true)] in T t4) => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t2").WithLocation(12, 26),
// (12,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F1<T>([MaybeNullWhen(true)]T t1, [MaybeNullWhen(true)] out T t2, [MaybeNullWhen(true)] ref T t3, [MaybeNullWhen(true)] in T t4) => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t3").WithLocation(12, 26),
// (13,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F2<T>([MaybeNullWhen(true)]T t1, [MaybeNullWhen(true)] out T t2, [MaybeNullWhen(true)] ref T t3, [MaybeNullWhen(true)] in T t4) where T : class => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t2").WithLocation(13, 26),
// (13,26): warning CS8765: Type of parameter 't3' doesn't match overridden member because of nullability attributes.
// (13,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F2<T>([MaybeNullWhen(true)]T t1, [MaybeNullWhen(true)] out T t2, [MaybeNullWhen(true)] ref T t3, [MaybeNullWhen(true)] in T t4) where T : class => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t3").WithLocation(13, 26)
);
......@@ -38472,15 +38476,25 @@ public class Derived : Base
}
";
var comp = CreateNullableCompilation(new[] { MaybeNullWhenAttributeDefinition, source });
// Note: we're missing warnings on F1 and F6 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
comp.VerifyDiagnostics(
// (14,26): warning CS8765: Type of parameter 't2' doesn't match overridden member because of nullability attributes.
// (13,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F1<T>([MaybeNullWhen(false)]T t1, [MaybeNullWhen(false)] out T t2, [MaybeNullWhen(false)] ref T t3, [MaybeNullWhen(false)] in T t4) => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t2").WithLocation(13, 26),
// (13,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F1<T>([MaybeNullWhen(false)]T t1, [MaybeNullWhen(false)] out T t2, [MaybeNullWhen(false)] ref T t3, [MaybeNullWhen(false)] in T t4) => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t3").WithLocation(13, 26),
// (14,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F2<T>([MaybeNullWhen(false)]T t1, [MaybeNullWhen(false)] out T t2, [MaybeNullWhen(false)] ref T t3, [MaybeNullWhen(false)] in T t4) where T : class => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t2").WithLocation(14, 26),
// (14,26): warning CS8765: Type of parameter 't3' doesn't match overridden member because of nullability attributes.
// (14,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F2<T>([MaybeNullWhen(false)]T t1, [MaybeNullWhen(false)] out T t2, [MaybeNullWhen(false)] ref T t3, [MaybeNullWhen(false)] in T t4) where T : class => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t3").WithLocation(14, 26)
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t3").WithLocation(14, 26),
// (18,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F6<T>([MaybeNullWhen(false)]T t1, [MaybeNullWhen(false)] out T t2, [MaybeNullWhen(false)] ref T t3, [MaybeNullWhen(false)] in T t4) => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F6").WithArguments("t2").WithLocation(18, 26),
// (18,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F6<T>([MaybeNullWhen(false)]T t1, [MaybeNullWhen(false)] out T t2, [MaybeNullWhen(false)] ref T t3, [MaybeNullWhen(false)] in T t4) => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F6").WithArguments("t3").WithLocation(18, 26)
);
}
......@@ -38531,16 +38545,26 @@ public class Derived : Base
public override bool F6<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) => throw null!;
}
";
// Note: we're missing warnings on F1 and F6 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
var comp = CreateNullableCompilation(new[] { MaybeNullWhenAttributeDefinition, MaybeNullAttributeDefinition, source });
comp.VerifyDiagnostics(
// (14,26): warning CS8765: Type of parameter 't2' doesn't match overridden member because of nullability attributes.
// (13,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F1<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t2").WithLocation(13, 26),
// (13,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F1<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t3").WithLocation(13, 26),
// (14,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F2<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) where T : class => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t2").WithLocation(14, 26),
// (14,26): warning CS8765: Type of parameter 't3' doesn't match overridden member because of nullability attributes.
// (14,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F2<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) where T : class => throw null!; // t2, t3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t3").WithLocation(14, 26)
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t3").WithLocation(14, 26),
// (18,26): warning CS8765: Nullability of type of parameter 't2' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F6<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F6").WithArguments("t2").WithLocation(18, 26),
// (18,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override bool F6<T>([MaybeNull]T t1, [MaybeNull] out T t2, [MaybeNull] ref T t3, [MaybeNull] in T t4) => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F6").WithArguments("t3").WithLocation(18, 26)
);
}
......@@ -38638,8 +38662,6 @@ public class Derived : Base
[Fact]
public void DisallowNull_Parameter_Generic_OnOverrides()
{
// Note: we're missing warnings on F1 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
var source =
@"using System.Diagnostics.CodeAnalysis;
public class Base
......@@ -38661,22 +38683,31 @@ public class Derived : Base
";
var comp = CreateNullableCompilation(new[] { DisallowNullAttributeDefinition, source });
comp.VerifyDiagnostics(
// (14,26): warning CS8765: Type of parameter 't1' doesn't match overridden member because of nullability attributes.
// (12,26): warning CS8765: Nullability of type of parameter 't1' doesn't match overridden member (possibly because of nullability attributes).
// public override void F1<T>([DisallowNull]T t1, [DisallowNull] out T t2, [DisallowNull] ref T t3, [DisallowNull] in T t4) => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t1").WithLocation(12, 26),
// (12,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override void F1<T>([DisallowNull]T t1, [DisallowNull] out T t2, [DisallowNull] ref T t3, [DisallowNull] in T t4) => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t3").WithLocation(12, 26),
// (12,26): warning CS8765: Nullability of type of parameter 't4' doesn't match overridden member (possibly because of nullability attributes).
// public override void F1<T>([DisallowNull]T t1, [DisallowNull] out T t2, [DisallowNull] ref T t3, [DisallowNull] in T t4) => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t4").WithLocation(12, 26),
// (14,26): warning CS8765: Nullability of type of parameter 't1' doesn't match overridden member (possibly because of nullability attributes).
// public override void F3<T>([DisallowNull]T? t1, [DisallowNull] out T? t2, [DisallowNull] ref T? t3, [DisallowNull] in T? t4) where T : class => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F3").WithArguments("t1").WithLocation(14, 26),
// (14,26): warning CS8765: Type of parameter 't3' doesn't match overridden member because of nullability attributes.
// (14,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override void F3<T>([DisallowNull]T? t1, [DisallowNull] out T? t2, [DisallowNull] ref T? t3, [DisallowNull] in T? t4) where T : class => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F3").WithArguments("t3").WithLocation(14, 26),
// (14,26): warning CS8765: Type of parameter 't4' doesn't match overridden member because of nullability attributes.
// (14,26): warning CS8765: Nullability of type of parameter 't4' doesn't match overridden member (possibly because of nullability attributes).
// public override void F3<T>([DisallowNull]T? t1, [DisallowNull] out T? t2, [DisallowNull] ref T? t3, [DisallowNull] in T? t4) where T : class => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F3").WithArguments("t4").WithLocation(14, 26),
// (16,26): warning CS8765: Type of parameter 't1' doesn't match overridden member because of nullability attributes.
// (16,26): warning CS8765: Nullability of type of parameter 't1' doesn't match overridden member (possibly because of nullability attributes).
// public override void F5<T>([DisallowNull]T? t1, [DisallowNull] out T? t2, [DisallowNull] ref T? t3, [DisallowNull] in T? t4) where T : struct => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F5").WithArguments("t1").WithLocation(16, 26),
// (16,26): warning CS8765: Type of parameter 't3' doesn't match overridden member because of nullability attributes.
// (16,26): warning CS8765: Nullability of type of parameter 't3' doesn't match overridden member (possibly because of nullability attributes).
// public override void F5<T>([DisallowNull]T? t1, [DisallowNull] out T? t2, [DisallowNull] ref T? t3, [DisallowNull] in T? t4) where T : struct => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F5").WithArguments("t3").WithLocation(16, 26),
// (16,26): warning CS8765: Type of parameter 't4' doesn't match overridden member because of nullability attributes.
// (16,26): warning CS8765: Nullability of type of parameter 't4' doesn't match overridden member (possibly because of nullability attributes).
// public override void F5<T>([DisallowNull]T? t1, [DisallowNull] out T? t2, [DisallowNull] ref T? t3, [DisallowNull] in T? t4) where T : struct => throw null!; // t1, t3, t4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F5").WithArguments("t4").WithLocation(16, 26)
);
......@@ -43159,22 +43190,23 @@ public class Derived : Base
[return: MaybeNull] public override T F6<T>() => throw null!; // 5
}
";
// Note: we're missing the warning on F6 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
var comp = CreateNullableCompilation(new[] { NotNullAttributeDefinition, MaybeNullAttributeDefinition, source });
comp.VerifyDiagnostics(
// (14,43): warning CS8764: Return type doesn't match overridden member because of nullability attributes.
// (14,43): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T F1<T>() => throw null!; // 1
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F1").WithLocation(14, 43),
// (15,43): warning CS8764: Return type doesn't match overridden member because of nullability attributes.
// (15,43): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T F2<T>() where T : class => throw null!; // 2
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F2").WithLocation(15, 43),
// (16,44): warning CS8764: Return type doesn't match overridden member because of nullability attributes.
// (16,44): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T? F3<T>() where T : class => throw null!; // 3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F3").WithLocation(16, 44),
// (19,44): warning CS8764: Return type doesn't match overridden member because of nullability attributes.
// (19,44): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T? F5<T>() where T : struct => throw null!; // 4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F5").WithLocation(19, 44)
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F5").WithLocation(19, 44),
// (20,43): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T F6<T>() => throw null!; // 5
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F6").WithLocation(20, 43)
);
}
......@@ -43210,22 +43242,23 @@ public class Derived : Base
[return: MaybeNull] public override T F6<T>() => throw null!; // 5
}
";
// Note: we're missing the warning on F6 because the overridden method with substituted T from Derived has an oblivious T
// https://github.com/dotnet/roslyn/issues/41368
var comp2 = CreateNullableCompilation(source2, references: new[] { comp.EmitToImageReference() });
comp2.VerifyDiagnostics(
// (4,43): warning CS8764: Return type doesn't match overridden member because of nullability attributes.
// (4,43): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T F1<T>() => throw null!; // 1
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F1").WithLocation(4, 43),
// (5,43): warning CS8764: Return type doesn't match overridden member because of nullability attributes.
// (5,43): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T F2<T>() where T : class => throw null!; // 2
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F2").WithLocation(5, 43),
// (6,44): warning CS8764: Return type doesn't match overridden member because of nullability attributes.
// (6,44): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T? F3<T>() where T : class => throw null!; // 3
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F3").WithLocation(6, 44),
// (9,44): warning CS8764: Return type doesn't match overridden member because of nullability attributes.
// (9,44): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T? F5<T>() where T : struct => throw null!; // 4
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F5").WithLocation(9, 44)
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F5").WithLocation(9, 44),
// (10,43): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// [return: MaybeNull] public override T F6<T>() => throw null!; // 5
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "F6").WithLocation(10, 43)
);
}
......@@ -112747,7 +112780,7 @@ static void F(C<object> x, C<object?>? y)
comp.VerifyTypes();
}
private static readonly NullableAnnotation[] s_AllNullableAnnotations = (NullableAnnotation[])Enum.GetValues(typeof(NullableAnnotation));
private static readonly NullableAnnotation[] s_AllNullableAnnotations = ((NullableAnnotation[])Enum.GetValues(typeof(NullableAnnotation))).Where(n => n != NullableAnnotation.Ignored).ToArray();
private static readonly NullableFlowState[] s_AllNullableFlowStates = (NullableFlowState[])Enum.GetValues(typeof(NullableFlowState));
[Fact]
......@@ -140073,7 +140106,14 @@ class B2 : A2
public override void F6<T>([DisallowNull] T t) { }
}";
comp = CreateCompilation(new[] { sourceB, DisallowNullAttributeDefinition, NotNullAttributeDefinition }, references: new[] { refA });
comp.VerifyDiagnostics();
comp.VerifyDiagnostics(
// (14,26): warning CS8765: Nullability of type of parameter 't' doesn't match overridden member (possibly because of nullability attributes).
// public override void F1<T>([DisallowNull] T t) { }
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F1").WithArguments("t").WithLocation(14, 26),
// (19,26): warning CS8765: Nullability of type of parameter 't' doesn't match overridden member (possibly because of nullability attributes).
// public override void F6<T>([DisallowNull] T t) { }
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F6").WithArguments("t").WithLocation(19, 26)
);
}
[Theory]
......@@ -140401,8 +140441,11 @@ class B : A
public override void F3<T>(out T? t) where T : default => throw null!;
}";
comp = CreateCompilation(sourceB4, references: new[] { refA });
// https://github.com/dotnet/roslyn/issues/49131: Should report warning for F2<T>().
comp.VerifyDiagnostics();
comp.VerifyDiagnostics(
// (5,26): warning CS8765: Nullability of type of parameter 't' doesn't match overridden member (possibly because of nullability attributes).
// public override void F2<T>(out T? t) where T : default => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "F2").WithArguments("t").WithLocation(5, 26)
);
}
[Theory]
......@@ -142078,5 +142121,665 @@ static T GetValue2<T>(Collection c, object key)
// return s2; // 4
Diagnostic(ErrorCode.WRN_NullReferenceReturn, "s2").WithLocation(47, 20));
}
[Theory, WorkItem(41368, "https://github.com/dotnet/roslyn/issues/41368")]
[CombinatorialData]
public void TypeSubstitution(bool useCompilationReference)
{
var sourceA = @"
#nullable enable
public class C
{
public static TQ? FTQ<TQ>(TQ? t) => throw null!; // T-question
public static T FT<T>(T t) => throw null!; // plain-T
public static TC FTC<TC>(TC t) where TC : class => throw null!; // T-class
#nullable disable
public static TO FTO<TO>(TO t) => throw null!; // T-oblivious
public static TCO FTCO<TCO>(TCO t) where TCO : class => throw null!; // T-class-oblivious
}";
var comp = CreateCompilation(sourceA);
comp.VerifyDiagnostics();
var refA = AsReference(comp, useCompilationReference);
var sourceB2 = @"
#nullable enable
class CTQ<TQ>
{
void M()
{
var x0 = C.FTQ<TQ?>(default);
x0.ToString(); // 1
var x1 = C.FT<TQ?>(default);
x1.ToString(); // 2
C.FTC<TQ?>(default).ToString(); // illegal
var x2 = C.FTO<TQ?>(default);
x2.ToString(); // 3
var x3 = C.FTCO<TQ?>(default); // illegal
x3.ToString();
}
}
class CT<T>
{
void M()
{
var x0 = C.FTQ<T>(default);
x0.ToString(); // 4
var x1 = C.FT<T>(default); // 5
x1.ToString(); // 6
C.FTC<T>(default).ToString(); // illegal
var x2 = C.FTO<T>(default); // 7
x2.ToString(); // 8
C.FTCO<T>(default).ToString(); // illegal
}
}
class CTC<TC> where TC : class
{
void M()
{
var x0 = C.FTQ<TC>(default);
x0.ToString(); // 9
var x1 = C.FT<TC>(default); // 10
x1.ToString();
var x2 = C.FTC<TC>(default); // 11
x2.ToString();
var x3 = C.FTO<TC>(default); // 12
x3.ToString();
var x4 = C.FTCO<TC>(default); // 13
x4.ToString();
}
}
class CTO<TO>
{
void M()
{
#nullable disable
C.FTQ<TO>
#nullable enable
(default).ToString();
#nullable disable
C.FT<TO>
#nullable enable
(default).ToString();
#nullable disable
C.FTC<TO> // illegal
#nullable enable
(default).ToString();
#nullable disable
C.FTO<TO>
#nullable enable
(default).ToString();
#nullable disable
C.FTCO<TO> // illegal
#nullable enable
(default).ToString();
}
}
class CTCO<TCO> where TCO : class
{
void M()
{
var x0 =
#nullable disable
C.FTQ<TCO>
#nullable enable
(default);
x0.ToString(); // 14
#nullable disable
C.FT<TCO>
#nullable enable
(default).ToString();
var x1 =
#nullable disable
C.FTC<TCO>
#nullable enable
(default); // 15
x1.ToString();
#nullable disable
C.FTO<TCO>
#nullable enable
(default).ToString();
#nullable disable
C.FTCO<TCO>
#nullable enable
(default).ToString();
}
}
";
comp = CreateCompilation(new[] { sourceB2 }, references: new[] { refA });
comp.VerifyDiagnostics(
// (8,9): warning CS8602: Dereference of a possibly null reference.
// x0.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x0").WithLocation(8, 9),
// (11,9): warning CS8602: Dereference of a possibly null reference.
// x1.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(11, 9),
// (13,11): error CS0452: The type 'TQ' must be a reference type in order to use it as parameter 'TC' in the generic type or method 'C.FTC<TC>(TC)'
// C.FTC<TQ?>(default).ToString(); // illegal
Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "FTC<TQ?>").WithArguments("C.FTC<TC>(TC)", "TC", "TQ").WithLocation(13, 11),
// (16,9): warning CS8602: Dereference of a possibly null reference.
// x2.ToString(); // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(16, 9),
// (18,20): error CS0452: The type 'TQ' must be a reference type in order to use it as parameter 'TCO' in the generic type or method 'C.FTCO<TCO>(TCO)'
// var x3 = C.FTCO<TQ?>(default); // illegal
Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "FTCO<TQ?>").WithArguments("C.FTCO<TCO>(TCO)", "TCO", "TQ").WithLocation(18, 20),
// (28,9): warning CS8602: Dereference of a possibly null reference.
// x0.ToString(); // 4
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x0").WithLocation(28, 9),
// (30,26): warning CS8604: Possible null reference argument for parameter 't' in 'T C.FT<T>(T t)'.
// var x1 = C.FT<T>(default); // 5
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "default").WithArguments("t", "T C.FT<T>(T t)").WithLocation(30, 26),
// (31,9): warning CS8602: Dereference of a possibly null reference.
// x1.ToString(); // 6
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x1").WithLocation(31, 9),
// (33,11): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'TC' in the generic type or method 'C.FTC<TC>(TC)'
// C.FTC<T>(default).ToString(); // illegal
Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "FTC<T>").WithArguments("C.FTC<TC>(TC)", "TC", "T").WithLocation(33, 11),
// (35,27): warning CS8604: Possible null reference argument for parameter 't' in 'T C.FTO<T>(T t)'.
// var x2 = C.FTO<T>(default); // 7
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "default").WithArguments("t", "T C.FTO<T>(T t)").WithLocation(35, 27),
// (36,9): warning CS8602: Dereference of a possibly null reference.
// x2.ToString(); // 8
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x2").WithLocation(36, 9),
// (38,11): error CS0452: The type 'T' must be a reference type in order to use it as parameter 'TCO' in the generic type or method 'C.FTCO<TCO>(TCO)'
// C.FTCO<T>(default).ToString(); // illegal
Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "FTCO<T>").WithArguments("C.FTCO<TCO>(TCO)", "TCO", "T").WithLocation(38, 11),
// (46,9): warning CS8602: Dereference of a possibly null reference.
// x0.ToString(); // 9
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x0").WithLocation(46, 9),
// (48,27): warning CS8625: Cannot convert null literal to non-nullable reference type.
// var x1 = C.FT<TC>(default); // 10
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(48, 27),
// (51,28): warning CS8625: Cannot convert null literal to non-nullable reference type.
// var x2 = C.FTC<TC>(default); // 11
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(51, 28),
// (54,28): warning CS8625: Cannot convert null literal to non-nullable reference type.
// var x3 = C.FTO<TC>(default); // 12
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(54, 28),
// (57,29): warning CS8625: Cannot convert null literal to non-nullable reference type.
// var x4 = C.FTCO<TC>(default); // 13
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(57, 29),
// (76,11): error CS0452: The type 'TO' must be a reference type in order to use it as parameter 'TC' in the generic type or method 'C.FTC<TC>(TC)'
// C.FTC<TO> // illegal
Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "FTC<TO>").WithArguments("C.FTC<TC>(TC)", "TC", "TO").WithLocation(76, 11),
// (86,11): error CS0452: The type 'TO' must be a reference type in order to use it as parameter 'TCO' in the generic type or method 'C.FTCO<TCO>(TCO)'
// C.FTCO<TO> // illegal
Diagnostic(ErrorCode.ERR_RefConstraintNotSatisfied, "FTCO<TO>").WithArguments("C.FTCO<TCO>(TCO)", "TCO", "TO").WithLocation(86, 11),
// (100,9): warning CS8602: Dereference of a possibly null reference.
// x0.ToString(); // 14
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x0").WithLocation(100, 9),
// (111,14): warning CS8625: Cannot convert null literal to non-nullable reference type.
// (default); // 15
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "default").WithLocation(111, 14)
);
}
[Fact]
public void DefaultParameterValue()
{
var src = @"
#nullable enable
C<string?> one = new();
C<string?> other = new();
_ = one.SequenceEqual(other);
_ = one.SequenceEqual(other, comparer: null);
public interface IIn<in t> { }
static class Extension
{
public static bool SequenceEqual<TDerived, TBase>(this C<TBase> one, C<TDerived> other, IIn<TBase>? comparer = null) where TDerived : TBase
=> throw null!;
}
public class C<T>
{
}
";
var comp = CreateCompilation(src, options: TestOptions.DebugExe);
comp.VerifyDiagnostics();
}
[Fact]
public void IgnoredNullability_CopyTypeModifiers_ImplicitContainingType()
{
var src = @"
#nullable enable
var c = new C<string>();
c.Property.Property2 = null;
public interface I<T>
{
T Property { get; set; }
}
public class C<U> : I<C<U>.Nested>
{
public Nested Property { get; set; } // implicitly means C<U>.Nested
public class Nested
{
public U Property2 { get; set; }
}
}
";
var comp = CreateCompilation(src, options: TestOptions.DebugExe);
comp.VerifyDiagnostics(
// (5,24): warning CS8625: Cannot convert null literal to non-nullable reference type.
// c.Property.Property2 = null;
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 24),
// (13,19): warning CS8618: Non-nullable property 'Property' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
// public Nested Property { get; set; } // implicitly means C<U>.Nested
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Property").WithArguments("property", "Property").WithLocation(13, 19),
// (16,18): warning CS8618: Non-nullable property 'Property2' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
// public U Property2 { get; set; }
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Property2").WithArguments("property", "Property2").WithLocation(16, 18)
);
}
[Fact]
public void IgnoredNullability_CopyTypeModifiers_ExplicitContainingType()
{
var src = @"
#nullable enable
var c = new C<string>();
c.Property.Property2 = null;
public interface I<T>
{
public T Property { get; set; }
}
public class C<U> : I<C<U>.Nested>
{
public C<U>.Nested Property { get; set; }
public class Nested
{
public U Property2 { get; set; }
}
}
";
var comp = CreateCompilation(src, options: TestOptions.DebugExe);
comp.VerifyDiagnostics(
// (5,24): warning CS8625: Cannot convert null literal to non-nullable reference type.
// c.Property.Property2 = null;
Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(5, 24),
// (13,24): warning CS8618: Non-nullable property 'Property' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
// public C<U>.Nested Property { get; set; }
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Property").WithArguments("property", "Property").WithLocation(13, 24),
// (16,18): warning CS8618: Non-nullable property 'Property2' must contain a non-null value when exiting constructor. Consider declaring the property as nullable.
// public U Property2 { get; set; }
Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "Property2").WithArguments("property", "Property2").WithLocation(16, 18)
);
}
[Fact]
public void IgnoredNullability_ConditionalWithThis()
{
var src = @"
#nullable enable
internal class C<T>
{
public C<T> M(bool b)
{
if (b)
return b ? this : new C<T>();
else
return b ? new C<T>() : this;
}
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics();
}
[Fact]
public void IgnoredNullability_ImplicitlyTypedArrayWithThis()
{
var src = @"
#nullable enable
internal class C<T>
{
public C<T>[] M(bool b)
{
if (b)
return new[] { this, new C<T>() };
else
return new[] { new C<T>(), this };
}
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics();
}
[Fact, WorkItem(49722, "https://github.com/dotnet/roslyn/issues/49722")]
public void IgnoredNullability_ImplicitlyTypedArrayWithThis_DifferentNullability()
{
var src = @"
#nullable enable
internal class C<T>
{
public void M(bool b)
{
_ = b ? this : new C<T?>();
}
}
";
var comp = CreateCompilation(src);
// missing warning
comp.VerifyDiagnostics();
}
[Fact]
public void IgnoredNullability_StaticField()
{
var src = @"
#nullable enable
public class C<T>
{
public static int field;
public void M()
{
var x = field;
var y = C<T>.field;
#nullable disable
var z = C<T>.field;
}
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var declarators = tree.GetRoot().DescendantNodes().OfType<EqualsValueClauseSyntax>().ToArray();
Assert.Equal("field", declarators[0].Value.ToString());
var field1 = model.GetSymbolInfo(declarators[0].Value).Symbol;
Assert.Equal("C<T>.field", declarators[1].Value.ToString());
var field2 = model.GetSymbolInfo(declarators[1].Value).Symbol;
Assert.Equal("C<T>.field", declarators[2].Value.ToString());
var field3 = model.GetSymbolInfo(declarators[2].Value).Symbol;
Assert.True(field2.Equals(field3, SymbolEqualityComparer.Default));
Assert.False(field2.Equals(field3, SymbolEqualityComparer.IncludeNullability));
Assert.True(field3.Equals(field2, SymbolEqualityComparer.Default));
Assert.False(field3.Equals(field2, SymbolEqualityComparer.IncludeNullability));
Assert.Equal(field2.GetHashCode(), field3.GetHashCode());
Assert.True(field1.Equals(field2, SymbolEqualityComparer.Default));
Assert.False(field1.Equals(field2, SymbolEqualityComparer.IncludeNullability));
Assert.True(field2.Equals(field1, SymbolEqualityComparer.Default));
Assert.False(field2.Equals(field1, SymbolEqualityComparer.IncludeNullability));
Assert.Equal(field1.GetHashCode(), field2.GetHashCode());
Assert.True(field1.Equals(field3, SymbolEqualityComparer.Default));
Assert.True(field1.Equals(field3, SymbolEqualityComparer.IncludeNullability));
Assert.True(field3.Equals(field1, SymbolEqualityComparer.Default));
Assert.True(field3.Equals(field1, SymbolEqualityComparer.IncludeNullability));
Assert.Equal(field1.GetHashCode(), field3.GetHashCode());
}
[Fact, WorkItem(49798, "https://github.com/dotnet/roslyn/issues/49798")]
public void IgnoredNullability_MethodSymbol()
{
var src = @"
#nullable enable
public class C
{
public void M<T>(out T x)
{
M<T>(out x);
#nullable disable
M<T>(out x);
}
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics();
var tree = comp.SyntaxTrees.Single();
var model = comp.GetSemanticModel(tree, ignoreAccessibility: false);
var method1 = model.GetDeclaredSymbol(tree.GetRoot().DescendantNodes().OfType<MethodDeclarationSyntax>().Single());
Assert.True(method1.IsDefinition);
var invocations = tree.GetRoot().DescendantNodes().OfType<InvocationExpressionSyntax>().ToArray();
Assert.Equal("M<T>(out x)", invocations[0].ToString());
var method2 = model.GetSymbolInfo(invocations[0]).Symbol;
Assert.False(method2.IsDefinition);
Assert.Equal("M<T>(out x)", invocations[1].ToString());
var method3 = model.GetSymbolInfo(invocations[1]).Symbol;
Assert.True(method3.IsDefinition);
// definitions and subsituted symbols should be equal when ignoring nullability
// Tracked by issue https://github.com/dotnet/roslyn/issues/49798
Assert.False(method2.Equals(method3, SymbolEqualityComparer.Default));
Assert.False(method2.Equals(method3, SymbolEqualityComparer.IncludeNullability));
Assert.False(method3.Equals(method2, SymbolEqualityComparer.Default));
Assert.False(method3.Equals(method2, SymbolEqualityComparer.IncludeNullability));
//Assert.Equal(method2.GetHashCode(), method3.GetHashCode());
Assert.False(method1.Equals(method2, SymbolEqualityComparer.Default));
Assert.False(method1.Equals(method2, SymbolEqualityComparer.IncludeNullability));
Assert.False(method2.Equals(method1, SymbolEqualityComparer.Default));
Assert.False(method2.Equals(method1, SymbolEqualityComparer.IncludeNullability));
//Assert.Equal(method1.GetHashCode(), method2.GetHashCode());
Assert.True(method1.Equals(method3, SymbolEqualityComparer.Default));
Assert.True(method1.Equals(method3, SymbolEqualityComparer.IncludeNullability));
Assert.True(method3.Equals(method1, SymbolEqualityComparer.Default));
Assert.True(method3.Equals(method1, SymbolEqualityComparer.IncludeNullability));
Assert.Equal(method1.GetHashCode(), method3.GetHashCode());
}
[Fact]
public void IgnoredNullability_OverrideReturnType_WithoutConstraint()
{
var src = @"
#nullable enable
public class C
{
public virtual T M<T>() => throw null!;
}
public class D : C
{
public override T? M<T>() where T : default => throw null!;
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (10,24): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// public override T? M<T>() where T : class => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "M").WithLocation(10, 24)
);
}
[Fact]
public void IgnoredNullability_OverrideReturnType_WithClassConstraint()
{
var src = @"
#nullable enable
public class C
{
public virtual T M<T>() where T : class => throw null!;
}
public class D : C
{
public override T? M<T>() where T : class => throw null!;
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (10,24): warning CS8764: Nullability of return type doesn't match overridden member (possibly because of nullability attributes).
// public override T? M<T>() where T : class => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnOverride, "M").WithLocation(10, 24)
);
}
[Fact, WorkItem(49131, "https://github.com/dotnet/roslyn/issues/49131")]
public void IgnoredNullability_OverrideOutParameterType_WithoutConstraint()
{
var src = @"
#nullable enable
public class C
{
public virtual void M<T>(out T t) => throw null!;
}
public class D : C
{
public override void M<T>(out T? t) where T : default => throw null!;
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (10,26): warning CS8765: Nullability of type of parameter 't' doesn't match overridden member (possibly because of nullability attributes).
// public override void M<T>(out T? t) where T : default => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "M").WithArguments("t").WithLocation(10, 26)
);
}
[Fact, WorkItem(49131, "https://github.com/dotnet/roslyn/issues/49131")]
public void IgnoredNullability_OverrideOutParameterType_WithClassConstraint()
{
var src = @"
#nullable enable
public class C
{
public virtual void M<T>(out T t) where T : class => throw null!;
}
public class D : C
{
public override void M<T>(out T? t) where T : class => throw null!;
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (10,26): warning CS8765: Nullability of type of parameter 't' doesn't match overridden member (possibly because of nullability attributes).
// public override void M<T>(out T? t) where T : class => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInParameterTypeOnOverride, "M").WithArguments("t").WithLocation(10, 26)
);
}
[Fact]
public void IgnoredNullability_ImplementationReturnType_WithoutConstraint()
{
var src = @"
#nullable enable
public interface I
{
T M<T>();
}
public class D : I
{
public T? M<T>() => throw null!;
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (10,15): warning CS8766: Nullability of reference types in return type of 'T? D.M<T>()' doesn't match implicitly implemented member 'T I.M<T>()' (possibly because of nullability attributes).
// public T? M<T>() => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnImplicitImplementation, "M").WithArguments("T? D.M<T>()", "T I.M<T>()").WithLocation(10, 15)
);
}
[Fact]
public void IgnoredNullability_ImplementationReturnType_WithClassConstraint()
{
var src = @"
#nullable enable
public interface I
{
T M<T>() where T : class;
}
public class D : I
{
public T? M<T>() where T : class => throw null!;
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (10,15): warning CS8766: Nullability of reference types in return type of 'T? D.M<T>()' doesn't match implicitly implemented member 'T I.M<T>()' (possibly because of nullability attributes).
// public T? M<T>() where T : class => throw null!;
Diagnostic(ErrorCode.WRN_TopLevelNullabilityMismatchInReturnTypeOnImplicitImplementation, "M").WithArguments("T? D.M<T>()", "T I.M<T>()").WithLocation(10, 15)
);
}
[Fact, WorkItem(49071, "https://github.com/dotnet/roslyn/issues/49071")]
public void IgnoredNullability_PartialMethodReturnType_WithoutConstraint()
{
var src = @"
#nullable enable
partial class C
{
public partial T F<T>();
}
partial class C
{
public partial T? F<T>() => default;
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (10,23): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration.
// public partial T? F<T>() => default;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "F").WithLocation(10, 23)
);
}
[Fact, WorkItem(49071, "https://github.com/dotnet/roslyn/issues/49071")]
public void IgnoredNullability_PartialMethodReturnType_WithClassConstraint()
{
var src = @"
#nullable enable
partial class C
{
public partial T F<T>() where T : class;
}
partial class C
{
public partial T? F<T>() where T : class => default;
}
";
var comp = CreateCompilation(src);
comp.VerifyDiagnostics(
// (10,23): warning CS8819: Nullability of reference types in return type doesn't match partial method declaration.
// public partial T? F<T>() where T : class => default;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInReturnTypeOnPartial, "F").WithLocation(10, 23)
);
}
}
}
......@@ -18,10 +18,10 @@ public class IndexedTypeParameterTests
[Fact]
public void TestTake()
{
var zero = IndexedTypeParameterSymbol.Take(0);
var zero = IndexedTypeParameterSymbol.TakeSymbols(0);
Assert.Equal(0, zero.Length);
var five = IndexedTypeParameterSymbol.Take(5);
var five = IndexedTypeParameterSymbol.TakeSymbols(5);
Assert.Equal(5, five.Length);
Assert.Equal(five[0], IndexedTypeParameterSymbol.GetTypeParameter(0));
Assert.Equal(five[1], IndexedTypeParameterSymbol.GetTypeParameter(1));
......@@ -29,14 +29,14 @@ public void TestTake()
Assert.Equal(five[3], IndexedTypeParameterSymbol.GetTypeParameter(3));
Assert.Equal(five[4], IndexedTypeParameterSymbol.GetTypeParameter(4));
var fifty = IndexedTypeParameterSymbol.Take(50);
var fifty = IndexedTypeParameterSymbol.TakeSymbols(50);
Assert.Equal(50, fifty.Length);
// prove they are all unique
var set = new HashSet<TypeParameterSymbol>(fifty);
Assert.Equal(50, set.Count);
var fiveHundred = IndexedTypeParameterSymbol.Take(500);
var fiveHundred = IndexedTypeParameterSymbol.TakeSymbols(500);
Assert.Equal(500, fiveHundred.Length);
}
}
......
......@@ -203,7 +203,7 @@ public interface ISymbol : IEquatable<ISymbol?>
ISymbol OriginalDefinition { get; }
void Accept(SymbolVisitor visitor);
TResult Accept<TResult>(SymbolVisitor<TResult> visitor);
TResult? Accept<TResult>(SymbolVisitor<TResult> visitor);
/// <summary>
/// Returns the Documentation Comment ID for the symbol, or null if the symbol doesn't
......
......@@ -19,7 +19,7 @@ private ExpressionSyntaxGeneratorVisitor()
}
public override ExpressionSyntax DefaultVisit(ISymbol symbol)
=> symbol.Accept(TypeSyntaxGeneratorVisitor.Create());
=> symbol.Accept(TypeSyntaxGeneratorVisitor.Create())!;
private static TExpressionSyntax AddInformationTo<TExpressionSyntax>(TExpressionSyntax syntax, ISymbol symbol)
where TExpressionSyntax : ExpressionSyntax
......@@ -48,7 +48,7 @@ public override ExpressionSyntax VisitNamedType(INamedTypeSymbol symbol)
}
else
{
var container = symbol.ContainingType.Accept(this);
var container = symbol.ContainingType.Accept(this)!;
return CreateMemberAccessExpression(symbol, container, simpleNameSyntax);
}
}
......@@ -66,7 +66,7 @@ public override ExpressionSyntax VisitNamedType(INamedTypeSymbol symbol)
}
else
{
var container = symbol.ContainingNamespace.Accept(this);
var container = symbol.ContainingNamespace.Accept(this)!;
return CreateMemberAccessExpression(symbol, container, simpleNameSyntax);
}
}
......@@ -91,7 +91,7 @@ public override ExpressionSyntax VisitNamespace(INamespaceSymbol symbol)
}
else
{
var container = symbol.ContainingNamespace.Accept(this);
var container = symbol.ContainingNamespace.Accept(this)!;
return CreateMemberAccessExpression(symbol, container, syntax);
}
}
......
......@@ -293,7 +293,7 @@ public override TypeSyntax VisitNamedType(INamedTypeSymbol symbol)
}
else
{
var container = symbol.ContainingNamespace.Accept(this);
var container = symbol.ContainingNamespace.Accept(this)!;
typeSyntax = AddInformationTo(SyntaxFactory.QualifiedName(
(NameSyntax)container,
simpleNameSyntax), symbol);
......@@ -323,7 +323,7 @@ public override TypeSyntax VisitNamespace(INamespaceSymbol symbol)
}
else
{
var container = symbol.ContainingNamespace.Accept(this);
var container = symbol.ContainingNamespace.Accept(this)!;
return AddInformationTo(SyntaxFactory.QualifiedName(
(NameSyntax)container,
syntax), symbol);
......
......@@ -22,7 +22,7 @@ internal static partial class ITypeSymbolExtensions
public static ExpressionSyntax GenerateExpressionSyntax(
this ITypeSymbol typeSymbol)
{
return typeSymbol.Accept(ExpressionSyntaxGeneratorVisitor.Instance).WithAdditionalAnnotations(Simplifier.Annotation);
return typeSymbol.Accept(ExpressionSyntaxGeneratorVisitor.Instance)!.WithAdditionalAnnotations(Simplifier.Annotation);
}
public static NameSyntax GenerateNameSyntax(
......@@ -48,7 +48,7 @@ internal static partial class ITypeSymbolExtensions
return SyntaxFactory.IdentifierName("var");
}
var syntax = symbol.Accept(TypeSyntaxGeneratorVisitor.Create(nameSyntax))
var syntax = symbol.Accept(TypeSyntaxGeneratorVisitor.Create(nameSyntax))!
.WithAdditionalAnnotations(Simplifier.Annotation);
if (!allowVar)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册