未验证 提交 fffa9bed 编写于 作者: C Charles Stoner 提交者: GitHub

Erase nullability from base and interfaces for types from unannotated assemblies (#28028)

上级 cbf4d8a3
......@@ -343,7 +343,7 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasS
TypeSymbolWithAnnotations constructedType;
if (Compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking))
{
constructedType = typeArgument.AsNullableReferenceOrValueType(Compilation, syntax.GetReference());
constructedType = typeArgument.AsNullableReferenceOrValueType(Compilation);
if (!ShouldCheckConstraints)
{
diagnostics.Add(new LazyUseSiteDiagnosticsInfoForNullableType(constructedType), syntax.GetLocation());
......@@ -433,7 +433,7 @@ internal NamespaceOrTypeOrAliasSymbolWithAnnotations BindNamespaceOrTypeOrAliasS
if (a.QuestionToken.IsKind(SyntaxKind.QuestionToken))
{
type = TypeSymbolWithAnnotations.CreateNullableReferenceType(array);
type = TypeSymbolWithAnnotations.Create(array, isNullableIfReferenceType: true);
}
else
{
......
......@@ -1338,7 +1338,7 @@ private static bool HasIdentityConversionInternal(TypeSymbol type1, TypeSymbol t
// PROTOTYPE(NullableReferenceTypes): If two types differ only by nullability and
// one has IsNullable unset and the other doesn't, which do we choose in inference?
// See failing test IdentityConversion_ArrayInitializer_IsNullableNull.
// See test TypeInference_04.
var compareKind = includeNullability ?
TypeCompareKind.AllIgnoreOptions | TypeCompareKind.CompareNullableModifiersForReferenceTypes | TypeCompareKind.UnknownNullableModifierMatchesAny :
TypeCompareKind.AllIgnoreOptions;
......@@ -1352,9 +1352,6 @@ private bool HasIdentityConversionInternal(TypeSymbol type1, TypeSymbol type2)
internal static bool HasTopLevelNullabilityIdentityConversion(TypeSymbolWithAnnotations source, TypeSymbolWithAnnotations destination)
{
// PROTOTYPE(NullableReferenceTypes): If two types differ only by nullability and
// one has IsNullable unset and the other doesn't, which do we choose in inference?
// See failing test IdentityConversion_ArrayInitializer_IsNullableNull.
bool? sourceIsNullable = source.IsNullable;
bool? destinationIsNullable = destination.IsNullable;
return sourceIsNullable == null || destinationIsNullable == null || sourceIsNullable == destinationIsNullable;
......
......@@ -65,7 +65,8 @@ internal abstract class PENamedTypeSymbol : NamedTypeSymbol
private NamedTypeSymbol _lazyBaseType = ErrorTypeSymbol.UnknownResultType;
private ImmutableArray<NamedTypeSymbol> _lazyInterfaces = default(ImmutableArray<NamedTypeSymbol>);
private NamedTypeSymbol _lazyDeclaredBaseType = ErrorTypeSymbol.UnknownResultType;
private NamedTypeSymbol _lazyDeclaredBaseTypeWithoutNullability = ErrorTypeSymbol.UnknownResultType;
private NamedTypeSymbol _lazyDeclaredBaseTypeWithNullability = ErrorTypeSymbol.UnknownResultType;
private ImmutableArray<NamedTypeSymbol> _lazyDeclaredInterfaces = default(ImmutableArray<NamedTypeSymbol>);
private Tuple<CultureInfo, string> _lazyDocComment;
......@@ -426,12 +427,32 @@ internal override ImmutableArray<NamedTypeSymbol> GetInterfacesToEmit()
internal override NamedTypeSymbol GetDeclaredBaseType(ConsList<Symbol> basesBeingResolved)
{
if (ReferenceEquals(_lazyDeclaredBaseType, ErrorTypeSymbol.UnknownResultType))
return GetDeclaredBaseType(ignoreNullability: false);
}
private NamedTypeSymbol GetDeclaredBaseType(bool ignoreNullability)
{
if (ReferenceEquals(_lazyDeclaredBaseTypeWithoutNullability, ErrorTypeSymbol.UnknownResultType))
{
Interlocked.CompareExchange(ref _lazyDeclaredBaseTypeWithoutNullability, MakeDeclaredBaseType(), ErrorTypeSymbol.UnknownResultType);
}
if (ignoreNullability)
{
Interlocked.CompareExchange(ref _lazyDeclaredBaseType, MakeDeclaredBaseType(), ErrorTypeSymbol.UnknownResultType);
return _lazyDeclaredBaseTypeWithoutNullability;
}
return _lazyDeclaredBaseType;
if (ReferenceEquals(_lazyDeclaredBaseTypeWithNullability, ErrorTypeSymbol.UnknownResultType))
{
var declaredBase = _lazyDeclaredBaseTypeWithoutNullability;
if ((object)declaredBase != null)
{
declaredBase = (NamedTypeSymbol)NullableTypeDecoder.TransformOrEraseNullability(TypeSymbolWithAnnotations.Create(declaredBase), _handle, ContainingPEModule).TypeSymbol;
}
Interlocked.CompareExchange(ref _lazyDeclaredBaseTypeWithNullability, declaredBase, ErrorTypeSymbol.UnknownResultType);
}
return _lazyDeclaredBaseTypeWithNullability;
}
internal override ImmutableArray<NamedTypeSymbol> GetDeclaredInterfaces(ConsList<Symbol> basesBeingResolved)
......@@ -456,8 +477,10 @@ private NamedTypeSymbol MakeDeclaredBaseType()
if (!token.IsNil)
{
TypeSymbol decodedType = new MetadataDecoder(moduleSymbol, this).GetTypeOfToken(token);
var result = (NamedTypeSymbol)DynamicTypeDecoder.TransformType(decodedType, 0, _handle, moduleSymbol);
return DecodeBaseAndInterfaceNullableAndTupleTypes(result, _handle, moduleSymbol);
decodedType = DynamicTypeDecoder.TransformType(decodedType, 0, _handle, moduleSymbol);
return (NamedTypeSymbol)TupleTypeDecoder.DecodeTupleTypesIfApplicable(decodedType,
_handle,
moduleSymbol);
}
}
catch (BadImageFormatException mrEx)
......@@ -485,16 +508,12 @@ private ImmutableArray<NamedTypeSymbol> MakeDeclaredInterfaces()
{
EntityHandle interfaceHandle = moduleSymbol.Module.MetadataReader.GetInterfaceImplementation(interfaceImpl).Interface;
TypeSymbol typeSymbol = tokenDecoder.GetTypeOfToken(interfaceHandle);
var result = typeSymbol as NamedTypeSymbol;
if (result is null)
{
result = new UnsupportedMetadataTypeSymbol(); // interface list contains a bad type
}
else
{
result = DecodeBaseAndInterfaceNullableAndTupleTypes(result, interfaceImpl, moduleSymbol);
}
symbols.Add(result);
typeSymbol = TupleTypeDecoder.DecodeTupleTypesIfApplicable(typeSymbol, interfaceImpl, moduleSymbol);
typeSymbol = NullableTypeDecoder.TransformOrEraseNullability(TypeSymbolWithAnnotations.Create(typeSymbol), interfaceImpl, moduleSymbol).TypeSymbol;
var namedTypeSymbol = typeSymbol as NamedTypeSymbol ?? new UnsupportedMetadataTypeSymbol(); // interface list contains a bad type
symbols.Add(namedTypeSymbol);
}
return symbols.ToImmutableAndFree();
......@@ -508,18 +527,6 @@ private ImmutableArray<NamedTypeSymbol> MakeDeclaredInterfaces()
}
}
private static NamedTypeSymbol DecodeBaseAndInterfaceNullableAndTupleTypes(NamedTypeSymbol type, EntityHandle handle, PEModuleSymbol moduleSymbol)
{
// PROTOTYPE(NullableReferenceTypes): Should call NullableTypeDecoder.TransformOrEraseNullability
// here (see StaticNullChecking.UnannotatedAssemblies_09) but TransformOrEraseNullability results in
// a StackOverflowException when building Roslyn.sln.
if (moduleSymbol.UtilizesNullableReferenceTypes)
{
type = (NamedTypeSymbol)NullableTypeDecoder.TransformType(TypeSymbolWithAnnotations.Create(type), handle, moduleSymbol).TypeSymbol;
}
return (NamedTypeSymbol)TupleTypeDecoder.DecodeTupleTypesIfApplicable(type, handle, moduleSymbol);
}
public override NamedTypeSymbol ConstructedFrom
{
get
......@@ -1628,7 +1635,7 @@ public override TypeKind TypeKind
}
else
{
TypeSymbol @base = GetDeclaredBaseType(null);
TypeSymbol @base = GetDeclaredBaseType(ignoreNullability: true);
result = TypeKind.Class;
......
......@@ -19,7 +19,7 @@ internal sealed class SymbolFactory : SymbolFactory<PEModuleSymbol, TypeSymbol>
return elementType;
}
return ArrayTypeSymbol.CreateMDArray(moduleSymbol.ContainingAssembly, TypeSymbolWithAnnotations.Create(elementType, CSharpCustomModifier.Convert(customModifiers)), rank, sizes, lowerBounds);
return ArrayTypeSymbol.CreateMDArray(moduleSymbol.ContainingAssembly, CreateType(elementType, customModifiers), rank, sizes, lowerBounds);
}
internal override TypeSymbol GetSpecialType(PEModuleSymbol moduleSymbol, SpecialType specialType)
......@@ -39,7 +39,7 @@ internal override TypeSymbol MakePointerTypeSymbol(PEModuleSymbol moduleSymbol,
return type;
}
return new PointerTypeSymbol(TypeSymbolWithAnnotations.Create(type, CSharpCustomModifier.Convert(customModifiers)));
return new PointerTypeSymbol(CreateType(type, customModifiers));
}
internal override TypeSymbol GetEnumUnderlyingType(PEModuleSymbol moduleSymbol, TypeSymbol type)
......@@ -74,7 +74,7 @@ internal override TypeSymbol GetSZArrayTypeSymbol(PEModuleSymbol moduleSymbol, T
return elementType;
}
return ArrayTypeSymbol.CreateSZArray(moduleSymbol.ContainingAssembly, TypeSymbolWithAnnotations.Create(elementType, CSharpCustomModifier.Convert(customModifiers)));
return ArrayTypeSymbol.CreateSZArray(moduleSymbol.ContainingAssembly, CreateType(elementType, customModifiers));
}
internal override TypeSymbol GetUnsupportedMetadataTypeSymbol(PEModuleSymbol moduleSymbol, BadImageFormatException exception)
......@@ -152,7 +152,7 @@ internal override TypeSymbol GetUnsupportedMetadataTypeSymbol(PEModuleSymbol mod
return new UnsupportedMetadataTypeSymbol();
}
TypeMap substitution = new TypeMap(typeParameters, arguments.SelectAsArray(arg => TypeSymbolWithAnnotations.Create(arg.Key, CSharpCustomModifier.Convert(arg.Value))));
TypeMap substitution = new TypeMap(typeParameters, arguments.SelectAsArray(arg => CreateType(arg.Key, arg.Value)));
NamedTypeSymbol constructedType = substitution.SubstituteNamedType(genericType);
......@@ -169,5 +169,10 @@ internal override TypeSymbol MakeUnboundIfGeneric(PEModuleSymbol moduleSymbol, T
var namedType = type as NamedTypeSymbol;
return ((object)namedType != null && namedType.IsGenericType) ? namedType.AsUnboundGenericType() : type;
}
private static TypeSymbolWithAnnotations CreateType(TypeSymbol type, ImmutableArray<ModifierInfo<TypeSymbol>> customModifiers)
{
return TypeSymbolWithAnnotations.Create(type, CSharpCustomModifier.Convert(customModifiers));
}
}
}
......@@ -196,20 +196,6 @@ public static TypeSymbolWithAnnotations Create(TypeSymbol typeSymbol)
return Create(typeSymbol, ImmutableArray<CustomModifier>.Empty);
}
// PROTOTYPE(NullableReferenceTypes): Check we are not using this method on type references in
// member signatures visible outside the assembly. Consider overriding, implementing, NoPIA embedding, etc.
public static TypeSymbolWithAnnotations CreateNullableReferenceType(TypeSymbol typeSymbol)
{
if (typeSymbol is null)
{
return null;
}
// PROTOTYPE(NullableReferenceTypes): Consider if it makes
// sense to cache and reuse instances, at least for definitions.
return new NonLazyType(typeSymbol, isNullable: true, ImmutableArray<CustomModifier>.Empty);
}
// PROTOTYPE(NullableReferenceTypes): Check we are not using this method on type references in
// member signatures visible outside the assembly. Consider overriding, implementing, NoPIA embedding, etc.
public static TypeSymbolWithAnnotations Create(TypeSymbol typeSymbol, ImmutableArray<CustomModifier> customModifiers)
......@@ -252,17 +238,18 @@ public static TypeSymbolWithAnnotations Create(TypeSymbol typeSymbol, bool? isNu
return new NonLazyType(typeSymbol, isNullable, customModifiers);
}
public TypeSymbolWithAnnotations AsNullableReferenceOrValueType(CSharpCompilation compilation, SyntaxReference nullableTypeSyntax)
public TypeSymbolWithAnnotations AsNullableReferenceOrValueType(CSharpCompilation compilation)
{
var typeSymbol = this.TypeSymbol;
Debug.Assert(compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking));
Debug.Assert(CustomModifiers.IsEmpty);
var typeSymbol = this.TypeSymbol;
// It is not safe to check if a type parameter is a reference type right away, this can send us into a cycle.
// In this case we delay asking this question as long as possible.
if (typeSymbol.TypeKind != TypeKind.TypeParameter)
{
if (typeSymbol.IsReferenceType && ((CSharpParseOptions)nullableTypeSyntax.SyntaxTree.Options).IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking))
if (typeSymbol.IsReferenceType)
{
return new NonLazyType(typeSymbol, isNullable: true, this.CustomModifiers);
}
......@@ -272,7 +259,7 @@ public TypeSymbolWithAnnotations AsNullableReferenceOrValueType(CSharpCompilatio
}
}
return new LazyNullableType(compilation, nullableTypeSyntax, this);
return new LazyNullableType(compilation, this);
}
/// <summary>
......@@ -744,17 +731,16 @@ public override string ToDisplayString(SymbolDisplayFormat format)
private sealed class LazyNullableType : TypeSymbolWithAnnotations
{
private readonly CSharpCompilation _compilation;
private readonly SyntaxReference _nullableTypeSyntax;
private readonly TypeSymbolWithAnnotations _underlying;
private TypeSymbol _resolved;
public LazyNullableType(CSharpCompilation compilation, SyntaxReference nullableTypeSyntax, TypeSymbolWithAnnotations underlying)
public LazyNullableType(CSharpCompilation compilation, TypeSymbolWithAnnotations underlying)
{
Debug.Assert(compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking));
Debug.Assert(underlying.IsNullable != true);
Debug.Assert(underlying.TypeKind == TypeKind.TypeParameter);
Debug.Assert(underlying.CustomModifiers.IsEmpty);
_compilation = compilation;
_nullableTypeSyntax = nullableTypeSyntax;
_underlying = underlying;
}
......@@ -769,15 +755,14 @@ public override TypeSymbol TypeSymbol
{
if ((object)_resolved == null)
{
if (!_underlying.IsValueType && ((CSharpParseOptions)_nullableTypeSyntax.SyntaxTree.Options).IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking))
if (!_underlying.IsValueType)
{
_resolved = _underlying.TypeSymbol;
}
else
{
Interlocked.CompareExchange(ref _resolved,
_compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(
ImmutableArray.Create(_underlying)),
_compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(ImmutableArray.Create(_underlying)),
null);
}
}
......@@ -890,7 +875,7 @@ public override TypeSymbolWithAnnotations SubstituteType(AbstractTypeMap typeMap
newUnderlying.TypeSymbol is IndexedTypeParameterSymbolForOverriding) &&
newUnderlying.CustomModifiers.IsEmpty)
{
return new LazyNullableType(_compilation, _nullableTypeSyntax, newUnderlying);
return new LazyNullableType(_compilation, newUnderlying);
}
return base.SubstituteType(typeMap);
......@@ -915,7 +900,7 @@ public override TypeSymbolWithAnnotations SubstituteTypeWithTupleUnification(Abs
newUnderlying.TypeSymbol is IndexedTypeParameterSymbolForOverriding) &&
newUnderlying.CustomModifiers.IsEmpty)
{
return new LazyNullableType(_compilation, _nullableTypeSyntax, newUnderlying);
return new LazyNullableType(_compilation, newUnderlying);
}
return base.SubstituteTypeWithTupleUnification(typeMap);
......
......@@ -819,9 +819,7 @@ static void F(object? x, object y, C2 c)
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "((A)c).F(x, y)").WithLocation(27, 9));
}
// PROTOTYPE(NullableReferenceTypes): Should call NullableTypeDecoder.TransformOrEraseNullability
// in PENamedTypeSymbol.MakeDeclaredBaseType.
[Fact(Skip = "TODO")]
[Fact]
public void UnannotatedAssemblies_10()
{
var source0 =
......@@ -15129,55 +15127,87 @@ static void F(IOut<object> x, IOut<object?> y, IOut<object>? z, IOut<object?>? w
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { w, z })[0]").WithLocation(31, 9));
}
// PROTOTYPE(NullableReferenceTypes): Update this method to use types from unannotated assemblies
// rather than `x!`, particularly because `x!` results in IsNullable=false rather than IsNullable=null.
[Fact]
public void IdentityConversion_ArrayInitializer_IsNullableNull()
{
var source =
@"#pragma warning disable 0649
#pragma warning disable 8618
class A<T>
var source0 =
@"#pragma warning disable 8618
public class A<T>
{
internal T F;
public T F;
}
class B
public class B : A<object>
{
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
var source =
@"class C
{
static void F(object? x, object y)
static void F(object? x, B b)
{
(new[] { x, x! })[0].ToString();
(new[] { x!, x })[0].ToString();
var y = b.F/*T:object*/;
(new[] { x, x! })[0].ToString(); // 1
(new[] { x!, x })[0].ToString(); // 2
(new[] { x!, x! })[0].ToString();
(new[] { y, y! })[0].ToString();
(new[] { y!, y })[0].ToString();
(new[] { x, y })[0].ToString(); // 3
(new[] { x, y! })[0].ToString(); // 4
(new[] { x!, y })[0].ToString();
(new[] { x!, y! })[0].ToString();
}
static void F(A<object?> z, A<object> w)
static void F(A<object?> z, B w)
{
(new[] { z, z! })[0].F.ToString();
(new[] { z!, z })[0].F.ToString();
(new[] { z!, z! })[0].F.ToString();
(new[] { z, z! })[0].F.ToString(); // 5
(new[] { z!, z })[0].F.ToString(); // 6
(new[] { z!, z! })[0].F.ToString(); // 7
(new[] { w, w! })[0].F.ToString();
(new[] { w!, w })[0].F.ToString();
(new[] { z, w })[0].F.ToString(); // 8
(new[] { z, w! })[0].F.ToString(); // 9
(new[] { z!, w })[0].F.ToString(); // 10
(new[] { z!, w! })[0].F.ToString(); // 11
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyTypes();
comp.VerifyDiagnostics(
// (6,9): warning CS8602: Possible dereference of a null reference.
// (new[] { x, x! })[0].ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { x, x! })[0]").WithLocation(6, 9),
// (7,9): warning CS8602: Possible dereference of a null reference.
// (new[] { x!, x })[0].ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { x!, x })[0]").WithLocation(7, 9),
// (11,9): warning CS8602: Possible dereference of a null reference.
// (new[] { x, x! })[0].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { x, x! })[0]").WithLocation(11, 9),
// (new[] { x, y })[0].ToString(); // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { x, y })[0]").WithLocation(11, 9),
// (12,9): warning CS8602: Possible dereference of a null reference.
// (new[] { x!, x })[0].ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { x!, x })[0]").WithLocation(12, 9),
// (new[] { x, y! })[0].ToString(); // 4
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { x, y! })[0]").WithLocation(12, 9),
// (18,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z, z! })[0].F.ToString(); // 5
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z, z! })[0].F").WithLocation(18, 9),
// (19,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z, z! })[0].F.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z, z! })[0].F").WithLocation(19, 9),
// (new[] { z!, z })[0].F.ToString(); // 6
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z!, z })[0].F").WithLocation(19, 9),
// (20,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z!, z })[0].F.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z!, z })[0].F").WithLocation(20, 9),
// (21,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z!, z! })[0].F.ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z!, z! })[0].F").WithLocation(21, 9)
);
// (new[] { z!, z! })[0].F.ToString(); // 7
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z!, z! })[0].F").WithLocation(20, 9),
// (23,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z, w })[0].F.ToString(); // 8
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z, w })[0].F").WithLocation(23, 9),
// (24,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z, w! })[0].F.ToString(); // 9
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z, w! })[0].F").WithLocation(24, 9),
// (25,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z!, w })[0].F.ToString(); // 10
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z!, w })[0].F").WithLocation(25, 9),
// (26,9): warning CS8602: Possible dereference of a null reference.
// (new[] { z!, w! })[0].F.ToString(); // 11
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "(new[] { z!, w! })[0].F").WithLocation(26, 9));
}
[Fact]
......@@ -20920,6 +20950,36 @@ class CL0<T>
);
}
[Fact]
public void MethodGroupConversion_06()
{
var source =
@"delegate void D<T>(T t) where T : A;
class A { }
class B<T>
{
internal void F(T t) { }
}
class C
{
static B<T> Create<T>(T t) => new B<T>();
static void G(A x, A? y)
{
D<A> d;
d = Create(x).F;
d = Create(y).F; // warning
x = y;
d = Create(x).F; // warning
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
// PROTOTYPE(NullableReferenceTypes): Report conversion warnings.
comp.VerifyDiagnostics(
// (15,13): warning CS8600: Converting null literal or possible null value to non-nullable type.
// x = y;
Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "y").WithLocation(15, 13));
}
[Fact]
public void UnaryOperator_01()
{
......@@ -32243,31 +32303,55 @@ static void G(I<string> x, I<string?> y)
[Fact]
public void TypeInference_04()
{
var source0 =
@"public class A
{
}
public class B
{
public A F;
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
// PROTOTYPE(NullableReferenceTypes): The result of type inference with null-oblivious
// depends on the order possible type arguments are considered. For instance,
// the type inferred for F(x, z) is A? and the type inferred for F(z, x) is A.
// See https://github.com/dotnet/roslyn/issues/27961.
var source =
@"class C
{
static T F<T>(T x, T y) => x;
static void G(C? x, C y)
static void G(A? x, A y, B b)
{
F(x, x).ToString();
F(x, y).ToString();
F(y, x).ToString();
F(y, y).ToString();
var z = b.F;
F(x, x)/*T:A?*/.ToString(); // 1
F(x, y)/*T:A?*/.ToString(); // 2
F(x, z)/*T:A?*/.ToString(); // 3
F(y, x)/*T:A?*/.ToString(); // 4
F(y, y)/*T:A!*/.ToString();
F(y, z)/*T:A!*/.ToString();
F(z, x)/*T:A*/.ToString(); // 5
F(z, y)/*T:A*/.ToString();
F(z, z)/*T:A*/.ToString();
}
}";
var comp = CreateCompilation(
source,
parseOptions: TestOptions.Regular8);
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyTypes();
comp.VerifyDiagnostics(
// (6,9): warning CS8602: Possible dereference of a null reference.
// F(x, x).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(x, x)").WithLocation(6, 9),
// (7,9): warning CS8602: Possible dereference of a null reference.
// F(x, y).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(x, y)").WithLocation(7, 9),
// F(x, x)/*T:A?*/.ToString(); // 1
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(x, x)").WithLocation(7, 9),
// (8,9): warning CS8602: Possible dereference of a null reference.
// F(y, x).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(y, x)").WithLocation(8, 9));
// F(x, y)/*T:A?*/.ToString(); // 2
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(x, y)").WithLocation(8, 9),
// (9,9): warning CS8602: Possible dereference of a null reference.
// F(x, z)/*T:A?*/.ToString(); // 3
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(x, z)").WithLocation(9, 9),
// (10,9): warning CS8602: Possible dereference of a null reference.
// F(y, x)/*T:A?*/.ToString(); // 4
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(y, x)").WithLocation(10, 9));
}
[Fact]
......@@ -34985,6 +35069,204 @@ class B2 : A<int>
comp.VerifyDiagnostics();
}
[WorkItem(27967, "https://github.com/dotnet/roslyn/issues/27967")]
[Fact]
public void UnannotatedTypeArgument_Interface()
{
var source0 =
@"public interface I<T>
{
}
public class B : I<object[]>
{
}
public class C : I<C>
{
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
var source =
@"class Program
{
static void F(B x)
{
I<object[]?> a = x;
I<object[]> b = x;
}
static void F(C y)
{
I<C?> a = y;
I<C> b = y;
}
}";
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
}
[WorkItem(27967, "https://github.com/dotnet/roslyn/issues/27967")]
[Fact]
public void UnannotatedTypeArgument_BaseType()
{
var source0 =
@"public class A<T>
{
}
public class B : A<object[]>
{
}
public class C : A<C>
{
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
var source =
@"class Program
{
static void F(B x)
{
A<object[]?> a = x;
A<object[]> b = x;
}
static void F(C y)
{
A<C?> a = y;
A<C> b = y;
}
}";
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
}
[Fact]
public void UnannotatedTypeArgument_Interface_Lookup()
{
var source0 =
@"public interface I<T>
{
void F(T t);
}
public interface I1 : I<object>
{
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
var source =
@"interface I2 : I<object>
{
}
class Program
{
static void F(I1 i1, I2 i2, object x, object? y)
{
i1.F(x);
i1.F(y);
i2.F(x);
i2.F(y); // warn
}
}";
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (11,14): warning CS8604: Possible null reference argument for parameter 't' in 'void I<object>.F(object t)'.
// i2.F(y); // warn
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("t", "void I<object>.F(object t)").WithLocation(11, 14));
}
[Fact]
public void UnannotatedTypeArgument_BaseType_Lookup()
{
var source0 =
@"public class A<T>
{
public static void F(T t) { }
}
public class B1 : A<object>
{
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
var source =
@"class B2 : A<object>
{
}
class Program
{
static void F(object x, object? y)
{
B1.F(x);
B1.F(y);
B2.F(x);
B2.F(y); // warn
}
}";
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (11,14): warning CS8604: Possible null reference argument for parameter 't' in 'void A<object>.F(object t)'.
// B2.F(y); // warn
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("t", "void A<object>.F(object t)").WithLocation(11, 14));
}
[Fact]
public void UnannotatedConstraint_01()
{
var source0 =
@"public class A
{
}
public class B<T> where T : A
{
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
var source =
@"class Program
{
static void Main()
{
new B<A?>();
new B<A>();
}
}";
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
}
[Fact]
public void UnannotatedConstraint_02()
{
var source0 =
@"public class A<T>
{
}
public class B<T> where T : A<object>
{
}";
var comp0 = CreateCompilation(source0, parseOptions: TestOptions.Regular7);
comp0.VerifyDiagnostics();
var ref0 = comp0.EmitToImageReference();
var source =
@"class Program
{
static void Main()
{
new B<A<object?>>();
new B<A<object>>();
}
}";
var comp = CreateCompilation(source, references: new[] { ref0 }, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
}
[Fact]
public void Constraint_Oblivious_01()
{
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册