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

Infer nested nullability in flow analysis (#23439)

上级 cb4b05f8
......@@ -2697,9 +2697,9 @@ private BoundExpression BindImplicitArrayCreationExpression(ImplicitArrayCreatio
var bestType = BestTypeInferrer.InferBestType(
boundInitializerExpressions,
this.Conversions,
this.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking),
out hadMultipleCandidates,
ref useSiteDiagnostics);
includeNullability: false,
hadMultipleCandidates: out hadMultipleCandidates,
useSiteDiagnostics: ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
if ((object)bestType == null || bestType.SpecialType == SpecialType.System_Void) // Dev10 also reports ERR_ImplicitlyTypedArrayNoBestType for void.
......
......@@ -3581,9 +3581,9 @@ private BoundExpression BindConditionalOperator(ConditionalExpressionSyntax node
trueExpr,
falseExpr,
this.Conversions,
this.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking),
out hadMultipleCandidates,
ref useSiteDiagnostics);
includeNullability: false,
hadMultipleCandidates: out hadMultipleCandidates,
useSiteDiagnostics: ref useSiteDiagnostics);
diagnostics.Add(node, useSiteDiagnostics);
if ((object)bestType == null)
......
......@@ -17,6 +17,7 @@ private BestTypeInferrer(Conversions conversions)
_conversions = conversions;
}
// PROTOTYPE(NullableReferenceTypes): Remove includeNullability parameter. Nullability should be calculated in flow analysis.
public static TypeSymbolWithAnnotations InferBestType(ImmutableArray<TypeSymbolWithAnnotations> types, Conversions conversions, bool includeNullability, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
{
var inferrer = new BestTypeInferrer(conversions);
......
......@@ -108,6 +108,7 @@ private enum Dependency
public static MethodTypeInferenceResult Infer(
Binder binder,
ConversionsBase conversions,
ImmutableArray<TypeParameterSymbol> methodTypeParameters,
// We are attempting to build a map from method type parameters
// to inferred type arguments.
......@@ -213,7 +214,8 @@ private enum Dependency
ImmutableArray<RefKind> formalParameterRefKinds, // Optional; assume all value if missing.
ImmutableArray<BoundExpression> arguments,// Required; in scenarios like method group conversions where there are
// no arguments per se we cons up some fake arguments.
ref HashSet<DiagnosticInfo> useSiteDiagnostics)
ref HashSet<DiagnosticInfo> useSiteDiagnostics,
bool includeNullability = false)
{
Debug.Assert(!methodTypeParameters.IsDefault);
Debug.Assert(methodTypeParameters.Length > 0);
......@@ -232,13 +234,13 @@ private enum Dependency
}
var inferrer = new MethodTypeInferrer(
binder.Conversions,
conversions,
methodTypeParameters,
constructedContainingTypeOfMethod,
formalParameterTypes,
formalParameterRefKinds,
arguments,
binder.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureStaticNullChecking));
includeNullability);
return inferrer.InferTypeArgs(binder, ref useSiteDiagnostics);
}
......
......@@ -356,7 +356,7 @@ private static bool OverloadResolutionResultIsValid<TMember>(ArrayBuilder<Member
return MemberAnalysisResult.UseSiteError();
}
var effectiveParameters = GetEffectiveParametersInNormalForm(constructor, arguments.Arguments.Count, argumentAnalysis.ArgsToParamsOpt, arguments.RefKinds, allowRefOmittedArguments: false);
var effectiveParameters = GetEffectiveParametersInNormalForm(constructor, arguments.Arguments.Count, argumentAnalysis.ArgsToParamsOpt, arguments.RefKinds, allowRefOmittedArguments: false, binder: _binder, hasAnyRefOmittedArgument: out _);
return IsApplicable(
constructor,
......@@ -388,7 +388,7 @@ private static bool OverloadResolutionResultIsValid<TMember>(ArrayBuilder<Member
return MemberAnalysisResult.UseSiteError();
}
var effectiveParameters = GetEffectiveParametersInExpandedForm(constructor, arguments.Arguments.Count, argumentAnalysis.ArgsToParamsOpt, arguments.RefKinds, allowRefOmittedArguments: false);
var effectiveParameters = GetEffectiveParametersInExpandedForm(constructor, arguments.Arguments.Count, argumentAnalysis.ArgsToParamsOpt, arguments.RefKinds, allowRefOmittedArguments: false, binder: _binder, hasAnyRefOmittedArgument: out _);
// A vararg ctor is never applicable in its expanded form because
// it is never a params method.
......@@ -2487,6 +2487,25 @@ private static bool IsUnsignedIntegralType(TypeSymbol type)
}
}
internal static void GetEffectiveParameterTypes(
MethodSymbol method,
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool allowRefOmittedArguments,
Binder binder,
bool expanded,
out ImmutableArray<TypeSymbolWithAnnotations> parameterTypes,
out ImmutableArray<RefKind> parameterRefKinds)
{
bool hasAnyRefOmittedArgument;
EffectiveParameters effectiveParameters = expanded ?
GetEffectiveParametersInExpandedForm(method, argumentCount, argToParamMap, argumentRefKinds, allowRefOmittedArguments, binder, out hasAnyRefOmittedArgument) :
GetEffectiveParametersInNormalForm(method, argumentCount, argToParamMap, argumentRefKinds, allowRefOmittedArguments, binder, out hasAnyRefOmittedArgument);
parameterTypes = effectiveParameters.ParameterTypes;
parameterRefKinds = effectiveParameters.ParameterRefKinds;
}
private struct EffectiveParameters
{
internal readonly ImmutableArray<TypeSymbolWithAnnotations> ParameterTypes;
......@@ -2499,24 +2518,13 @@ internal EffectiveParameters(ImmutableArray<TypeSymbolWithAnnotations> types, Im
}
}
private EffectiveParameters GetEffectiveParametersInNormalForm<TMember>(
TMember member,
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool allowRefOmittedArguments)
where TMember : Symbol
{
bool discarded;
return GetEffectiveParametersInNormalForm(member, argumentCount, argToParamMap, argumentRefKinds, allowRefOmittedArguments, hasAnyRefOmittedArgument: out discarded);
}
private EffectiveParameters GetEffectiveParametersInNormalForm<TMember>(
private static EffectiveParameters GetEffectiveParametersInNormalForm<TMember>(
TMember member,
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool allowRefOmittedArguments,
Binder binder,
out bool hasAnyRefOmittedArgument) where TMember : Symbol
{
Debug.Assert(argumentRefKinds != null);
......@@ -2549,10 +2557,10 @@ internal EffectiveParameters(ImmutableArray<TypeSymbolWithAnnotations> types, Im
continue;
}
var parameter = parameters[parm];
types.Add(_binder.GetTypeOrReturnTypeWithAdjustedNullableAnnotations(parameter));
types.Add(parameter.Type);
RefKind argRefKind = hasAnyRefArg ? argumentRefKinds[arg] : RefKind.None;
RefKind paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, allowRefOmittedArguments, ref hasAnyRefOmittedArgument);
RefKind paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, allowRefOmittedArguments, binder, ref hasAnyRefOmittedArgument);
if (refs == null)
{
......@@ -2572,7 +2580,7 @@ internal EffectiveParameters(ImmutableArray<TypeSymbolWithAnnotations> types, Im
return new EffectiveParameters(types.ToImmutableAndFree(), refKinds);
}
private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind argRefKind, bool allowRefOmittedArguments, ref bool hasAnyRefOmittedArgument)
private static RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind argRefKind, bool allowRefOmittedArguments, Binder binder, ref bool hasAnyRefOmittedArgument)
{
var paramRefKind = parameter.RefKind;
......@@ -2585,7 +2593,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
// Omit ref feature for COM interop: We can pass arguments by value for ref parameters if we are calling a method/property on an instance of a COM imported type.
// We must ignore the 'ref' on the parameter while determining the applicability of argument for the given method call.
// During argument rewriting, we will replace the argument value with a temporary local and pass that local by reference.
if (allowRefOmittedArguments && paramRefKind == RefKind.Ref && argRefKind == RefKind.None && !_binder.InAttributeArgument)
if (allowRefOmittedArguments && paramRefKind == RefKind.Ref && argRefKind == RefKind.None && !binder.InAttributeArgument)
{
hasAnyRefOmittedArgument = true;
return RefKind.None;
......@@ -2594,23 +2602,13 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
return paramRefKind;
}
private EffectiveParameters GetEffectiveParametersInExpandedForm<TMember>(
TMember member,
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool allowRefOmittedArguments) where TMember : Symbol
{
bool discarded;
return GetEffectiveParametersInExpandedForm(member, argumentCount, argToParamMap, argumentRefKinds, allowRefOmittedArguments, hasAnyRefOmittedArgument: out discarded);
}
private EffectiveParameters GetEffectiveParametersInExpandedForm<TMember>(
private static EffectiveParameters GetEffectiveParametersInExpandedForm<TMember>(
TMember member,
int argumentCount,
ImmutableArray<int> argToParamMap,
ArrayBuilder<RefKind> argumentRefKinds,
bool allowRefOmittedArguments,
Binder binder,
out bool hasAnyRefOmittedArgument) where TMember : Symbol
{
Debug.Assert(argumentRefKinds != null);
......@@ -2626,12 +2624,12 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
{
var parm = argToParamMap.IsDefault ? arg : argToParamMap[arg];
var parameter = parameters[parm];
var type = _binder.GetTypeOrReturnTypeWithAdjustedNullableAnnotations(parameter);
var type = parameter.Type;
types.Add(parm == parameters.Length - 1 ? ((ArrayTypeSymbol)type.TypeSymbol).ElementType : type);
var argRefKind = hasAnyRefArg ? argumentRefKinds[arg] : RefKind.None;
var paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, allowRefOmittedArguments, ref hasAnyRefOmittedArgument);
var paramRefKind = GetEffectiveParameterRefKind(parameter, argRefKind, allowRefOmittedArguments, binder, ref hasAnyRefOmittedArgument);
refs.Add(paramRefKind);
if (paramRefKind != RefKind.None)
......@@ -2692,6 +2690,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
allowRefOmittedArguments,
_binder,
out hasAnyRefOmittedArgument);
Debug.Assert(!hasAnyRefOmittedArgument || allowRefOmittedArguments);
......@@ -2702,7 +2701,9 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
arguments.Arguments.Count,
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
allowRefOmittedArguments);
allowRefOmittedArguments,
_binder,
out _);
// The member passed to the following call is returned in the result (possibly a constructed version of it).
// The applicability is checked based on effective parameters passed in.
......@@ -2759,6 +2760,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
allowRefOmittedArguments,
_binder,
out hasAnyRefOmittedArgument);
Debug.Assert(!hasAnyRefOmittedArgument || allowRefOmittedArguments);
......@@ -2769,7 +2771,9 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
arguments.Arguments.Count,
argumentAnalysis.ArgsToParamsOpt,
arguments.RefKinds,
allowRefOmittedArguments);
allowRefOmittedArguments,
_binder,
out _);
// The member passed to the following call is returned in the result (possibly a constructed version of it).
// The applicability is checked based on effective parameters passed in.
......@@ -2937,6 +2941,7 @@ private RefKind GetEffectiveParameterRefKind(ParameterSymbol parameter, RefKind
var inferenceResult = MethodTypeInferrer.Infer(
_binder,
_binder.Conversions,
originalTypeParameters,
method.ContainingType,
originalEffectiveParameters.ParameterTypes,
......
......@@ -227,6 +227,8 @@ internal static TypeSymbolWithAnnotations GetTypeAndNullability(this BoundExpres
case BoundKind.Literal:
case BoundKind.UnboundLambda:
break;
case BoundKind.ValuePlaceholder:
return ((BoundValuePlaceholder)expr).IsNullable;
default:
// PROTOTYPE(NullableReferenceTypes): Handle all expression kinds.
//Debug.Assert(false, "Unhandled expression: " + expr.Kind);
......
......@@ -1651,8 +1651,10 @@
<Field Name="Type" Type="TypeSymbol" Override="true" Null="always"/>
</Node>
<!-- Special node, used only during Data Flow Pass -->
<!-- Special node, used only during nullability flow analysis -->
<!-- PROTOTYPE(NullableReferenceTypes): Derive from BoundValuePlaceholderBase and give specific name. -->
<Node Name="BoundValuePlaceholder" Base="BoundExpression">
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="IsNullable" Type="bool?" Null="allow"/>
</Node>
</Tree>
......@@ -140,6 +140,7 @@ public TypeSymbolWithAnnotations InferredReturnType(ref HashSet<DiagnosticInfo>
}
else
{
// PROTOTYPE(NullableReferenceTypes): Should pass includeNullability: false.
bestResultType = BestTypeInferrer.InferBestType(resultTypes, binder.Conversions, includeNullability, ref useSiteDiagnostics);
}
......@@ -200,6 +201,7 @@ private BlockReturns(bool includeNullability, HashSet<TypeSymbolWithAnnotations>
_types = types;
}
// PROTOTYPE(NullableReferenceTypes): Remove includeNullability parameter.
public static ImmutableArray<TypeSymbolWithAnnotations> GetReturnTypes(bool includeNullability, BoundBlock block, out RefKind refKind, out int numberOfDistinctReturns)
{
var types = new HashSet<TypeSymbolWithAnnotations>(TypeSymbolWithAnnotations.EqualsComparer.Instance);
......
......@@ -1890,7 +1890,7 @@ internal static BoundCall GenerateBaseParameterlessConstructorInitializer(Method
argsToParamsOpt: ImmutableArray<int>.Empty,
resultKind: resultKind,
binderOpt: null,
type: baseType,
type: baseConstructor.ReturnType.TypeSymbol,
hasErrors: hasErrors)
{ WasCompilerGenerated = true };
}
......
......@@ -65,7 +65,7 @@ private new List<Symbol> Analyze(ref bool badRegion)
return result;
}
protected override void WriteArgument(BoundExpression arg, RefKind refKind, MethodSymbol method, ParameterSymbol parameter)
protected override void WriteArgument(BoundExpression arg, RefKind refKind, MethodSymbol method)
{
// ref parameter does not "always" assign.
if (refKind == RefKind.Out)
......
......@@ -18,7 +18,7 @@ public VariableIdentifier(Symbol symbol, int containingSlot = 0)
{
Debug.Assert(symbol.Kind == SymbolKind.Local || symbol.Kind == SymbolKind.Field || symbol.Kind == SymbolKind.Parameter ||
(symbol as MethodSymbol)?.MethodKind == MethodKind.LocalFunction ||
symbol.Kind == SymbolKind.Property);
symbol.Kind == SymbolKind.Property || symbol.Kind == SymbolKind.Event);
Symbol = symbol;
ContainingSlot = containingSlot;
}
......
......@@ -1751,7 +1751,7 @@ public override BoundNode VisitAddressOfOperator(BoundAddressOfOperator node)
return null;
}
protected override void WriteArgument(BoundExpression arg, RefKind refKind, MethodSymbol method, ParameterSymbol parameter)
protected override void WriteArgument(BoundExpression arg, RefKind refKind, MethodSymbol method)
{
if (refKind == RefKind.Ref)
{
......
......@@ -176,7 +176,7 @@ protected Symbol GetNonMemberSymbol(int slot)
VariableIdentifier variableId = variableBySlot[slot];
while (variableId.ContainingSlot > 0)
{
Debug.Assert(variableId.Symbol.Kind == SymbolKind.Field || variableId.Symbol.Kind == SymbolKind.Property);
Debug.Assert(variableId.Symbol.Kind == SymbolKind.Field || variableId.Symbol.Kind == SymbolKind.Property || variableId.Symbol.Kind == SymbolKind.Event);
variableId = variableBySlot[variableId.ContainingSlot];
}
return variableId.Symbol;
......@@ -269,6 +269,8 @@ protected static TypeSymbolWithAnnotations VariableType(Symbol s)
return null;
case SymbolKind.Property:
return ((PropertySymbol)s).Type;
case SymbolKind.Event:
return ((EventSymbol)s).Type;
default:
throw ExceptionUtilities.UnexpectedValue(s.Kind);
}
......
......@@ -6187,33 +6187,37 @@ public OutDeconstructVarPendingInference Update()
internal sealed partial class BoundValuePlaceholder : BoundExpression
{
public BoundValuePlaceholder(SyntaxNode syntax, TypeSymbol type, bool hasErrors)
public BoundValuePlaceholder(SyntaxNode syntax, bool? isNullable, TypeSymbol type, bool hasErrors)
: base(BoundKind.ValuePlaceholder, syntax, type, hasErrors)
{
Debug.Assert(type != null, "Field 'type' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
this.IsNullable = isNullable;
}
public BoundValuePlaceholder(SyntaxNode syntax, TypeSymbol type)
public BoundValuePlaceholder(SyntaxNode syntax, bool? isNullable, TypeSymbol type)
: base(BoundKind.ValuePlaceholder, syntax, type)
{
Debug.Assert(type != null, "Field 'type' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
this.IsNullable = isNullable;
}
public bool? IsNullable { get; }
public override BoundNode Accept(BoundTreeVisitor visitor)
{
return visitor.VisitValuePlaceholder(this);
}
public BoundValuePlaceholder Update(TypeSymbol type)
public BoundValuePlaceholder Update(bool? isNullable, TypeSymbol type)
{
if (type != this.Type)
if (isNullable != this.IsNullable || type != this.Type)
{
var result = new BoundValuePlaceholder(this.Syntax, type, this.HasErrors);
var result = new BoundValuePlaceholder(this.Syntax, isNullable, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated;
return result;
}
......@@ -9441,7 +9445,7 @@ public override BoundNode VisitOutDeconstructVarPendingInference(OutDeconstructV
public override BoundNode VisitValuePlaceholder(BoundValuePlaceholder node)
{
TypeSymbol type = this.VisitType(node.Type);
return node.Update(type);
return node.Update(node.IsNullable, type);
}
}
......@@ -11023,6 +11027,7 @@ public override TreeDumperNode VisitValuePlaceholder(BoundValuePlaceholder node,
{
return new TreeDumperNode("valuePlaceholder", null, new TreeDumperNode[]
{
new TreeDumperNode("isNullable", node.IsNullable, null),
new TreeDumperNode("type", node.Type, null)
}
);
......
......@@ -5812,24 +5812,24 @@ class CL1
", parseOptions: TestOptions.Regular8);
c.VerifyDiagnostics(
// (13,14): warning CS8619: Nullability of reference types in value of type 'CL1?[]' doesn't match target type 'CL1[]'.
// u1 = new [] { y1, z1 };
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new [] { y1, z1 }").WithArguments("CL1?[]", "CL1[]").WithLocation(13, 14),
// (14,14): warning CS8619: Nullability of reference types in value of type 'CL1?[*,*]' doesn't match target type 'CL1[*,*]'.
// v1 = new [,] { {y1}, {z1} };
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new [,] { {y1}, {z1} }").WithArguments("CL1?[*,*]", "CL1[*,*]").WithLocation(14, 14),
// (25,14): warning CS8619: Nullability of reference types in value of type 'CL1?[]' doesn't match target type 'CL1[]'.
// u2 = a2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "a2").WithArguments("CL1?[]", "CL1[]").WithLocation(25, 14),
// (26,14): warning CS8619: Nullability of reference types in value of type 'CL1?[*,*]' doesn't match target type 'CL1[*,*]'.
// v2 = b2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b2").WithArguments("CL1?[*,*]", "CL1[*,*]").WithLocation(26, 14),
// (31,21): warning CS8619: Nullability of reference types in value of type 'CL1?[]' doesn't match target type 'CL1[]'.
// CL1 [] x8 = new [] { y8, z8 };
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new [] { y8, z8 }").WithArguments("CL1?[]", "CL1[]").WithLocation(31, 21),
// (36,22): warning CS8619: Nullability of reference types in value of type 'CL1?[*,*]' doesn't match target type 'CL1[*,*]'.
// CL1 [,] x9 = new [,] { {y9}, {z9} };
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new [,] { {y9}, {z9} }").WithArguments("CL1?[*,*]", "CL1[*,*]").WithLocation(36, 22)
// (13,14): warning CS8619: Nullability of reference types in value of type 'CL1?[]' doesn't match target type 'CL1[]'.
// u1 = new [] { y1, z1 };
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new [] { y1, z1 }").WithArguments("CL1?[]", "CL1[]").WithLocation(13, 14),
// (14,14): warning CS8619: Nullability of reference types in value of type 'CL1?[*,*]' doesn't match target type 'CL1[*,*]'.
// v1 = new [,] { {y1}, {z1} };
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new [,] { {y1}, {z1} }").WithArguments("CL1?[*,*]", "CL1[*,*]").WithLocation(14, 14),
// (25,14): warning CS8619: Nullability of reference types in value of type 'CL1?[]' doesn't match target type 'CL1[]'.
// u2 = a2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "a2").WithArguments("CL1?[]", "CL1[]").WithLocation(25, 14),
// (26,14): warning CS8619: Nullability of reference types in value of type 'CL1?[*,*]' doesn't match target type 'CL1[*,*]'.
// v2 = b2;
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b2").WithArguments("CL1?[*,*]", "CL1[*,*]").WithLocation(26, 14),
// (31,21): warning CS8619: Nullability of reference types in value of type 'CL1?[]' doesn't match target type 'CL1[]'.
// CL1 [] x8 = new [] { y8, z8 };
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new [] { y8, z8 }").WithArguments("CL1?[]", "CL1[]").WithLocation(31, 21),
// (36,22): warning CS8619: Nullability of reference types in value of type 'CL1?[*,*]' doesn't match target type 'CL1[*,*]'.
// CL1 [,] x9 = new [,] { {y9}, {z9} };
Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "new [,] { {y9}, {z9} }").WithArguments("CL1?[*,*]", "CL1[*,*]").WithLocation(36, 22)
);
}
......@@ -8428,9 +8428,12 @@ class CL1
", new[] { CSharpRef, SystemCoreRef }, parseOptions: TestOptions.Regular8);
c.VerifyDiagnostics(
// (15,17): warning CS8601: Possible null reference assignment.
// z2[0] = y2;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y2").WithLocation(15, 17)
// (14,26): warning CS8601: Possible null reference assignment.
// x2[(dynamic)0] = y2;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y2").WithLocation(14, 26),
// (15,17): warning CS8601: Possible null reference assignment.
// z2[0] = y2;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y2").WithLocation(15, 17)
);
}
......@@ -8865,6 +8868,25 @@ void Test3(dynamic? x3)
);
}
[Fact]
public void DynamicMemberAccess_02()
{
// PROTOTYPE(NullableReferenceTypes): Consider adding test infrastructure to verify
// nullability based on /*[...]*/ annotations such as [dynamic], [dynamic!], [dynamic?].
var source =
@"class C
{
static void M(dynamic x)
{
x.F/*[dynamic]*/.ToString();
var y/*[dynamic]*/ = x.F;
y = null;
}
}";
var comp = CreateCompilationWithMscorlibAndSystemCore(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
}
[Fact]
public void DynamicObjectCreationExpression_01()
{
......@@ -9300,9 +9322,6 @@ class CL0
// (10,19): warning CS8604: Possible null reference argument for parameter 'x' in 'CL0 CL0.operator &(CL0 x, CL0? y)'.
// CL0? z1 = x1 && y1;
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x1").WithArguments("x", "CL0 CL0.operator &(CL0 x, CL0? y)").WithLocation(10, 19),
// (11,18): warning CS8601: Possible null reference assignment.
// CL0 u1 = z1;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "z1").WithLocation(11, 18),
// (17,18): hidden CS8607: Expression is probably never null.
// CL0 u2 = z2 ?? new CL0();
Diagnostic(ErrorCode.HDN_ExpressionIsProbablyNeverNull, "z2").WithLocation(17, 18)
......@@ -9570,12 +9589,6 @@ class CL0
", parseOptions: TestOptions.Regular8);
c.VerifyDiagnostics(
// (10,19): warning CS8604: Possible null reference argument for parameter 'x' in 'bool CL0.operator true(CL0 x)'.
// CL0? u1 = x1 && y1 || z1;
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x1 && y1").WithArguments("x", "bool CL0.operator true(CL0 x)").WithLocation(10, 19),
// (10,19): warning CS8604: Possible null reference argument for parameter 'x' in 'CL0 CL0.operator |(CL0 x, CL0? y)'.
// CL0? u1 = x1 && y1 || z1;
Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x1 && y1").WithArguments("x", "CL0 CL0.operator |(CL0 x, CL0? y)").WithLocation(10, 19)
);
}
......@@ -9702,6 +9715,48 @@ class CL0
);
}
[Fact]
public void BinaryOperator_13()
{
CSharpCompilation c = CreateStandardCompilation(@"
class C
{
static void Main()
{
}
void Test1(CL0 x1, CL0 y1)
{
CL0 z1 = x1 && y1;
}
}
class CL0
{
public static CL0? operator &(CL0 x, CL0 y)
{
return new CL0();
}
public static bool operator true(CL0 x)
{
return false;
}
public static bool operator false(CL0? x)
{
return false;
}
}
", parseOptions: TestOptions.Regular8);
c.VerifyDiagnostics(
// (10,18): warning CS8601: Possible null reference assignment.
// CL0 z1 = x1 && y1;
Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x1 && y1").WithLocation(10, 18)
);
}
[Fact]
public void MethodGroupConversion_01()
{
......@@ -11224,7 +11279,9 @@ void Test7(D2? x7)
);
}
[Fact]
// PROTOTYPE(NullableReferenceTypes): Events are not tracked for structs.
// (This should be fixed if/when struct member state is populated lazily.)
[Fact(Skip = "TODO")]
public void Events_02()
{
CSharpCompilation c = CreateStandardCompilation(@"
......@@ -11278,7 +11335,9 @@ void Test3(System.Action x3)
);
}
[Fact]
// PROTOTYPE(NullableReferenceTypes): Events are not tracked for structs.
// (This should be fixed if/when struct member state is populated lazily.)
[Fact(Skip = "TODO")]
public void Events_03()
{
CSharpCompilation c = CreateStandardCompilation(@"
......@@ -17168,5 +17227,62 @@ void M()
// _value = _f.GetHashCode();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "_f").WithLocation(16, 22));
}
[Fact]
public void Pointer()
{
var source =
@"class C
{
static unsafe void F(int* p)
{
*p = 0;
}
}";
var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular8, options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics();
}
[Fact]
public void IncrementWithErrors()
{
var source =
@"using System.Threading.Tasks;
class C
{
static async Task<int> F(ref int i)
{
return await Task.Run(() => i++);
}
}";
var comp = CreateCompilationWithMscorlib46(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (4,38): error CS1988: Async methods cannot have ref or out parameters
// static async Task<int> F(ref int i)
Diagnostic(ErrorCode.ERR_BadAsyncArgType, "i").WithLocation(4, 38),
// (6,37): error CS1628: Cannot use ref or out parameter 'i' inside an anonymous method, lambda expression, or query expression
// return await Task.Run(() => i++);
Diagnostic(ErrorCode.ERR_AnonDelegateCantUse, "i").WithArguments("i").WithLocation(6, 37));
}
[Fact]
public void NullCastToValueType()
{
var source =
@"struct S { }
class C
{
static void M()
{
S s = (S)null;
s.ToString();
}
}";
var comp = CreateStandardCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (6,15): error CS0037: Cannot convert null to 'S' because it is a non-nullable value type
// S s = (S)null;
Diagnostic(ErrorCode.ERR_ValueCantBeNull, "(S)null").WithArguments("S").WithLocation(6, 15));
}
}
}
......@@ -1120,7 +1120,9 @@ static void G(IOut<string> x, IOut<string?> y)
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(y, y)").WithLocation(37, 9));
}
[Fact]
// PROTOTYPE(NullableReferenceTypes): Currently reporting WRN_NullabilityMismatchInArgument
// passing (string, string?) to (string?, string?).
[Fact(Skip = "TODO")]
public void TupleTypeInference_01()
{
var source =
......@@ -1151,7 +1153,9 @@ static void G(string x, string? y)
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F((y, y)).Item2").WithLocation(9, 9));
}
[Fact]
// PROTOTYPE(NullableReferenceTypes): Currently reporting WRN_NullabilityMismatchInArgument
// passing (string, string?) to (string?, string?).
[Fact(Skip = "TODO")]
public void TupleTypeInference_02()
{
var source =
......@@ -1662,7 +1666,10 @@ static void F(object o)
comp.VerifyDiagnostics(
// (13,22): error CS1061: '(object?, int)' does not contain a definition for 'x' and no extension method 'x' accepting a first argument of type '(object?, int)' could be found (are you missing a using directive or an assembly reference?)
// c.F((o, -1)).x.ToString();
Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "x").WithArguments("(object?, int)", "x").WithLocation(13, 22));
Diagnostic(ErrorCode.ERR_NoSuchMemberOrExtension, "x").WithArguments("(object?, int)", "x").WithLocation(13, 22),
// (13,13): warning CS8620: Nullability of reference types in argument of type '(object o, int)' doesn't match target type '(object?, int)' for parameter 't' in '(object?, int) E.F<(object?, int)>(C<(object?, int)> c, (object?, int) t)'.
// c.F((o, -1)).x.ToString();
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "(o, -1)").WithArguments("(object o, int)", "(object?, int)", "t", "(object?, int) E.F<(object?, int)>(C<(object?, int)> c, (object?, int) t)").WithLocation(13, 13));
}
[Fact]
......@@ -1721,7 +1728,10 @@ static void F(dynamic x, object y)
source,
references: new[] { ValueTupleRef, SystemRuntimeFacadeRef },
parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
comp.VerifyDiagnostics(
// (13,13): warning CS8620: Nullability of reference types in argument of type '(dynamic x, object y)' doesn't match target type '(dynamic, object?)' for parameter 't' in '(dynamic, object?) E.F<(dynamic, object?)>(C<(dynamic, object?)> c, (dynamic, object?) t)'.
// c.F((x, y)).Item1.G();
Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "(x, y)").WithArguments("(dynamic x, object y)", "(dynamic, object?)", "t", "(dynamic, object?) E.F<(dynamic, object?)>(C<(dynamic, object?)> c, (dynamic, object?) t)").WithLocation(13, 13));
}
// Assert failure in ConversionsBase.IsValidExtensionMethodThisArgConversion.
......@@ -1767,15 +1777,17 @@ static void G()
object? y = x;
F(x).ToString();
F(y).ToString();
y = null;
F(y).ToString();
}
}";
var comp = CreateStandardCompilation(
source,
parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics(
// (9,9): warning CS8602: Possible dereference of a null reference.
// (11,9): warning CS8602: Possible dereference of a null reference.
// F(y).ToString();
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(y)").WithLocation(9, 9));
Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "F(y)").WithLocation(11, 9));
}
[Fact]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册