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

MaybeNullWhen and NotNullWhen attribute affects callers (#36172)

上级 611578d7
...@@ -35,12 +35,12 @@ namespace System.Runtime.CompilerServices ...@@ -35,12 +35,12 @@ namespace System.Runtime.CompilerServices
public sealed class NullableAttribute : Attribute public sealed class NullableAttribute : Attribute
{ {
public readonly byte[] NullableFlags; public readonly byte[] NullableFlags;
public NullableAttribute(byte b) public NullableAttribute(byte b)
{ {
NullableFlags = new byte[] { b }; NullableFlags = new byte[] { b };
} }
public NullableAttribute(byte[] b) public NullableAttribute(byte[] b)
{ {
NullableFlags = b; NullableFlags = b;
...@@ -52,14 +52,14 @@ namespace System.Runtime.CompilerServices ...@@ -52,14 +52,14 @@ namespace System.Runtime.CompilerServices
Each type reference is accompanied by a NullableAttribute with an array of bytes, where 0 is Oblivious, 1 is NotAnnotated and 2 is Annotated. Each type reference is accompanied by a NullableAttribute with an array of bytes, where 0 is Oblivious, 1 is NotAnnotated and 2 is Annotated.
All value types are marked with flag 0 (oblivious). All value types are marked with flag 0 (oblivious).
To optimize trivial cases the attribute can be omitted, or instead can be replaced with an attribute that takes a single byte value rather than an array. To optimize trivial cases the attribute can be omitted, or instead can be replaced with an attribute that takes a single byte value rather than an array.
Trivial/optimized cases: Trivial/optimized cases:
1) All parts are NotAnnotated – a NullableAttribute with a single value 1 (rather than an array of 1s) 1) All parts are NotAnnotated – a NullableAttribute with a single value 1 (rather than an array of 1s)
2) All parts are Annotated - a NullableAttribute with a single value 2 (rather than an array of 2s) 2) All parts are Annotated - a NullableAttribute with a single value 2 (rather than an array of 2s)
3) All parts are Oblivious – the attribute is omitted, this matches how we interpret the lack of an attribute in legacy assemblies. 3) All parts are Oblivious – the attribute is omitted, this matches how we interpret the lack of an attribute in legacy assemblies.
For completeness, we would also recognize a NullableAttribute with a single value 0 (rather than an array of 0s), For completeness, we would also recognize a NullableAttribute with a single value 0 (rather than an array of 0s),
but compiler will never emit an attribute like this. but compiler will never emit an attribute like this.
NullableAttribute(1) should be placed on a type parameter definition that has a `notnull` constraint. NullableAttribute(1) should be placed on a type parameter definition that has a `notnull` constraint.
NullableAttribute(1) should be placed on a type parameter definition that has a `class!` constraint. NullableAttribute(1) should be placed on a type parameter definition that has a `class!` constraint.
...@@ -103,9 +103,11 @@ A number of null checks affect the flow state when tested for: ...@@ -103,9 +103,11 @@ A number of null checks affect the flow state when tested for:
- `is` operator: `x is null`, `x is K` (where `K` is a constant), `x is string`, `x is string s` - `is` operator: `x is null`, `x is K` (where `K` is a constant), `x is string`, `x is string s`
Invocation of methods annotated with the following attributes will also affect flow analysis: Invocation of methods annotated with the following attributes will also affect flow analysis:
- `[NotNullWhenTrue]` (e.g. `TryGetValue`) and `[NotNullWhenFalse]` (e.g. `string.IsNullOrEmpty`) - simple pre-conditions: `[AllowNull]` and `[DisallowNull]`
- `[EnsuresNotNull]` (e.g. `ThrowIfNull`) - simple post-conditions: `[MaybeNull]` and `[NotNull]`
- conditional post-conditions: `[MaybeNullWhen(bool)]` and `[NotNullWhen(bool)]`
- `[AssertsTrue]` (e.g. `Debug.Assert`) and `[AssertsFalse]` - `[AssertsTrue]` (e.g. `Debug.Assert`) and `[AssertsFalse]`
See https://github.com/dotnet/csharplang/blob/master/meetings/2019/LDM-2019-05-15.md
## `default` ## `default`
If `T` is a reference type, `default(T)` is `T?`. If `T` is a reference type, `default(T)` is `T?`.
......
...@@ -351,7 +351,7 @@ private BoundLambda SuppressIfNeeded(BoundLambda lambda) ...@@ -351,7 +351,7 @@ private BoundLambda SuppressIfNeeded(BoundLambda lambda)
public bool HasExplicitlyTypedParameterList { get { return Data.HasExplicitlyTypedParameterList; } } public bool HasExplicitlyTypedParameterList { get { return Data.HasExplicitlyTypedParameterList; } }
public int ParameterCount { get { return Data.ParameterCount; } } public int ParameterCount { get { return Data.ParameterCount; } }
public TypeWithAnnotations InferReturnType(ConversionsBase conversions, NamedTypeSymbol delegateType, ref HashSet<DiagnosticInfo> useSiteDiagnostics) public TypeWithAnnotations InferReturnType(ConversionsBase conversions, NamedTypeSymbol delegateType, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
=> BindForReturnTypeInference(delegateType).GetInferredReturnType(conversions, _nullableState, ref useSiteDiagnostics); => BindForReturnTypeInference(delegateType).GetInferredReturnType(conversions, _nullableState?.Clone(), ref useSiteDiagnostics);
public RefKind RefKind(int index) { return Data.RefKind(index); } public RefKind RefKind(int index) { return Data.RefKind(index); }
public void GenerateAnonymousFunctionConversionError(DiagnosticBag diagnostics, TypeSymbol targetType) { Data.GenerateAnonymousFunctionConversionError(diagnostics, targetType); } public void GenerateAnonymousFunctionConversionError(DiagnosticBag diagnostics, TypeSymbol targetType) { Data.GenerateAnonymousFunctionConversionError(diagnostics, targetType); }
......
...@@ -73,6 +73,8 @@ private TypeWithState(TypeSymbol type, NullableFlowState state) ...@@ -73,6 +73,8 @@ private TypeWithState(TypeSymbol type, NullableFlowState state)
public TypeWithState WithNotNullState() => new TypeWithState(Type, NullableFlowState.NotNull); public TypeWithState WithNotNullState() => new TypeWithState(Type, NullableFlowState.NotNull);
public TypeWithState WithSuppression(bool suppress) => suppress ? new TypeWithState(Type, NullableFlowState.NotNull) : this;
public TypeWithAnnotations ToTypeWithAnnotations() public TypeWithAnnotations ToTypeWithAnnotations()
{ {
NullableAnnotation annotation = this.State.IsNotNull() || Type?.CanContainNull() == false || Type?.IsTypeParameterDisallowingAnnotation() == true NullableAnnotation annotation = this.State.IsNotNull() || Type?.CanContainNull() == false || Type?.IsTypeParameterDisallowingAnnotation() == true
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册