diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index 4ce3903ef64ac136f9fd98f3d484478ac932c7fd..b258dc2576e1a1aba49b515a65b0e05cacba3468 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -284,23 +284,6 @@ internal static bool IsTypeOrValueExpression(BoundExpression expression) } } - private static bool IsLegalSuppressionValueKind(BindValueKind valueKind) - { - // Need to review allowed uses of the suppression operator - // Tracked by https://github.com/dotnet/roslyn/issues/31297 - - switch (valueKind) - { - case BindValueKind.RValue: - case BindValueKind.RValueOrMethodGroup: - case BindValueKind.RefOrOut: - return true; - } - - // all others are illegal - return false; - } - /// /// The purpose of this method is to determine if the expression satisfies desired capabilities. /// If it is not then this code gives an appropriate error message. @@ -323,12 +306,6 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin return false; } - if (expr.IsSuppressed && !IsLegalSuppressionValueKind(valueKind)) - { - Error(diagnostics, ErrorCode.ERR_IllegalSuppression, node); - return false; - } - switch (expr.Kind) { // we need to handle properties and event in a special way even in an RValue case because of getters diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index 0fd2b5d06bbff1a54f7b1377dfabd3d195d784a9..960c7e049c895c9c37a2c1963f7a5984d3c67d57 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -238,12 +238,12 @@ private BoundExpression BindArgListOperator(InvocationExpressionSyntax node, Dia // Either we have a dynamic method group invocation "dyn.M(...)" or // a dynamic delegate invocation "dyn(...)" -- either way, bind it as a dynamic // invocation and let the lowering pass sort it out. - reportSuppressionIfPresent(); + ReportSuppressionIfNeeded(boundExpression, diagnostics); result = BindDynamicInvocation(node, boundExpression, analyzedArguments, ImmutableArray.Empty, diagnostics, queryClause); } else if (boundExpression.Kind == BoundKind.MethodGroup) { - reportSuppressionIfPresent(); + ReportSuppressionIfNeeded(boundExpression, diagnostics); result = BindMethodGroupInvocation( node, expression, methodName, (BoundMethodGroup)boundExpression, analyzedArguments, diagnostics, queryClause, allowUnexpandedForm: allowUnexpandedForm, anyApplicableCandidates: out _); @@ -270,14 +270,6 @@ private BoundExpression BindArgListOperator(InvocationExpressionSyntax node, Dia CheckRestrictedTypeReceiver(result, this.Compilation, diagnostics); return result; - - void reportSuppressionIfPresent() - { - if (boundExpression.IsSuppressed) - { - Error(diagnostics, ErrorCode.ERR_IllegalSuppression, boundExpression.Syntax); - } - } } private BoundExpression BindDynamicInvocation( diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs index 3b766e66910487098c8d867aff72ef1cf9045f26..96a8828dee756cfcd3b30e4d736ea9fbfc3b30c5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs @@ -18,6 +18,7 @@ private BoundExpression BindCompoundAssignment(AssignmentExpressionSyntax node, node.Left.CheckDeconstructionCompatibleArgument(diagnostics); BoundExpression left = BindValue(node.Left, diagnostics, GetBinaryAssignmentKind(node.Kind())); + ReportSuppressionIfNeeded(left, diagnostics); BoundExpression right = BindValue(node.Right, diagnostics, BindValueKind.RValue); BinaryOperatorKind kind = SyntaxKindToBinaryOperatorKind(node.Kind()); @@ -2105,6 +2106,7 @@ private static void BindPointerIndirectionExpressionInternal(CSharpSyntaxNode no private BoundExpression BindAddressOfExpression(PrefixUnaryExpressionSyntax node, DiagnosticBag diagnostics) { BoundExpression operand = BindValue(node.Operand, diagnostics, BindValueKind.AddressOf); + ReportSuppressionIfNeeded(operand, diagnostics); bool hasErrors = operand.HasAnyErrors; // This would propagate automatically, but by reading it explicitly we can reduce cascading. bool isFixedStatementAddressOfExpression = SyntaxFacts.IsFixedStatementExpression(node); @@ -2283,6 +2285,14 @@ private BoundExpression BindUnaryOperator(PrefixUnaryExpressionSyntax node, Diag return constant ?? BindUnaryOperatorCore(node, node.OperatorToken.Text, operand, diagnostics); } + private void ReportSuppressionIfNeeded(BoundExpression expr, DiagnosticBag diagnostics) + { + if (expr.IsSuppressed) + { + Error(diagnostics, ErrorCode.ERR_IllegalSuppression, expr.Syntax); + } + } + private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string operatorText, BoundExpression operand, DiagnosticBag diagnostics) { UnaryOperatorKind kind = SyntaxKindToUnaryOperatorKind(node.Kind()); @@ -3569,6 +3579,7 @@ private BoundExpression BindNullCoalescingOperator(BinaryExpressionSyntax node, private BoundExpression BindNullCoalescingAssignmentOperator(AssignmentExpressionSyntax node, DiagnosticBag diagnostics) { BoundExpression leftOperand = BindValue(node.Left, diagnostics, BindValueKind.CompoundAssignment); + ReportSuppressionIfNeeded(leftOperand, diagnostics); BoundExpression rightOperand = BindValue(node.Right, diagnostics, BindValueKind.RValue); // If either operand is bad, bail out preventing more cascading errors diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs index 196528f1fa70f93f54c09646e329bf7b0bf25f54..cdb1660148fc93513a21795e6a8c20f979146ec2 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Statements.cs @@ -586,6 +586,7 @@ private BoundExpressionStatement BindExpressionStatement(CSharpSyntaxNode node, BoundExpressionStatement expressionStatement; var expression = BindValue(syntax, diagnostics, BindValueKind.RValue); + ReportSuppressionIfNeeded(expression, diagnostics); if (!allowsAnyExpression && !IsValidStatementExpression(syntax, expression)) { if (!node.HasErrors) @@ -1324,6 +1325,7 @@ private BoundExpression BindAssignment(AssignmentExpressionSyntax node, Diagnost } var op1 = BindValue(node.Left, diagnostics, lhsKind); + ReportSuppressionIfNeeded(op1, diagnostics); var lhsRefKind = RefKind.None; // If the LHS is a ref (not ref-readonly), the rhs diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs index 574a8dee9e070c40fe9f7320d9d4e7277b73a6d3..e919d19f976d5fbd4dd88607e71264a8742a26df 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs +++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs @@ -15017,7 +15017,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types.. + /// Looks up a localized string similar to Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types.. /// internal static string WRN_NullabilityMismatchInArgument { get { @@ -15026,7 +15026,7 @@ internal class CSharpResources { } /// - /// Looks up a localized string similar to Argument cannot be used as an input for parameter due to differences in the nullability of reference types.. + /// Looks up a localized string similar to Argument cannot be used for parameter due to differences in the nullability of reference types.. /// internal static string WRN_NullabilityMismatchInArgument_Title { get { diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index eee66e9bcd101797c45cd7a3baa4b96ba80bbf9d..342abbcedffabd3061410d10d11ec3c1d042da78 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -5422,10 +5422,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ A null literal introduces a null value for a type parameter. - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. Argument of type '{0}' cannot be used as an output of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs index dc11aff8743238d5c80e7d1b9b746676cdcd8a4c..e518b0dbbf059d656f26e536fe8ec9947852165a 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/NullableWalker.cs @@ -1169,7 +1169,15 @@ protected override BoundNode VisitReturnStatementNoAdjust(BoundReturnStatement n if (_returnTypesOpt == null && TryGetReturnType(out TypeSymbolWithAnnotations returnType)) { - VisitOptionalImplicitConversion(expr, returnType, useLegacyWarnings: false, AssignmentKind.Return); + if (node.RefKind == RefKind.None) + { + VisitOptionalImplicitConversion(expr, returnType, useLegacyWarnings: false, AssignmentKind.Return); + } + else + { + // return ref expr; + VisitRefExpression(expr, returnType); + } } else { @@ -1183,6 +1191,28 @@ protected override BoundNode VisitReturnStatementNoAdjust(BoundReturnStatement n return null; } + private TypeWithState VisitRefExpression(BoundExpression expr, TypeSymbolWithAnnotations destinationType) + { + Visit(expr); + TypeWithState resultType = ResultType; + if (!expr.IsSuppressed && RemoveConversion(expr, includeExplicitConversions: false).expression.Kind != BoundKind.ThrowExpression) + { + var lvalueResultType = LvalueResultType; + if (IsNullabilityMismatch(lvalueResultType, destinationType)) + { + // declared types must match + ReportNullabilityMismatchInAssignment(expr.Syntax, lvalueResultType, destinationType); + } + else + { + // types match, but state would let a null in + ReportNullableAssignmentIfNecessary(expr, destinationType, resultType, useLegacyWarnings: false); + } + } + + return resultType; + } + private bool TryGetReturnType(out TypeSymbolWithAnnotations type) { var method = (MethodSymbol)_symbol; @@ -1238,18 +1268,26 @@ public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node) bool inferredType = node.DeclaredType.InferredType; TypeSymbolWithAnnotations type = local.Type; - TypeWithState valueType = VisitOptionalImplicitConversion(initializer, targetTypeOpt: inferredType ? default : type, useLegacyWarnings: true, AssignmentKind.Assignment); - - if (inferredType) + TypeWithState valueType; + if (local.IsRef) + { + valueType = VisitRefExpression(initializer, type); + } + else { - if (valueType.HasNullType) + valueType = VisitOptionalImplicitConversion(initializer, targetTypeOpt: inferredType ? default : type, useLegacyWarnings: true, AssignmentKind.Assignment); + + if (inferredType) { - Debug.Assert(type.IsErrorType()); - valueType = type.ToTypeWithState(); - } + if (valueType.HasNullType) + { + Debug.Assert(type.IsErrorType()); + valueType = type.ToTypeWithState(); + } - type = valueType.ToTypeSymbolWithAnnotations(); - _variableTypes[local] = type; + type = valueType.ToTypeSymbolWithAnnotations(); + _variableTypes[local] = type; + } } TrackNullableStateForAssignment(initializer, type, slot, valueType, MakeSlot(initializer)); @@ -2836,6 +2874,9 @@ void visitArgumentEvaluateAndUnsplit(int argumentIndex, bool assertsTrue, bool a VisitResult result, bool extensionMethodThisArgument) { + // Note: we allow for some variance in `in` and `out` cases. Unlike in binding, we're not + // limited by CLR constraints. + var resultType = result.RValueType; bool reported = false; switch (refKind) @@ -2861,20 +2902,31 @@ void visitArgumentEvaluateAndUnsplit(int argumentIndex, bool assertsTrue, bool a { if (!argument.IsSuppressed) { - reported = ReportNullableAssignmentIfNecessary(argument, parameterType, resultType, - useLegacyWarnings: false, AssignmentKind.Argument, target: parameter); - if (!reported) + var lvalueResultType = result.LValueType; + if (IsNullabilityMismatch(lvalueResultType, parameterType)) { - HashSet useSiteDiagnostics = null; - if (!_conversions.HasIdentityOrImplicitReferenceConversion(resultType.Type, parameterType.TypeSymbol, ref useSiteDiagnostics)) - { - ReportNullabilityMismatchInArgument(argument, resultType.Type, parameter, parameterType.TypeSymbol, forOutput: false); - reported = true; - } + // declared types must match + ReportNullabilityMismatchInRefArgument(argument, argumentType: lvalueResultType, parameter, parameterType); + } + else + { + // types match, but state would let a null in + ReportNullableAssignmentIfNecessary(argument, parameterType, resultType, useLegacyWarnings: false); } } + + // Check assignment from a fictional value from the parameter to the argument. + var parameterWithState = parameterType.ToTypeWithState(); + if (argument.IsSuppressed) + { + parameterWithState = parameterWithState.WithNotNullState(); + } + + var parameterValue = new BoundParameter(argument.Syntax, parameter); + var lValueType = result.LValueType; + TrackNullableStateForAssignment(parameterValue, lValueType, MakeSlot(argument), parameterWithState); } - goto case RefKind.Out; + break; case RefKind.Out: { var parameterWithState = parameterType.ToTypeWithState(); @@ -2884,8 +2936,7 @@ void visitArgumentEvaluateAndUnsplit(int argumentIndex, bool assertsTrue, bool a } var lValueType = result.LValueType; - // The argument and the parameter may have different nested or top-level nullabilities, - // so we're going to check assignment from a fictional value from the parameter to the argument. + // Check assignment from a fictional value from the parameter to the argument. var parameterValue = new BoundParameter(argument.Syntax, parameter); if (!argument.IsSuppressed && !reported) @@ -4165,7 +4216,16 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) } else { - TypeWithState rightType = VisitOptionalImplicitConversion(right, leftLValueType, UseLegacyWarnings(left), AssignmentKind.Assignment); + TypeWithState rightType; + if (!node.IsRef) + { + rightType = VisitOptionalImplicitConversion(right, leftLValueType, UseLegacyWarnings(left), AssignmentKind.Assignment); + } + else + { + rightType = VisitRefExpression(right, leftLValueType); + } + TrackNullableStateForAssignment(right, leftLValueType, MakeSlot(left), rightType, MakeSlot(right)); SetResult(new TypeWithState(leftLValueType.TypeSymbol, rightType.State), leftLValueType); } @@ -4604,6 +4664,14 @@ private void ReportArgumentWarnings(BoundExpression argument, TypeWithState argu } } + private void ReportNullabilityMismatchInRefArgument(BoundExpression argument, TypeSymbolWithAnnotations argumentType, ParameterSymbol parameter, TypeSymbolWithAnnotations parameterType) + { + ReportSafetyDiagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, + argument.Syntax, argumentType, parameterType, + new FormattedSymbol(parameter, SymbolDisplayFormat.ShortFormat), + new FormattedSymbol(parameter.ContainingSymbol, SymbolDisplayFormat.MinimallyQualifiedFormat)); + } + /// /// Report warning passing argument where nested nullability does not match /// parameter (e.g.: calling `void F(object[] o)` with `F(new[] { maybeNull })`). @@ -4762,33 +4830,52 @@ protected override void VisitForEachExpression(BoundForEachStatement node) public override void VisitForEachIterationVariables(BoundForEachStatement node) { // declare and assign all iteration variables + TypeSymbolWithAnnotations sourceType = node.EnumeratorInfoOpt?.ElementType ?? default; + TypeWithState sourceState = sourceType.ToTypeWithState(); foreach (var iterationVariable in node.IterationVariables) { - TypeWithState sourceType = node.EnumeratorInfoOpt?.ElementType.ToTypeWithState() ?? default; var state = NullableFlowState.NotNull; - if (!sourceType.HasNullType) + if (!sourceState.HasNullType) { TypeSymbolWithAnnotations destinationType = iterationVariable.Type; - HashSet useSiteDiagnostics = null; - Conversion conversion = _conversions.ClassifyImplicitConversionFromType(sourceType.Type, destinationType.TypeSymbol, ref useSiteDiagnostics); - TypeWithState result = ApplyConversion( - node.IterationVariableType, - operandOpt: null, - conversion, - destinationType, - sourceType, - checkConversion: false, - fromExplicitCast: false, - useLegacyWarnings: false, - AssignmentKind.Assignment, - reportTopLevelWarnings: false, - reportRemainingWarnings: false); - if (destinationType.IsReferenceType && destinationType.NullableAnnotation.IsAnyNotNullable() && result.MaybeNull) + + if (iterationVariable.IsRef) { - ReportNonSafetyDiagnostic(node.IterationVariableType.Syntax); + // foreach (ref DestinationType variable in collection) + if (IsNullabilityMismatch(sourceType, destinationType)) + { + var foreachSyntax = (ForEachStatementSyntax)node.Syntax; + ReportNullabilityMismatchInAssignment(foreachSyntax.Type, sourceType, destinationType); + } + state = sourceState.State; } + else + { + // foreach (DestinationType variable in collection) + // foreach (var variable in collection) + // foreach (var (..., ...) in collection) + // and asynchronous variants + HashSet useSiteDiagnostics = null; + Conversion conversion = _conversions.ClassifyImplicitConversionFromType(sourceType.TypeSymbol, destinationType.TypeSymbol, ref useSiteDiagnostics); + TypeWithState result = ApplyConversion( + node.IterationVariableType, + operandOpt: null, + conversion, + destinationType, + sourceState, + checkConversion: false, + fromExplicitCast: false, + useLegacyWarnings: false, + AssignmentKind.Assignment, + reportTopLevelWarnings: false, + reportRemainingWarnings: false); + if (destinationType.IsReferenceType && destinationType.NullableAnnotation.IsAnyNotNullable() && result.MaybeNull) + { + ReportNonSafetyDiagnostic(node.IterationVariableType.Syntax); + } - state = result.State; + state = result.State; + } } int slot = GetOrCreateSlot(iterationVariable); diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 50f7cc9eaf00bce6fd234d5a768459835a98016a..00c974bed8cda450c367a334211fe0992b277104 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. Typ odkazu s možnou hodnotou null v argumentu typu {0} neodpovídá cílovému typu {1} parametru {2} v {3}. @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. Typ odkazu s možnou hodnotou null v argumentu neodpovídá cílovému typu. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 301d939f74a4d0600f453a93c154ac5c4dc5afb1..b1e26fd3314d747f72708d09d74de27b2eeaad37 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. Die NULL-Zulässigkeit von Verweistypen im Argument vom Typ "{0}" entspricht nicht dem Zieltyp "{1}" für den Parameter "{2}" in "{3}". @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. Die NULL-Zulässigkeit von Verweistypen im Argument entspricht nicht dem Zieltyp. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index 53c4012a750b3f2d84859209758e791d63a10c80..fc4997eebad7b80a9e3cf620d664617484766ee4 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. La nulabilidad de los tipos de referencia del argumento de tipo "{0}" no coincide con el tipo de destino "{1}" para el parámetro "{2}" en "{3}". @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. La nulabilidad de los tipos de referencia del argumento no coincide con el tipo de destino diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index 69fc28d5caf7caf39147edc4672a4e2519d5e42e..f5dda8cc53aba2a81b369eba3795e5263e1eaad9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. La nullabilité des types référence dans l'argument de type '{0}' ne correspond pas au type cible '{1}' pour le paramètre '{2}' dans '{3}'. @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. La nullabilité des types référence dans l'argument ne correspond pas au type cible. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 0024f28a1735c9870ad5df4ea12ebad89d1510ad..2aa4acd43a319d28c61a1376b60acd41020e9c26 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. Il supporto dei valori Null dei tipi riferimento nell'argomento di tipo '{0}' non corrisponde al tipo di destinazione '{1}' per il parametro '{2}' in '{3}'. @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. Il supporto dei valori Null dei tipi riferimento nell'argomento non corrisponde al tipo di destinazione. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index fc1cc59f1bb9fc8526b969614b65aed061d7dbc9..87d44cb914ae97f810560c6cfb8bb80e543641d9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. '{0}' 型の引数における参照型の Null 許容性が、'{3}' 内のパラメーター '{2}' に関する対象の型 '{1}' と一致しません。 @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. 引数における参照型の Null 許容性が、対象の型と一致しません。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 6ccd5b163b4760ce94b896da5ba04657e3b96251..ec0e4cf00721d0ea2dddb43d5c6dc79cb600acc6 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. '{0}' 형식의 인수에 있는 참조 형식 Null 허용 여부가 '{3}'의 매개 변수 '{2}'에 대한 '{1}' 대상 형식과 일치하지 않습니다. @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. 인수에 있는 참조 형식 Null 허용 여부가 대상 형식과 일치하지 않습니다. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index 60840b4b2a43ea4eac9c274b7bbcc94b0509ee4a..37fa225a3695cff88d3269d820257ae51cc0ae21 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. Obsługa wartości null dla typów referencyjnych w argumencie typu „{0}” jest niezgodna z typem docelowym „{1}” dla parametru „{2}” w „{3}”. @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. Obsługa wartości null dla typów referencyjnych w argumencie jest niezgodna z typem docelowym. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index bfc8f12e74d5daabdf2c758a567e560c51386142..79fdf874eef287468d3cfd217a7848d612fa3fc5 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. A anulabilidade de tipos de referência em um argumento do tipo '{0}' não coincide com o tipo de destino '{1}' para o parâmetro '{2}' em '{3}'. @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. A anulabilidade de tipos de referência no argumento não corresponde ao tipo de destino. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index 65b5c9b3383aa471a6666d463ed75b4145aa650f..9246907e9ca22f5e261fcdfd42b8fe0db4b65acf 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. Допустимость значения NULL для ссылочных типов в аргументе типа "{0}" не соответствует целевому типу "{1}" для параметра "{2}" в "{3}". @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. Допустимость значения NULL для ссылочных типов в аргументе не соответствует целевому типу. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index c34de25c4f611c912a4c2f7df5c201d6740328f4..9b3c8c440f2afaad460c6a1ebc2ade49d88a1cc0 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. '{0}' türündeki bağımsız değişken için başvuru türlerinin boş değer atanabilirliği, '{3}' içindeki '{2}' parametresi için '{1}' hedef türüyle eşleşmiyor. @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. Bağımsız değişkendeki başvuru türlerinin boş değer atanabilirliği hedef tür ile eşleşmiyor. diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 6d970d637cf283ed6f5d2b32e3785f3785ba57a0..7c8b142645aefe46c5c57745db64ae3d187296d9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -1048,7 +1048,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. 类型“{0}”的实参中引用类型的为 Null 性与“{3}”中形参“{2}”的目标类型“{1}”不匹配。 @@ -1063,7 +1063,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. 参数中的引用类型的为 Null 性与目标类型不匹配。 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 5fa94c7cccdacf0bb9c79f6e996866ff9ccd5932..f55dafe6eb7df7d0daad20eaed308e0649808b50 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -1343,7 +1343,7 @@ - Argument of type '{0}' cannot be used as an input of type '{1}' for parameter '{2}' in '{3}' due to differences in the nullability of reference types. + Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types. 型別 '{0}' 的引數中參考型別可 Null 性與 '{3}' 中參數 '{2}' 的目標型別 '{1}' 不符合。 @@ -1358,7 +1358,7 @@ - Argument cannot be used as an input for parameter due to differences in the nullability of reference types. + Argument cannot be used for parameter due to differences in the nullability of reference types. 引數中參考型別的可 Null 性與目標型別不符合。 diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs index 8aed3e1e4bb1f795e0d3b8ceee723eeba59e8306..e0364b7cd6c58f30b8e0837e85bef0cc6a774642 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/NullableReferenceTypesTests.cs @@ -152,12 +152,15 @@ public void M2() // (6,19): error CS1525: Invalid expression term '=' // object y! = null; Diagnostic(ErrorCode.ERR_InvalidExprTerm, "=").WithArguments("=").WithLocation(6, 19), + // (7,16): warning CS0219: The variable 'y2' is assigned but its value is never used + // object y2; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "y2").WithArguments("y2").WithLocation(7, 16), // (8,9): error CS8598: The suppression operator is not allowed in this context // y2! = null; Diagnostic(ErrorCode.ERR_IllegalSuppression, "y2").WithLocation(8, 9), - // (8,9): error CS0165: Use of unassigned local variable 'y2' + // (8,15): warning CS8600: Converting null literal or possible null value to non-nullable type. // y2! = null; - Diagnostic(ErrorCode.ERR_UseDefViolation, "y2").WithArguments("y2").WithLocation(8, 9) + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(8, 15) ); } @@ -194,56 +197,100 @@ public void SuppressNullableWarning_RefSpanReturn() using System; class C { - ref Span M() + ref Span M(bool b) { Span x = stackalloc byte[10]; ref Span y = ref x!; - return ref y; // 1 + if (b) + return ref y; // 1 + else + return ref y!; // 2 } - ref Span M2() + ref Span M2(ref Span x, bool b) { - Span x = stackalloc byte[10]; - ref Span y = ref x; - return ref y!; // 2 + if (b) + return ref x; // 3 + else + return ref x!; } -}", options: TestOptions.ReleaseDll); +}", options: WithNonNullTypes(TestOptions.ReleaseDll, NullableContextOptions.Enable)); comp.VerifyDiagnostics( - // (9,20): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference - // return ref y; // 1 - Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(9, 20), - // (15,20): error CS8598: The suppression operator is not allowed in this context - // return ref y!; // 2 - Diagnostic(ErrorCode.ERR_IllegalSuppression, "y").WithLocation(15, 20) + // (10,24): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference + // return ref y; // 1 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(10, 24), + // (12,24): error CS8157: Cannot return 'y' by reference because it was initialized to a value that cannot be returned by reference + // return ref y!; // 2 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "y").WithArguments("y").WithLocation(12, 24), + // (17,24): warning CS8619: Nullability of reference types in value of type 'Span' doesn't match target type 'Span'. + // return ref x; // 3 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("System.Span", "System.Span").WithLocation(17, 24) ); } [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] public void SuppressNullableWarning_RefReassignment() { - var comp = CreateCompilationWithMscorlibAndSpan(@" + var comp = CreateCompilation(@" class C { void M() { - ref var x = ref NullableRef(); - x = ref x!; + ref string x = ref NullableRef(); // 1 + ref string x2 = ref x; // 2 + ref string x3 = ref x!; - ref var y = ref NullableRef()!; - y = ref y!; + ref string y = ref NullableRef()!; + ref string y2 = ref y; + ref string y3 = ref y!; } ref string? NullableRef() => throw null!; }", options: WithNonNullTypesTrue()); - // Need to refine. Tracked by https://github.com/dotnet/roslyn/issues/31297 comp.VerifyDiagnostics( - // (7,17): error CS8598: The suppression operator is not allowed in this context - // x = ref x!; - Diagnostic(ErrorCode.ERR_IllegalSuppression, "x").WithLocation(7, 17), - // (10,17): error CS8598: The suppression operator is not allowed in this context - // y = ref y!; - Diagnostic(ErrorCode.ERR_IllegalSuppression, "y").WithLocation(10, 17) + // (6,28): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // ref string x = ref NullableRef(); // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "NullableRef()").WithArguments("string?", "string").WithLocation(6, 28), + // (7,29): warning CS8601: Possible null reference assignment. + // ref string x2 = ref x; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "x").WithLocation(7, 29) + ); + } + + [Fact] + public void SuppressNullableWarning_This() + { + var comp = CreateCompilation(@" +class C +{ + void M() + { + this!.M(); + } +}", options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics(); + } + + [Fact] + public void SuppressNullableWarning_UnaryOperator() + { + var comp = CreateCompilation(@" +class C +{ + void M(C? y) + { + y++; + y!++; + y--; + } + public static C operator++(C x) => throw null!; + public static C operator--(C? x) => throw null!; +}", options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (6,9): warning CS8604: Possible null reference argument for parameter 'x' in 'C C.operator ++(C x)'. + // y++; + Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("x", "C C.operator ++(C x)").WithLocation(6, 9) ); } @@ -410,6 +457,7 @@ class C void M() { E! += () => {}; + E(); } }"); comp.VerifyDiagnostics( @@ -444,9 +492,9 @@ void Method(ref System.Action a, C c) } "; CreateCompilation(text).VerifyDiagnostics( - // (11,9): error CS8598: The suppression operator is not allowed in this context + // (11,11): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C') // c.E! = a; //CS0070 - Diagnostic(ErrorCode.ERR_IllegalSuppression, "c.E").WithLocation(11, 9), + Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C").WithLocation(11, 11), // (12,9): error CS8598: The suppression operator is not allowed in this context // c.E! += a; Diagnostic(ErrorCode.ERR_IllegalSuppression, "c.E").WithLocation(12, 9), @@ -462,12 +510,15 @@ void Method(ref System.Action a, C c) // (16,21): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C') // bool b1 = c.E! is System.Action; //CS0070 Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C").WithLocation(16, 21), - // (17,9): error CS8598: The suppression operator is not allowed in this context + // (17,11): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C') // c.E!++; //CS0070 - Diagnostic(ErrorCode.ERR_IllegalSuppression, "c.E").WithLocation(17, 9), + Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C").WithLocation(17, 11), // (18,9): error CS8598: The suppression operator is not allowed in this context // c.E! |= true; //CS0070 - Diagnostic(ErrorCode.ERR_IllegalSuppression, "c.E").WithLocation(18, 9) + Diagnostic(ErrorCode.ERR_IllegalSuppression, "c.E").WithLocation(18, 9), + // (18,11): error CS0070: The event 'C.E' can only appear on the left hand side of += or -= (except when used from within the type 'C') + // c.E! |= true; //CS0070 + Diagnostic(ErrorCode.ERR_BadEventUsage, "E").WithArguments("C.E", "C").WithLocation(18, 11) ); } @@ -493,6 +544,9 @@ unsafe public void Main() } "; CreateCompilation(text, options: TestOptions.UnsafeReleaseDll).VerifyDiagnostics( + // (8,25): error CS0213: You cannot use the fixed statement to take the address of an already fixed expression + // fixed (int *j = &(i!)) { } + Diagnostic(ErrorCode.ERR_FixedNotNeeded, "&(i!)").WithLocation(8, 25), // (8,27): error CS8598: The suppression operator is not allowed in this context // fixed (int *j = &(i!)) { } Diagnostic(ErrorCode.ERR_IllegalSuppression, "i").WithLocation(8, 27), @@ -860,9 +914,9 @@ static void M(A a) } }"; CreateCompilation(source).VerifyDiagnostics( - // (8,9): error CS8598: The suppression operator is not allowed in this context + // (8,9): error CS1656: Cannot assign to 'E' because it is a 'method group' // a.E! += a.E!; // 1 - Diagnostic(ErrorCode.ERR_IllegalSuppression, "a.E").WithLocation(8, 9), + Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "a.E").WithArguments("E", "method group").WithLocation(8, 9), // (9,13): error CS0019: Operator '!=' cannot be applied to operands of type 'method group' and '' // if (a.E! != null) // 2 Diagnostic(ErrorCode.ERR_BadBinaryOps, "a.E! != null").WithArguments("!=", "method group", "").WithLocation(9, 13), @@ -881,9 +935,9 @@ static void M(A a) // (15,17): error CS0019: Operator '??' cannot be applied to operands of type 'method group' and 'method group' // o = a.E! ?? a.F!; // 7 Diagnostic(ErrorCode.ERR_BadBinaryOps, "a.E! ?? a.F!").WithArguments("??", "method group", "method group").WithLocation(15, 17), - // (17,9): error CS8598: The suppression operator is not allowed in this context + // (17,9): error CS1656: Cannot assign to 'F' because it is a 'method group' // a.F! += a.F!; // 8 - Diagnostic(ErrorCode.ERR_IllegalSuppression, "a.F").WithLocation(17, 9), + Diagnostic(ErrorCode.ERR_AssgReadonlyLocalCause, "a.F").WithArguments("F", "method group").WithLocation(17, 9), // (18,13): error CS0019: Operator '!=' cannot be applied to operands of type 'method group' and '' // if (a.F! != null) // 9 Diagnostic(ErrorCode.ERR_BadBinaryOps, "a.F! != null").WithArguments("!=", "method group", "").WithLocation(18, 13), @@ -969,7 +1023,10 @@ void M() Diagnostic(ErrorCode.ERR_InvalidInitializerElementInitializer, "P! = null").WithLocation(7, 23), // (7,23): error CS8598: The suppression operator is not allowed in this context // _ = new C() { P! = null }; - Diagnostic(ErrorCode.ERR_IllegalSuppression, "P").WithLocation(7, 23) + Diagnostic(ErrorCode.ERR_IllegalSuppression, "P").WithLocation(7, 23), + // (7,28): warning CS8625: Cannot convert null literal to non-nullable reference or unconstrained type parameter. + // _ = new C() { P! = null }; + Diagnostic(ErrorCode.WRN_NullAsNonNullable, "null").WithLocation(7, 28) ); } @@ -1525,15 +1582,451 @@ static void M() }"; var comp = CreateCompilation(source, options: TestOptions.UnsafeReleaseDll); comp.VerifyDiagnostics( - // (6,15): error CS8598: The suppression operator is not allowed in this context + // (6,15): error CS0211: Cannot take the address of the given expression // _ = &(() => {}!); - Diagnostic(ErrorCode.ERR_IllegalSuppression, "() => {}").WithLocation(6, 15), - // (7,15): error CS8598: The suppression operator is not allowed in this context + Diagnostic(ErrorCode.ERR_InvalidAddrOp, "() => {}").WithLocation(6, 15), + // (7,15): error CS0211: Cannot take the address of the given expression // _ = &(M!); - Diagnostic(ErrorCode.ERR_IllegalSuppression, "M").WithLocation(7, 15) + Diagnostic(ErrorCode.ERR_InvalidAddrOp, "M").WithArguments("M", "method group").WithLocation(7, 15) + ); + } + + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] + public void SuppressNullableWarning_AddressOf() + { + var source = @" +unsafe class C +{ + static void M(C x) + { + C* y1 = &x; + C* y2 = &x!; + } +}"; + var comp = CreateCompilation(source, options: WithNonNullTypes(TestOptions.UnsafeReleaseDll, NullableContextOptions.Enable)); + comp.VerifyDiagnostics( + // (6,9): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C') + // C* y1 = &x; + Diagnostic(ErrorCode.ERR_ManagedAddr, "C*").WithArguments("C").WithLocation(6, 9), + // (6,26): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C') + // C* y1 = &x; + Diagnostic(ErrorCode.ERR_ManagedAddr, "&x").WithArguments("C").WithLocation(6, 26), + // (6,26): warning CS8619: Nullability of reference types in value of type 'C*' doesn't match target type 'C*'. + // C* y1 = &x; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "&x").WithArguments("C*", "C*").WithLocation(6, 26), + // (7,9): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C') + // C* y2 = &x!; + Diagnostic(ErrorCode.ERR_ManagedAddr, "C*").WithArguments("C").WithLocation(7, 9), + // (7,26): error CS0208: Cannot take the address of, get the size of, or declare a pointer to a managed type ('C') + // C* y2 = &x!; + Diagnostic(ErrorCode.ERR_ManagedAddr, "&x!").WithArguments("C").WithLocation(7, 26), + // (7,26): warning CS8619: Nullability of reference types in value of type 'C*' doesn't match target type 'C*'. + // C* y2 = &x!; + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "&x!").WithArguments("C*", "C*").WithLocation(7, 26), + // (7,27): error CS8598: The suppression operator is not allowed in this context + // C* y2 = &x!; + Diagnostic(ErrorCode.ERR_IllegalSuppression, "x").WithLocation(7, 27) + ); + } + + [Fact] + public void SuppressNullableWarning_Invocation() + { + var source = @" +class C +{ + void M() + { + _ = nameof!(M); + _ = typeof!(C); + this.M!(); + dynamic d = null!; + d.M2!(); + } +}"; + var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (6,13): error CS0103: The name 'nameof' does not exist in the current context + // _ = nameof!(M); + Diagnostic(ErrorCode.ERR_NameNotInContext, "nameof").WithArguments("nameof").WithLocation(6, 13), + // (7,19): error CS1003: Syntax error, '(' expected + // _ = typeof!(C); + Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments("(", "!").WithLocation(7, 19), + // (7,19): error CS1031: Type expected + // _ = typeof!(C); + Diagnostic(ErrorCode.ERR_TypeExpected, "!").WithLocation(7, 19), + // (7,19): error CS1026: ) expected + // _ = typeof!(C); + Diagnostic(ErrorCode.ERR_CloseParenExpected, "!").WithLocation(7, 19), + // (7,21): error CS0119: 'C' is a type, which is not valid in the given context + // _ = typeof!(C); + Diagnostic(ErrorCode.ERR_BadSKunknown, "C").WithArguments("C", "type").WithLocation(7, 21), + // (8,9): error CS8598: The suppression operator is not allowed in this context + // this.M!(); + Diagnostic(ErrorCode.ERR_IllegalSuppression, "this.M").WithLocation(8, 9), + // (10,9): error CS8598: The suppression operator is not allowed in this context + // d.M2!(); + Diagnostic(ErrorCode.ERR_IllegalSuppression, "d.M2").WithLocation(10, 9) + ); + } + + [Fact, WorkItem(32701, "https://github.com/dotnet/roslyn/issues/32701")] + public void Verify32701() + { + var source = @" +class C +{ + static void M(ref T t, dynamic? d) + { + t = d; // 1 + } + static void M2(T t, dynamic? d) + { + t = d; // 2 + } +}"; + var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (6,13): warning CS8601: Possible null reference assignment. + // t = d; // 1 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "d").WithLocation(6, 13), + // (10,13): warning CS8601: Possible null reference assignment. + // t = d; // 2 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "d").WithLocation(10, 13) + ); + } + + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] + public void RefReturn() + { + var source = @" +struct S +{ + ref S M(ref S x) + { + return ref x; // 1 + } + ref S M2(ref S x) + { + return ref x!; + } +} +class C +{ + ref C? M3(ref C x) + { + return ref x; // 2 + } + ref C M4(ref C? x) + { + return ref x; // 3 + } + ref C? M5(ref C x) + { + return ref x!; + } + ref C M6(ref C? x) + { + return ref x!; + } +}"; + var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (6,20): warning CS8619: Nullability of reference types in value of type 'S' doesn't match target type 'S'. + // return ref x; // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("S", "S").WithLocation(6, 20), + // (17,20): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C?'. + // return ref x; // 2 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("C", "C?").WithLocation(17, 20), + // (21,20): warning CS8619: Nullability of reference types in value of type 'C?' doesn't match target type 'C'. + // return ref x; // 3 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("C?", "C").WithLocation(21, 20) ); } + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] + public void RefReturn_State() + { + var source = @" +class C +{ + ref C M1(ref C? w) + { + return ref w; // 1 + } + ref C? M2(ref C w) + { + return ref w; // 2 + } + ref C M3(ref C w) + { + return ref w; + } + ref C? M4(ref C? w) + { + return ref w; + } +}"; + + var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (6,20): warning CS8619: Nullability of reference types in value of type 'C?' doesn't match target type 'C'. + // return ref w; // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "w").WithArguments("C?", "C").WithLocation(6, 20), + // (10,20): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C?'. + // return ref w; // 2 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "w").WithArguments("C", "C?").WithLocation(10, 20) + ); + } + + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] + public void RefAssignment() + { + var source = @" +class C +{ + void M1(C? x) + { + ref C y = ref x; // 1 + y.ToString(); // 2 + } + void M2(C x) + { + ref C? y = ref x; // 3 + y.ToString(); + } + void M3(C? x, C nonNull) + { + x = nonNull; + ref C y = ref x; // 4 + y.ToString(); + y = null; // 5 + } + void M4(C x, C? nullable) + { + x = nullable; // 6 + ref C? y = ref x; // 7 + y.ToString(); // 8 + } +}"; + + var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (6,23): warning CS8619: Nullability of reference types in value of type 'C?' doesn't match target type 'C'. + // ref C y = ref x; // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("C?", "C").WithLocation(6, 23), + // (7,9): warning CS8602: Possible dereference of a null reference. + // y.ToString(); // 2 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(7, 9), + // (11,24): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C?'. + // ref C? y = ref x; // 3 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("C", "C?").WithLocation(11, 24), + // (17,23): warning CS8619: Nullability of reference types in value of type 'C?' doesn't match target type 'C'. + // ref C y = ref x; // 4 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("C?", "C").WithLocation(17, 23), + // (19,13): warning CS8600: Converting null literal or possible null value to non-nullable type. + // y = null; // 5 + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(19, 13), + // (23,13): warning CS8600: Converting null literal or possible null value to non-nullable type. + // x = nullable; // 6 + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "nullable").WithLocation(23, 13), + // (24,24): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C?'. + // ref C? y = ref x; // 7 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("C", "C?").WithLocation(24, 24), + // (25,9): warning CS8602: Possible dereference of a null reference. + // y.ToString(); // 8 + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "y").WithLocation(25, 9) + ); + } + + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] + public void RefAssignment_WithSuppression() + { + var source = @" +class C +{ + void M1(C? x) + { + ref C y = ref x!; + y.ToString(); + } + void M2(C x) + { + ref C? y = ref x!; + y.ToString(); + } + void M3(C? x, C nonNull) + { + x = nonNull; + ref C y = ref x!; + y.ToString(); + } + void M4(C x, C? nullable) + { + x = nullable; // 1 + ref C? y = ref x!; + y.ToString(); + } +}"; + + var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (22,13): warning CS8600: Converting null literal or possible null value to non-nullable type. + // x = nullable; // 1 + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "nullable").WithLocation(22, 13) + ); + } + + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] + public void RefAssignment_Nested() + { + var source = @" +struct S +{ + void M(ref S x) + { + S y = default; + ref S y2 = ref y; // 1 + y2 = ref y; // 2 + y2 = ref y!; + } +}"; + + var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics( + // (7,32): warning CS8619: Nullability of reference types in value of type 'S' doesn't match target type 'S'. + // ref S y2 = ref y; // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y").WithArguments("S", "S").WithLocation(7, 32), + // (8,18): warning CS8619: Nullability of reference types in value of type 'S' doesn't match target type 'S'. + // y2 = ref y; // 2 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y").WithArguments("S", "S").WithLocation(8, 18) + ); + } + + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] + public void RefAssignment_Foreach() + { + verify(variableType: "string?", itemType: "string", + // (6,18): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. + // foreach (ref string? item in collection) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "ref string?").WithArguments("string", "string?").WithLocation(6, 18)); + + verify("string", "string?", + // (6,18): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. + // foreach (ref string item in collection) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "ref string").WithArguments("string?", "string").WithLocation(6, 18), + // (8,13): warning CS8602: Possible dereference of a null reference. + // item.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "item").WithLocation(8, 13)); + + verify("string", "string"); + verify("string?", "string?", + // (8,13): warning CS8602: Possible dereference of a null reference. + // item.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "item").WithLocation(8, 13)); + + verify("C", "C", + // (6,18): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C'. + // foreach (ref C item in collection) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "ref C").WithArguments("C", "C").WithLocation(6, 18)); + + verify("C", "C", + // (6,18): warning CS8619: Nullability of reference types in value of type 'C' doesn't match target type 'C'. + // foreach (ref C item in collection) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "ref C").WithArguments("C", "C").WithLocation(6, 18)); + + verify("C", "C?", + // (6,18): warning CS8619: Nullability of reference types in value of type 'C?' doesn't match target type 'C'. + // foreach (ref C item in collection) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "ref C").WithArguments("C?", "C").WithLocation(6, 18), + // (8,13): warning CS8602: Possible dereference of a null reference. + // item.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "item").WithLocation(8, 13)); + + verify("C", "C"); + verify("var", "string"); + + verify("var", "string?", + // (8,13): warning CS8602: Possible dereference of a null reference. + // item.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "item").WithLocation(8, 13)); + + verify("T", "T", + // (8,13): warning CS8602: Possible dereference of a null reference. + // item.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "item").WithLocation(8, 13)); + + void verify(string variableType, string itemType, params DiagnosticDescription[] expected) + { + var source = @" +class C +{ + void M(RefEnumerable collection) + { + foreach (ref VARTYPE item in collection) + { + item.ToString(); + } + } + + class RefEnumerable + { + public StructEnum GetEnumerator() => throw null!; + public struct StructEnum + { + public ref ITEMTYPE Current => throw null!; + public bool MoveNext() => throw null!; + } + } +}"; + + var comp = CreateCompilation(source.Replace("VARTYPE", variableType).Replace("ITEMTYPE", itemType), options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics(expected); + } + } + + [Fact, WorkItem(31297, "https://github.com/dotnet/roslyn/issues/31297")] + public void RefAssignment_Foreach_Nested() + { + verify(fieldType: "string?", + // (9,13): warning CS8602: Possible dereference of a null reference. + // item.Field.ToString(); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "item.Field").WithLocation(9, 13)); + + verify(fieldType: "string", + // (2,7): warning CS8618: Non-nullable field 'Field' is uninitialized. + // class C + Diagnostic(ErrorCode.WRN_UninitializedNonNullableField, "C").WithArguments("field", "Field").WithLocation(2, 7)); + + void verify(string fieldType, params DiagnosticDescription[] expected) + { + var source = @" +class C +{ + public FIELDTYPE Field; + void M(RefEnumerable collection) + { + foreach (ref C item in collection) + { + item.Field.ToString(); + } + } + + class RefEnumerable + { + public StructEnum GetEnumerator() => throw null!; + public struct StructEnum + { + public ref C Current => throw null!; + public bool MoveNext() => throw null!; + } + } +}"; + var comp = CreateCompilation(source.Replace("FIELDTYPE", fieldType), options: WithNonNullTypesTrue()); + comp.VerifyDiagnostics(expected); + } + } + [Fact, WorkItem(31370, "https://github.com/dotnet/roslyn/issues/31370")] public void TestLambdaWithError19() { @@ -1667,15 +2160,27 @@ string M(string x) // Suppressed expression cannot be used as a statement var comp = CreateCompilation(src); comp.VerifyDiagnostics( + // (6,9): error CS8598: The suppression operator is not allowed in this context + // x!; + Diagnostic(ErrorCode.ERR_IllegalSuppression, "x").WithLocation(6, 9), // (6,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // x!; Diagnostic(ErrorCode.ERR_IllegalStatement, "x!").WithLocation(6, 9), + // (7,9): error CS8598: The suppression operator is not allowed in this context + // M2(x)!; + Diagnostic(ErrorCode.ERR_IllegalSuppression, "M2(x)").WithLocation(7, 9), // (7,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // M2(x)!; Diagnostic(ErrorCode.ERR_IllegalStatement, "M2(x)!").WithLocation(7, 9), + // (11,9): error CS8598: The suppression operator is not allowed in this context + // x!; + Diagnostic(ErrorCode.ERR_IllegalSuppression, "x").WithLocation(11, 9), // (11,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // x!; Diagnostic(ErrorCode.ERR_IllegalStatement, "x!").WithLocation(11, 9), + // (12,9): error CS8598: The suppression operator is not allowed in this context + // M(x)!; + Diagnostic(ErrorCode.ERR_IllegalSuppression, "M(x)").WithLocation(12, 9), // (12,9): error CS0201: Only assignment, call, increment, decrement, await, and new object expressions can be used as a statement // M(x)!; Diagnostic(ErrorCode.ERR_IllegalStatement, "M(x)!").WithLocation(12, 9) @@ -2056,9 +2561,9 @@ void M(object o, int? i) // (16,10): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer // (null)++; // 9 Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "null").WithLocation(16, 10), - // (17,10): error CS8598: The suppression operator is not allowed in this context + // (17,10): error CS1059: The operand of an increment or decrement operator must be a variable, property or indexer // (null!)++; // 10 - Diagnostic(ErrorCode.ERR_IllegalSuppression, "null").WithLocation(17, 10), + Diagnostic(ErrorCode.ERR_IncrementLvalueExpected, "null").WithLocation(17, 10), // (18,13): error CS8310: Operator '!' cannot be applied to operand '' // _ = !null; // 11 Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "!null").WithArguments("!", "").WithLocation(18, 13), @@ -2678,12 +3183,15 @@ void M() } "; CreateCompilation(source, options: WithNonNullTypesTrue()).VerifyDiagnostics( + // (6,16): warning CS0219: The variable 'x' is assigned but its value is never used + // object x; + Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "x").WithArguments("x").WithLocation(6, 16), // (7,9): error CS8598: The suppression operator is not allowed in this context // x! = null; Diagnostic(ErrorCode.ERR_IllegalSuppression, "x").WithLocation(7, 9), - // (7,9): error CS0165: Use of unassigned local variable 'x' + // (7,14): warning CS8600: Converting null literal or possible null value to non-nullable type. // x! = null; - Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(7, 9) + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(7, 14) ); } @@ -2698,11 +3206,7 @@ void M() for (var x = 0; ; x!++) { } } }"; - CreateCompilation(source, options: WithNonNullTypesTrue()).VerifyDiagnostics( - // (6,27): error CS8598: The suppression operator is not allowed in this context - // for (var x = 0; ; x!++) { } - Diagnostic(ErrorCode.ERR_IllegalSuppression, "x").WithLocation(6, 27) - ); + CreateCompilation(source, options: WithNonNullTypesTrue()).VerifyDiagnostics(); } [Fact, WorkItem(26654, "https://github.com/dotnet/roslyn/issues/26654")] @@ -4354,15 +4858,22 @@ void M(string? x) "; var c = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); c.VerifyDiagnostics( - // (6,28): warning CS8600: Converting null literal or possible null value to non-nullable type. + // (6,28): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // ref string y = ref x; - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x").WithLocation(6, 28), - // (7,29): warning CS8600: Converting null literal or possible null value to non-nullable type. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("string?", "string").WithLocation(6, 28), + // (7,29): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // ref string y2 = ref x; - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x").WithLocation(7, 29), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("string?", "string").WithLocation(7, 29), // (8,10): error CS8598: The suppression operator is not allowed in this context // (y2! = ref y) = ref y; - Diagnostic(ErrorCode.ERR_IllegalSuppression, "y2").WithLocation(8, 10)); + Diagnostic(ErrorCode.ERR_IllegalSuppression, "y2").WithLocation(8, 10), + // (8,20): warning CS8601: Possible null reference assignment. + // (y2! = ref y) = ref y; + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y").WithLocation(8, 20), + // (8,29): warning CS8601: Possible null reference assignment. + // (y2! = ref y) = ref y; + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "y").WithLocation(8, 29) + ); } [Fact] @@ -12384,18 +12895,18 @@ class CL1 // (27,16): error CS0165: Use of unassigned local variable 'x3' // M2(ref x3); Diagnostic(ErrorCode.ERR_UseDefViolation, "x3").WithArguments("x3").WithLocation(27, 16), - // (27,16): warning CS8600: Converting null literal or possible null value to non-nullable type. + // (27,16): warning CS8620: Argument of type 'CL1' cannot be used for parameter 'p' of type 'CL1?' in 'void C.M2(ref CL1? p)' due to differences in the nullability of reference types. // M2(ref x3); - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x3").WithLocation(27, 16), - // (32,16): warning CS8600: Converting null literal or possible null value to non-nullable type. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "x3").WithArguments("CL1", "CL1?", "p", "void C.M2(ref CL1? p)").WithLocation(27, 16), + // (32,16): warning CS8620: Argument of type 'CL1' cannot be used for parameter 'p' of type 'CL1?' in 'void C.M2(ref CL1? p)' due to differences in the nullability of reference types. // M2(ref x4); - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x4").WithLocation(32, 16), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "x4").WithArguments("CL1", "CL1?", "p", "void C.M2(ref CL1? p)").WithLocation(32, 16), // (40,16): warning CS8600: Converting null literal or possible null value to non-nullable type. // M3(out x5); Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x5").WithLocation(40, 16), - // (48,16): warning CS8604: Possible null reference argument for parameter 'p' in 'void C.M4(ref CL1 p)'. + // (48,16): warning CS8620: Argument of type 'CL1?' cannot be used for parameter 'p' of type 'CL1' in 'void C.M4(ref CL1 p)' due to differences in the nullability of reference types. // M4(ref x6); - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "x6").WithArguments("p", "void C.M4(ref CL1 p)").WithLocation(48, 16), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "x6").WithArguments("CL1?", "CL1", "p", "void C.M4(ref CL1 p)").WithLocation(48, 16), // (56,18): warning CS8600: Converting null literal or possible null value to non-nullable type. // CL1 u7 = x7; Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x7").WithLocation(56, 18), @@ -13257,15 +13768,16 @@ static void G(out object x, ref object y, in object z) }"; var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); comp.VerifyDiagnostics( - // (5,22): warning CS8604: Possible null reference argument for parameter 'y' in 'void C.G(out object x, ref object y, in object z)'. + // (5,22): warning CS8620: Argument of type 'object?' cannot be used for parameter 'y' of type 'object' in 'void C.G(out object x, ref object y, in object z)' due to differences in the nullability of reference types. // G(out x, ref y, in z); - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "y").WithArguments("y", "void C.G(out object x, ref object y, in object z)").WithLocation(5, 22), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "y").WithArguments("object?", "object", "y", "void C.G(out object x, ref object y, in object z)").WithLocation(5, 22), // (5,28): warning CS8604: Possible null reference argument for parameter 'z' in 'void C.G(out object x, ref object y, in object z)'. // G(out x, ref y, in z); Diagnostic(ErrorCode.WRN_NullReferenceArgument, "z").WithArguments("z", "void C.G(out object x, ref object y, in object z)").WithLocation(5, 28), // (8,9): warning CS8602: Possible dereference of a null reference. // z.ToString(); - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z").WithLocation(8, 9)); + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "z").WithLocation(8, 9) + ); } [Fact] @@ -13291,9 +13803,9 @@ static void G(out object? x, ref object? y, in object? z) // (5,15): warning CS8600: Converting null literal or possible null value to non-nullable type. // G(out x, ref y, in z); Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "x").WithLocation(5, 15), - // (5,22): warning CS8600: Converting null literal or possible null value to non-nullable type. + // (5,22): warning CS8620: Argument of type 'object' cannot be used for parameter 'y' of type 'object?' in 'void C.G(out object? x, ref object? y, in object? z)' due to differences in the nullability of reference types. // G(out x, ref y, in z); - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "y").WithLocation(5, 22), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "y").WithArguments("object", "object?", "y", "void C.G(out object? x, ref object? y, in object? z)").WithLocation(5, 22), // (6,9): warning CS8602: Possible dereference of a null reference. // x.ToString(); Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "x").WithLocation(6, 9), @@ -14565,9 +15077,9 @@ public void Main(string? s) " }, options: WithNonNullTypesTrue()); c.VerifyDiagnostics( - // (6,15): warning CS8604: Possible null reference argument for parameter 'value' in 'void C.M(ref string value)'. + // (6,15): warning CS8620: Argument of type 'string?' cannot be used as an input of type 'string' for parameter 'value' in 'void C.M(ref string value)' due to differences in the nullability of reference types. // M(ref s); // warn - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("value", "void C.M(ref string value)").WithLocation(6, 15) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s").WithArguments("string?", "string", "value", "void C.M(ref string value)").WithLocation(6, 15) ); } @@ -14587,7 +15099,11 @@ public void Main() } " }, options: WithNonNullTypesTrue()); - c.VerifyDiagnostics(); + c.VerifyDiagnostics( + // (7,15): warning CS8620: Argument of type 'string?' cannot be used as an input of type 'string' for parameter 'value' in 'void C.M(ref string value)' due to differences in the nullability of reference types. + // M(ref s); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s").WithArguments("string?", "string", "value", "void C.M(ref string value)").WithLocation(7, 15) + ); } [Fact] @@ -14606,9 +15122,9 @@ public void Main(string s) " }, options: WithNonNullTypesTrue()); c.VerifyDiagnostics( - // (6,15): warning CS8600: Converting null literal or possible null value to non-nullable type. + // (6,15): warning CS8620: Argument of type 'string' cannot be used as an input of type 'string?' for parameter 'value' in 'void C.M(ref string? value)' due to differences in the nullability of reference types. // M(ref s); // warn 1 - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "s").WithLocation(6, 15), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s").WithArguments("string", "string?", "value", "void C.M(ref string? value)").WithLocation(6, 15), // (7,9): warning CS8602: Possible dereference of a null reference. // s.ToString(); // warn 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(7, 9) @@ -14632,9 +15148,9 @@ public void Main() " }, options: WithNonNullTypesTrue()); c.VerifyDiagnostics( - // (7,15): warning CS8600: Converting null literal or possible null value to non-nullable type. + // (7,15): warning CS8620: Argument of type 'string' cannot be used as an input of type 'string?' for parameter 'value' in 'void C.M(ref string? value)' due to differences in the nullability of reference types. // M(ref s); // warn 1 - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "s").WithLocation(7, 15), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s").WithArguments("string", "string?", "value", "void C.M(ref string? value)").WithLocation(7, 15), // (8,9): warning CS8602: Possible dereference of a null reference. // s.ToString(); // warn 2 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(8, 9) @@ -15104,8 +15620,13 @@ public void M() string s2 = """"; M(ref s2); // 2 s2.ToString(); // 3 + + string s3 = null; // 4 + M2(ref s3); // 5 + s3.ToString(); } void M(ref string? s) => throw null!; + void M2(ref string s) => throw null!; } ", options: WithNonNullTypesTrue()); @@ -15113,12 +15634,18 @@ public void M() // (8,9): warning CS8602: Possible dereference of a null reference. // s.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(8, 9), - // (11,15): warning CS8600: Converting null literal or possible null value to non-nullable type. + // (11,15): warning CS8620: Argument of type 'string' cannot be used for parameter 's' of type 'string?' in 'void C.M(ref string? s)' due to differences in the nullability of reference types. // M(ref s2); // 2 - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "s2").WithLocation(11, 15), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s2").WithArguments("string", "string?", "s", "void C.M(ref string? s)").WithLocation(11, 15), // (12,9): warning CS8602: Possible dereference of a null reference. // s2.ToString(); // 3 - Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s2").WithLocation(12, 9) + Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s2").WithLocation(12, 9), + // (14,21): warning CS8600: Converting null literal or possible null value to non-nullable type. + // string s3 = null; // 4 + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "null").WithLocation(14, 21), + // (15,16): warning CS8601: Possible null reference assignment. + // M2(ref s3); // 5 + Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "s3").WithLocation(15, 16) ); } @@ -15140,9 +15667,9 @@ public void M() ", options: WithNonNullTypesTrue()); c.VerifyDiagnostics( - // (7,15): warning CS8604: Possible null reference argument for parameter 's' in 'void C.M(ref string s)'. + // (7,15): warning CS8620: Argument of type 'string?' cannot be used as an input of type 'string' for parameter 's' in 'void C.M(ref string s)' due to differences in the nullability of reference types. // M(ref s); - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.M(ref string s)").WithLocation(7, 15) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s").WithArguments("string?", "string", "s", "void C.M(ref string s)").WithLocation(7, 15) ); } @@ -15201,9 +15728,9 @@ public void M() // (9,15): error CS1510: A ref or out value must be an assignable variable // M(ref ""); // 2 Diagnostic(ErrorCode.ERR_RefLvalueExpected, @"""""").WithLocation(9, 15), - // (11,15): warning CS8601: Possible null reference assignment. + // (11,15): warning CS8620: Argument of type 'string' cannot be used as an input of type 'string?' for parameter 's' in 'void C.M(ref string? s)' due to differences in the nullability of reference types. // M(ref field); // 3 - Diagnostic(ErrorCode.WRN_NullReferenceAssignment, "field").WithLocation(11, 15), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "field").WithArguments("string", "string?", "s", "void C.M(ref string? s)").WithLocation(11, 15), // (12,9): warning CS8602: Possible dereference of a null reference. // field.ToString(); // 4 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "field").WithLocation(12, 9), @@ -15244,9 +15771,9 @@ public static class Extension // (8,9): warning CS8602: Possible dereference of a null reference. // s.ToString(); // 1 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s").WithLocation(8, 9), - // (11,20): warning CS8600: Converting null literal or possible null value to non-nullable type. + // (11,20): warning CS8620: Argument of type 'string' cannot be used as an input of type 'string?' for parameter 's' in 'void Extension.M(C c, ref string? s)' due to differences in the nullability of reference types. // this.M(ref s2); // 2 - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "s2").WithLocation(11, 20), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s2").WithArguments("string", "string?", "s", "void Extension.M(C c, ref string? s)").WithLocation(11, 20), // (12,9): warning CS8602: Possible dereference of a null reference. // s2.ToString(); // 3 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "s2").WithLocation(12, 9) @@ -15361,9 +15888,9 @@ public void M() // (14,9): warning CS8602: Possible dereference of a null reference. // v2.ToString(); // 3 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "v2").WithLocation(14, 9), - // (17,25): warning CS8604: Possible null reference argument for parameter 's' in 'string? C.M2(ref string s, string? u)'. + // (17,25): warning CS8620: Argument of type 'string?' cannot be used as an input of type 'string' for parameter 's' in 'string? C.M2(ref string s, string? u)' due to differences in the nullability of reference types. // var v3 = M2(ref s, s); // 4 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "string? C.M2(ref string s, string? u)").WithLocation(17, 25), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s").WithArguments("string?", "string", "s", "string? C.M2(ref string s, string? u)").WithLocation(17, 25), // (19,9): warning CS8602: Possible dereference of a null reference. // v3.ToString(); // 5 Diagnostic(ErrorCode.WRN_NullReferenceReceiver, "v3").WithLocation(19, 9) @@ -27373,9 +27900,14 @@ static void G(bool b) } }"; var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); - // https://github.com/dotnet/roslyn/issues/30432: Report warnings for combinations of `object?` and `object!`. - comp.VerifyDiagnostics(); - comp.VerifyTypes(); + comp.VerifyDiagnostics( + // (8,81): warning CS8619: Nullability of reference types in value of type 'object' doesn't match target type 'object?'. + // F((ref object? x2, ref object y2) => { if (b) return ref x2; return ref y2; }); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y2").WithArguments("object", "object?").WithLocation(8, 81), + // (9,66): warning CS8619: Nullability of reference types in value of type 'object' doesn't match target type 'object?'. + // F((ref object x3, ref object? y3) => { if (b) return ref x3; return ref y3; }); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x3").WithArguments("object", "object?").WithLocation(9, 66) + ); } [WorkItem(30432, "https://github.com/dotnet/roslyn/issues/30432")] @@ -27400,31 +27932,37 @@ static void G(bool b) F((ref I a4, ref I b4) => { if (b) return ref a4; return ref b4; }); // IIn F((ref IIn c1, ref IIn d1) => { if (b) return ref c1; return ref d1; }); - F((ref IIn c2, ref IIn d2) => { if (b) return ref c2; return ref d2; }); - F((ref IIn c3, ref IIn d3) => { if (b) return ref c3; return ref d3; }); + F((ref IIn c2, ref IIn d2) => { if (b) return ref c2; return ref d2; }); // 3 + F((ref IIn c3, ref IIn d3) => { if (b) return ref c3; return ref d3; }); // 4 F((ref IIn c4, ref IIn d4) => { if (b) return ref c4; return ref d4; }); // IOut F((ref IOut e1, ref IOut f1) => { if (b) return ref e1; return ref f1; }); - F((ref IOut e2, ref IOut f2) => { if (b) return ref e2; return ref f2; }); - F((ref IOut e3, ref IOut f3) => { if (b) return ref e3; return ref f3; }); + F((ref IOut e2, ref IOut f2) => { if (b) return ref e2; return ref f2; }); // 5 + F((ref IOut e3, ref IOut f3) => { if (b) return ref e3; return ref f3; }); // 6 F((ref IOut e4, ref IOut f4) => { if (b) return ref e4; return ref f4; }); } }"; var comp = CreateCompilation(new[] { source }, options: WithNonNullTypesTrue()); - // https://github.com/dotnet/roslyn/issues/30432: Report warnings for combinations of `IIn` and `IIn` - // and combinations of `IOut` and `IOut`. - // https://github.com/dotnet/roslyn/issues/30964 - Report warnings about nullability mismatch in conditional operators for: - // F((ref I a2, ref I b2) => { if (b) return ref a2; return ref b2; }); - // F((ref I a3, ref I b3) => { if (b) return ref a3; return ref b3; }); comp.VerifyDiagnostics( // (12,72): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. // F((ref I a2, ref I b2) => { if (b) return ref a2; return ref b2; }); // 1 Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "a2").WithArguments("I", "I").WithLocation(12, 72), // (13,87): warning CS8619: Nullability of reference types in value of type 'I' doesn't match target type 'I'. // F((ref I a3, ref I b3) => { if (b) return ref a3; return ref b3; }); // 2 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b3").WithArguments("I", "I").WithLocation(13, 87) + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "b3").WithArguments("I", "I").WithLocation(13, 87), + // (17,76): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. + // F((ref IIn c2, ref IIn d2) => { if (b) return ref c2; return ref d2; }); // 3 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "c2").WithArguments("IIn", "IIn").WithLocation(17, 76), + // (18,91): warning CS8619: Nullability of reference types in value of type 'IIn' doesn't match target type 'IIn'. + // F((ref IIn c3, ref IIn d3) => { if (b) return ref c3; return ref d3; }); // 4 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "d3").WithArguments("IIn", "IIn").WithLocation(18, 91), + // (22,93): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. + // F((ref IOut e2, ref IOut f2) => { if (b) return ref e2; return ref f2; }); // 5 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "f2").WithArguments("IOut", "IOut").WithLocation(22, 93), + // (23,78): warning CS8619: Nullability of reference types in value of type 'IOut' doesn't match target type 'IOut'. + // F((ref IOut e3, ref IOut f3) => { if (b) return ref e3; return ref f3; }); // 6 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "e3").WithArguments("IOut", "IOut").WithLocation(23, 78) ); - comp.VerifyTypes(); } [Fact] @@ -31646,15 +32184,15 @@ static void G(ref I x, ref IIn y, ref IOut z) // (8,22): warning CS8620: Argument of type 'IIn' cannot be used as an input of type 'IIn' for parameter 'y' in 'void C.G(ref I x, ref IIn y, ref IOut z)' due to differences in the nullability of reference types. // G(ref x, ref y, ref z); Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "y").WithArguments("IIn", "IIn", "y", "void C.G(ref I x, ref IIn y, ref IOut z)").WithLocation(8, 22), - // (8,29): warning CS8624: Argument of type 'IOut' cannot be used as an output of type 'IOut' for parameter 'z' in 'void C.G(ref I x, ref IIn y, ref IOut z)' due to differences in the nullability of reference types. + // (8,29): warning CS8620: Argument of type 'IOut' cannot be used as an input of type 'IOut' for parameter 'z' in 'void C.G(ref I x, ref IIn y, ref IOut z)' due to differences in the nullability of reference types. // G(ref x, ref y, ref z); - Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgumentForOutput, "z").WithArguments("IOut", "IOut", "z", "void C.G(ref I x, ref IIn y, ref IOut z)").WithLocation(8, 29), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "z").WithArguments("IOut", "IOut", "z", "void C.G(ref I x, ref IIn y, ref IOut z)").WithLocation(8, 29), // (12,15): warning CS8620: Argument of type 'I' cannot be used as an input of type 'I' for parameter 'x' in 'void C.F(ref I x, ref IIn y, ref IOut z)' due to differences in the nullability of reference types. // F(ref x, ref y, ref z); Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "x").WithArguments("I", "I", "x", "void C.F(ref I x, ref IIn y, ref IOut z)").WithLocation(12, 15), - // (12,22): warning CS8624: Argument of type 'IIn' cannot be used as an output of type 'IIn' for parameter 'y' in 'void C.F(ref I x, ref IIn y, ref IOut z)' due to differences in the nullability of reference types. + // (12,22): warning CS8620: Argument of type 'IIn' cannot be used as an input of type 'IIn' for parameter 'y' in 'void C.F(ref I x, ref IIn y, ref IOut z)' due to differences in the nullability of reference types. // F(ref x, ref y, ref z); - Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgumentForOutput, "y").WithArguments("IIn", "IIn", "y", "void C.F(ref I x, ref IIn y, ref IOut z)").WithLocation(12, 22), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "y").WithArguments("IIn", "IIn", "y", "void C.F(ref I x, ref IIn y, ref IOut z)").WithLocation(12, 22), // (12,29): warning CS8620: Argument of type 'IOut' cannot be used as an input of type 'IOut' for parameter 'z' in 'void C.F(ref I x, ref IIn y, ref IOut z)' due to differences in the nullability of reference types. // F(ref x, ref y, ref z); Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "z").WithArguments("IOut", "IOut", "z", "void C.F(ref I x, ref IIn y, ref IOut z)").WithLocation(12, 29)); @@ -37975,12 +38513,12 @@ static void Main() parseOptions: TestOptions.Regular8, options: WithNonNullTypesTrue(TestOptions.ReleaseExe)); comp.VerifyDiagnostics( - // (10,15): warning CS8604: Possible null reference argument for parameter 's' in 'void C.F(ref string s, ref string? t)'. + // (10,15): warning CS8620: Argument of type 'string?' cannot be used as an input of type 'string' for parameter 's' in 'void C.F(ref string s, ref string? t)' due to differences in the nullability of reference types. // F(ref s, ref t); - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "s").WithArguments("s", "void C.F(ref string s, ref string? t)").WithLocation(10, 15), - // (10,22): warning CS8600: Converting null literal or possible null value to non-nullable type. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "s").WithArguments("string?", "string", "s", "void C.F(ref string s, ref string? t)").WithLocation(10, 15), + // (10,22): warning CS8620: Argument of type 'string' cannot be used as an input of type 'string?' for parameter 't' in 'void C.F(ref string s, ref string? t)' due to differences in the nullability of reference types. // F(ref s, ref t); - Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "t").WithLocation(10, 22)); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "t").WithArguments("string", "string?", "t", "void C.F(ref string s, ref string? t)").WithLocation(10, 22)); } [Fact] @@ -38007,18 +38545,18 @@ static void F2(ref List a, ref List? b, ref List c, ref new[] { source }, options: WithNonNullTypesTrue(), parseOptions: TestOptions.Regular8); comp.VerifyDiagnostics( - // (10,15): warning CS8604: Possible null reference argument for parameter 'a' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)'. + // (10,15): warning CS8620: Argument of type 'List?' cannot be used as an input of type 'List' for parameter 'a' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. // F(ref b, ref c, ref d, ref a); // warn 1, 2, 3 and 4 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "b").WithArguments("a", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(10, 15), - // (10,22): warning CS8620: Argument of type 'List' cannot be used as an input of type 'List' for parameter 'b' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "b").WithArguments("List?", "List", "a", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(10, 15), + // (10,22): warning CS8620: Argument of type 'List' cannot be used as an input of type 'List?' for parameter 'b' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. // F(ref b, ref c, ref d, ref a); // warn 1, 2, 3 and 4 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "c").WithArguments("List", "List", "b", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(10, 22), - // (10,29): warning CS8604: Possible null reference argument for parameter 'c' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)'. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "c").WithArguments("List", "List?", "b", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(10, 22), + // (10,29): warning CS8620: Argument of type 'List?' cannot be used as an input of type 'List' for parameter 'c' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. // F(ref b, ref c, ref d, ref a); // warn 1, 2, 3 and 4 - Diagnostic(ErrorCode.WRN_NullReferenceArgument, "d").WithArguments("c", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(10, 29), - // (10,36): warning CS8620: Argument of type 'List' cannot be used as an input of type 'List' for parameter 'd' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "d").WithArguments("List?", "List", "c", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(10, 29), + // (10,36): warning CS8620: Argument of type 'List' cannot be used as an input of type 'List?' for parameter 'd' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. // F(ref b, ref c, ref d, ref a); // warn 1, 2, 3 and 4 - Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "a").WithArguments("List", "List", "d", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(10, 36)); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "a").WithArguments("List", "List?", "d", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(10, 36)); } [Fact] @@ -38050,28 +38588,32 @@ static void F2() F(ref b!, ref c!, ref d!, ref a!); } }"; - var comp = CreateCompilation( - new[] { source }, options: WithNonNullTypesTrue(), - parseOptions: TestOptions.Regular8); + var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); comp.VerifyDiagnostics( // (15,15): error CS0165: Use of unassigned local variable 'b' // F(ref b, ref c, ref d, ref a); Diagnostic(ErrorCode.ERR_UseDefViolation, "b").WithArguments("b").WithLocation(15, 15), + // (15,15): warning CS8620: Argument of type 'List?' cannot be used for parameter 'a' of type 'List' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. + // F(ref b, ref c, ref d, ref a); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "b").WithArguments("List?", "List", "a", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(15, 15), // (15,22): error CS0165: Use of unassigned local variable 'c' // F(ref b, ref c, ref d, ref a); Diagnostic(ErrorCode.ERR_UseDefViolation, "c").WithArguments("c").WithLocation(15, 22), - // (15,22): warning CS8620: Argument of type 'List' cannot be used as an input of type 'List' for parameter 'b' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. + // (15,22): warning CS8620: Argument of type 'List' cannot be used for parameter 'b' of type 'List?' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. // F(ref b, ref c, ref d, ref a); - Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "c").WithArguments("List", "List", "b", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(15, 22), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "c").WithArguments("List", "List?", "b", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(15, 22), // (15,29): error CS0165: Use of unassigned local variable 'd' // F(ref b, ref c, ref d, ref a); Diagnostic(ErrorCode.ERR_UseDefViolation, "d").WithArguments("d").WithLocation(15, 29), + // (15,29): warning CS8620: Argument of type 'List?' cannot be used for parameter 'c' of type 'List' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. + // F(ref b, ref c, ref d, ref a); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "d").WithArguments("List?", "List", "c", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(15, 29), // (15,36): error CS0165: Use of unassigned local variable 'a' // F(ref b, ref c, ref d, ref a); Diagnostic(ErrorCode.ERR_UseDefViolation, "a").WithArguments("a").WithLocation(15, 36), - // (15,36): warning CS8620: Argument of type 'List' cannot be used as an input of type 'List' for parameter 'd' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. + // (15,36): warning CS8620: Argument of type 'List' cannot be used for parameter 'd' of type 'List?' in 'void C.F(ref List a, ref List? b, ref List c, ref List? d)' due to differences in the nullability of reference types. // F(ref b, ref c, ref d, ref a); - Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "a").WithArguments("List", "List", "d", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(15, 36), + Diagnostic(ErrorCode.WRN_NullabilityMismatchInArgument, "a").WithArguments("List", "List?", "d", "void C.F(ref List a, ref List? b, ref List c, ref List? d)").WithLocation(15, 36), // (23,15): error CS0165: Use of unassigned local variable 'b' // F(ref b!, ref c!, ref d!, ref a!); Diagnostic(ErrorCode.ERR_UseDefViolation, "b").WithArguments("b").WithLocation(23, 15), @@ -38202,12 +38744,18 @@ static void Main() // (7,9): error CS8598: The suppression operator is not allowed in this context // t! = s; Diagnostic(ErrorCode.ERR_IllegalSuppression, "t").WithLocation(7, 9), + // (7,14): warning CS8600: Converting null literal or possible null value to non-nullable type. + // t! = s; + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "s").WithLocation(7, 14), // (8,9): error CS8598: The suppression operator is not allowed in this context // t! += s; Diagnostic(ErrorCode.ERR_IllegalSuppression, "t").WithLocation(8, 9), // (9,10): error CS8598: The suppression operator is not allowed in this context // (t!) = s; - Diagnostic(ErrorCode.ERR_IllegalSuppression, "t").WithLocation(9, 10) + Diagnostic(ErrorCode.ERR_IllegalSuppression, "t").WithLocation(9, 10), + // (9,16): warning CS8600: Converting null literal or possible null value to non-nullable type. + // (t!) = s; + Diagnostic(ErrorCode.WRN_ConvertingNullableToNonNullable, "s").WithLocation(9, 16) ); } @@ -80582,8 +81130,11 @@ static void F(ref string x) } }"; var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); - // https://github.com/dotnet/roslyn/issues/33095: Missing warning. - comp.VerifyDiagnostics(); + comp.VerifyDiagnostics( + // (5,29): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. + // ref string? y = ref x; // 1 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("string", "string?").WithLocation(5, 29) + ); } [Fact] @@ -80603,11 +81154,14 @@ public void ByRefTarget_10() } }"; var comp = CreateCompilation(source, options: WithNonNullTypesTrue()); - // https://github.com/dotnet/roslyn/issues/33095: Missing warning. comp.VerifyDiagnostics( - // (5,20): warning CS8603: Possible null reference return. + // (5,20): warning CS8619: Nullability of reference types in value of type 'string?' doesn't match target type 'string'. // return ref x; // 1 - Diagnostic(ErrorCode.WRN_NullReferenceReturn, "x").WithLocation(5, 20)); + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "x").WithArguments("string?", "string").WithLocation(5, 20), + // (9,20): warning CS8619: Nullability of reference types in value of type 'string' doesn't match target type 'string?'. + // return ref y; // 2 + Diagnostic(ErrorCode.WRN_NullabilityMismatchInAssignment, "y").WithArguments("string", "string?").WithLocation(9, 20) + ); } [Fact]