Addressed remaining test items

All known outstanding tests are added. Also addressed all known
outstanding work items.
上级 433ff025
......@@ -12986,6 +12986,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to &apos;default&apos; is converted to &apos;null&apos;, not &apos;default({0})&apos;.
/// </summary>
internal static string WRN_DefaultLiteralConvertedToNullIsNotIntended {
get {
return ResourceManager.GetString("WRN_DefaultLiteralConvertedToNullIsNotIntended", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The default value specified for parameter &apos;{0}&apos; will have no effect because it applies to a member that is used in contexts that do not allow optional arguments.
/// </summary>
......
......@@ -5360,4 +5360,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="CannotCreateConstructedFromNongeneric" xml:space="preserve">
<value>Cannot create constructed generic type from non-generic type.</value>
</data>
</root>
<data name="WRN_DefaultLiteralConvertedToNullIsNotIntended" xml:space="preserve">
<value>'default' is converted to 'null', not 'default({0})'</value>
</data>
</root>
\ No newline at end of file
......@@ -1461,7 +1461,7 @@ internal enum ErrorCode
#region more stragglers for C# 7
ERR_VarInvocationLvalueReserved = 8199,
//ERR_ExpressionVariableInConstructorOrFieldInitializer = 8200,
//ERR_ExpressionVariableInQueryClause = 8201,
//ERR_ExpressionVariableInQueryClause = 8201,
ERR_PublicSignNetModule = 8202,
ERR_BadAssemblyName = 8203,
ERR_BadAsyncMethodBuilderTaskProperty = 8204,
......@@ -1582,6 +1582,7 @@ internal enum ErrorCode
#region diagnostics introduced for C# 8.0
ERR_FeatureNotAvailableInVersion8 = 8400,
ERR_AltInterpolatedVerbatimStringsNotAvailable = 8401,
WRN_DefaultLiteralConvertedToNullIsNotIntended = 8402,
#endregion diagnostics introduced for C# 8.0
}
// Note: you will need to re-generate compiler code after adding warnings (build\scripts\generate-compiler-code.cmd)
......
......@@ -180,6 +180,7 @@ public static bool IsWarning(ErrorCode code)
case ErrorCode.WRN_AttributesOnBackingFieldsNotAvailable:
case ErrorCode.WRN_TupleBinopLiteralNameMismatch:
case ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter:
case ErrorCode.WRN_DefaultLiteralConvertedToNullIsNotIntended:
return true;
default:
return false;
......
......@@ -47,20 +47,23 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
var isUnconstrainedTypeParameter = rewrittenLeft.Type != null && !rewrittenLeft.Type.IsReferenceType && !rewrittenLeft.Type.IsValueType;
// first we can make a small optimization:
// If left is a constant then we already know whether it is null or not. If it is null then we
// If left is a constant then we already know whether it is null or not. If it is null then we
// can simply generate "right". If it is not null then we can simply generate
// MakeConversion(left). This does not hold when the left is an unconstrained type parameter: at runtime,
// it can be either left or right depending on the runtime type of T
if (rewrittenLeft.IsDefaultValue() && !isUnconstrainedTypeParameter)
if (!isUnconstrainedTypeParameter)
{
return rewrittenRight;
}
if (rewrittenLeft.IsDefaultValue())
{
return rewrittenRight;
}
if (rewrittenLeft.ConstantValue != null && !isUnconstrainedTypeParameter)
{
Debug.Assert(!rewrittenLeft.ConstantValue.IsNull);
if (rewrittenLeft.ConstantValue != null)
{
Debug.Assert(!rewrittenLeft.ConstantValue.IsNull);
return GetConvertedLeftForNullCoalescingOperator(rewrittenLeft, leftConversion, rewrittenResultType);
return GetConvertedLeftForNullCoalescingOperator(rewrittenLeft, leftConversion, rewrittenResultType);
}
}
// string concatenation is never null.
......@@ -125,7 +128,7 @@ public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperato
return BoundCall.Synthesized(rewrittenLeft.Syntax, rewrittenLeft, getValueOrDefault);
}
// We lower left ?? right to
// We lower left ?? right to
//
// var temp = left;
// (temp != null) ? MakeConversion(temp) : right
......
......@@ -8714,6 +8714,7 @@ internal static bool IsRightAssociative(SyntaxKind op)
case SyntaxKind.OrAssignmentExpression:
case SyntaxKind.LeftShiftAssignmentExpression:
case SyntaxKind.RightShiftAssignmentExpression:
case SyntaxKind.CoalesceAssignmentExpression:
case SyntaxKind.CoalesceExpression:
return true;
default:
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -422,6 +422,11 @@
<target state="new">SyntaxTree is not part of the compilation, so it cannot be removed</target>
<note />
</trans-unit>
<trans-unit id="WRN_DefaultLiteralConvertedToNullIsNotIntended">
<source>'default' is converted to 'null', not 'default({0})'</source>
<target state="new">'default' is converted to 'null', not 'default({0})'</target>
<note />
</trans-unit>
<trans-unit id="WRN_TypeParameterSameAsOuterMethodTypeParameter">
<source>Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</source>
<target state="new">Type parameter '{0}' has the same name as the type parameter from outer method '{1}'</target>
......
......@@ -419,8 +419,8 @@ public static void M456()
static C GetC() { Console.Write(""GetC""); return c; }
byte f;
public static void Main()
{
public static void Main()
{
C.c = new C();
D d123 = M123;
D d456 = M456;
......@@ -844,7 +844,7 @@ static void Main()
{
string myStr = ""goo"";
object o = myStr;
object b = o as string;
object b = o as string;
TestType tt = null;
o = tt;
......@@ -853,7 +853,7 @@ static void Main()
tt = new TestType();
o = tt;
b = o as AnotherType;
b = o as MyInter;
MyInter mi = new TestType();
......@@ -862,13 +862,13 @@ static void Main()
MyBase mb = new MyBase();
o = mb;
b = o as MyDerived;
b = o as MyDerived;
MyDerived md = new MyDerived();
o = md;
b = o as MyBase;
b = null as MyBase;
b = null as MyBase;
}
}
}
......@@ -1384,6 +1384,13 @@ static void Goo<T>(T x1, T x2)
{
Console.WriteLine(x1 ?? x2);
}
static void Goo2<T1, T2>(T1 t1, T2 t2, dynamic d) where T1 : T2
{
// Verifying no type errors
T2 t = t1 ?? t2;
dynamic d2 = t1 ?? d;
}
}
";
var comp = CompileAndVerify(source, expectedOutput: @"
......@@ -3504,7 +3511,7 @@ public static void Main()
// Can't actually see an unchecked cast here since only constant values are emitted.
comp.VerifyIL("A.Main", @"
{
{
// Code size 13 (0xd)
.maxstack 2
.locals init (A.E V_0) //e
......@@ -5361,7 +5368,7 @@ struct S1
public static implicit operator bool (S1 x)
{
return true;
}
}
}
";
......@@ -5551,7 +5558,7 @@ static void Main()
System.Console.WriteLine(CoalesceDifferentTupleNames(null));
}
}";
var expectedOutput =
var expectedOutput =
@"(True, 533d4d3b-5013-461e-ae9e-b98eb593d761, value)
(False, 00000000-0000-0000-0000-000000000000, )";
var comp = CompileAndVerify(source, expectedOutput: expectedOutput);
......@@ -5729,7 +5736,7 @@ static int Coalesce(int? x)
}";
var comp = CreateCompilation(source);
comp.MakeMemberMissing(SpecialMember.System_Nullable_T_GetValueOrDefault);
comp.VerifyEmitDiagnostics(
// (6,16): error CS0656: Missing compiler required member 'System.Nullable`1.GetValueOrDefault'
// return x ?? 0;
......
......@@ -131,5 +131,35 @@ void assertTypeInfo(SyntaxNode syntax)
}
}
[Fact]
public void CoalesceAssignment_NotConvertedToNonNullable()
{
var source = @"
class C
{
void M(int? a, int b)
{
a ??= b;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.Regular8);
comp.VerifyDiagnostics();
var syntaxTree = comp.SyntaxTrees.Single();
var syntaxRoot = syntaxTree.GetRoot();
var semanticModel = comp.GetSemanticModel(syntaxTree);
var coalesceAssignment = syntaxRoot.DescendantNodes().OfType<AssignmentExpressionSyntax>().Single();
var nullable = comp.GetSpecialType(SpecialType.System_Nullable_T);
var int32 = comp.GetSpecialType(SpecialType.System_Int32);
var coalesceType = semanticModel.GetTypeInfo(coalesceAssignment).Type;
var genericParameter = ((INamedTypeSymbol)coalesceType).TypeArguments.Single();
Assert.Equal(nullable, coalesceType.OriginalDefinition);
Assert.Equal(int32, genericParameter);
}
}
}
......@@ -3944,6 +3944,33 @@ public void NullCoalesingAssigmentExpressionAndCoalescingOperator()
EOF();
}
[Fact]
public void NullCoalescingAssignmentExpressionNested()
{
UsingExpression("a ??= b ??= c");
N(SyntaxKind.CoalesceAssignmentExpression);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "a");
}
N(SyntaxKind.QuestionQuestionEqualsToken);
N(SyntaxKind.CoalesceAssignmentExpression);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "b");
}
N(SyntaxKind.QuestionQuestionEqualsToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "c");
}
}
}
EOF();
}
[Fact]
public void NullCoalescingAssignmentCSharp7_3()
{
......@@ -3951,6 +3978,19 @@ public void NullCoalescingAssignmentCSharp7_3()
// (1,3): error CS8370: Feature 'coalescing assignment' is not available in C# 7.3. Please use language version 8.0 or greater.
// a ??= b
Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_3, "??=").WithArguments("coalescing assignment", "8.0").WithLocation(1, 3));
N(SyntaxKind.CoalesceAssignmentExpression);
{
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "a");
}
N(SyntaxKind.QuestionQuestionEqualsToken);
N(SyntaxKind.IdentifierName);
{
N(SyntaxKind.IdentifierToken, "b");
}
}
EOF();
}
}
}
......@@ -2858,7 +2858,7 @@ public override IOperation VisitCoalesceAssignment(ICoalesceAssignmentOperation
SpillEvalStack();
int valueCaptureId = GetNextCaptureId(valueFrame.RegionBuilderOpt);
AddStatement(new FlowCapture(valueCaptureId, locationCapture.Syntax, locationCapture));
IOperation valueCapture = GetCaptureReference(valueCaptureId, OperationCloner.CloneOperation(locationCapture));
IOperation valueCapture = GetCaptureReference(valueCaptureId, locationCapture);
var whenNull = new BasicBlockBuilder(BasicBlockKind.Block);
var afterCoalesce = new BasicBlockBuilder(BasicBlockKind.Block);
......@@ -2891,7 +2891,7 @@ public override IOperation VisitCoalesceAssignment(ICoalesceAssignmentOperation
IOperation whenNullValue = Visit(operation.Value);
IOperation whenNullAssignment = new SimpleAssignmentExpression(OperationCloner.CloneOperation(locationCapture), isRef: false, whenNullValue, semanticModel: null,
operation.Syntax, operation.Type, constantValue: operation.ConstantValue, isImplicit: true);
operation.Syntax, operation.Type, constantValue: operation.ConstantValue, isImplicit: true);
if (isStatement)
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册