提交 60f8e76a 编写于 作者: N Neal Gafter

Add tests to improve code coverage for pattern-matching

Fixes #31145
上级 b4b406b3
......@@ -245,7 +245,6 @@ private BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSymbol in
TypeSymbol inputType,
TypeSymbol patternType,
bool patternTypeWasInSource,
bool isVar,
DiagnosticBag diagnostics)
{
Debug.Assert((object)inputType != null);
......@@ -261,7 +260,7 @@ private BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSymbol in
diagnostics.Add(ErrorCode.ERR_PointerTypeInPatternMatching, typeSyntax.Location);
return true;
}
else if (patternType.IsNullableType() && !isVar && patternTypeWasInSource)
else if (patternType.IsNullableType() && patternTypeWasInSource)
{
// It is an error to use pattern-matching with a nullable type, because you'll never get null. Use the underlying type.
Error(diagnostics, ErrorCode.ERR_PatternNullableType, typeSyntax, patternType, patternType.GetNullableUnderlyingType());
......@@ -272,7 +271,7 @@ private BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSymbol in
Error(diagnostics, ErrorCode.ERR_VarDeclIsStaticClass, typeSyntax, patternType);
return true;
}
else if (!isVar)
else
{
if (patternType.IsDynamic())
{
......@@ -348,9 +347,7 @@ private BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSymbol in
DiagnosticBag diagnostics)
{
TypeSyntax typeSyntax = node.Type;
BoundTypeExpression boundDeclType = BindPatternType(typeSyntax, inputType, diagnostics, ref hasErrors, out bool isVar);
Debug.Assert(!typeSyntax.IsVar); // if the syntax had `var`, it would have been parsed as a var pattern.
Debug.Assert(!isVar);
BoundTypeExpression boundDeclType = BindPatternType(typeSyntax, inputType, diagnostics, ref hasErrors);
TypeSymbol declType = boundDeclType.Type;
inputValEscape = GetValEscape(declType, inputValEscape);
BindPatternDesignation(node, node.Designation, boundDeclType.Type, inputValEscape, typeSyntax, diagnostics, ref hasErrors, out Symbol variableSymbol, out BoundExpression variableAccess);
......@@ -361,27 +358,16 @@ private BoundPattern BindDiscardPattern(DiscardPatternSyntax node, TypeSymbol in
TypeSyntax typeSyntax,
TypeSymbol inputType,
DiagnosticBag diagnostics,
ref bool hasErrors,
out bool isVar)
ref bool hasErrors)
{
Debug.Assert(inputType != (object)null);
Debug.Assert(!typeSyntax.IsVar); // if the syntax had `var`, it would have been parsed as a var pattern.
AliasSymbol aliasOpt;
TypeSymbolWithAnnotations declType = BindTypeOrVarKeyword(typeSyntax, diagnostics, out isVar, out aliasOpt);
if (isVar)
{
declType = TypeSymbolWithAnnotations.Create(NonNullTypesContext, inputType);
}
if (declType.IsNull)
{
Debug.Assert(hasErrors);
declType = TypeSymbolWithAnnotations.Create(NonNullTypesContext, this.CreateErrorType("var"));
}
BoundTypeExpression boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: isVar, type: declType.TypeSymbol);
hasErrors |= CheckValidPatternType(typeSyntax, inputType, declType.TypeSymbol,
isVar: isVar, patternTypeWasInSource: true, diagnostics: diagnostics);
TypeSymbolWithAnnotations declType = BindTypeOrVarKeyword(typeSyntax, diagnostics, out bool isVar, out aliasOpt);
Debug.Assert(!isVar); // if the type were `var`, it would not have been parsed as a pattern's type
Debug.Assert(!declType.IsNull);
BoundTypeExpression boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt, inferredType: false, type: declType.TypeSymbol);
hasErrors |= CheckValidPatternType(typeSyntax, inputType, declType.TypeSymbol, patternTypeWasInSource: true, diagnostics: diagnostics);
return boundDeclType;
}
......@@ -464,19 +450,7 @@ TypeSymbol BindRecursivePatternType(TypeSyntax typeSyntax, TypeSymbol inputType,
{
if (typeSyntax != null)
{
boundDeclType = BindPatternType(typeSyntax, inputType, diagnostics, ref hasErrors, out bool isVar);
if (isVar)
{
// The type `var` is not permitted in recursive patterns. If you want the type inferred, just omit it.
if (!hasErrors)
{
diagnostics.Add(ErrorCode.ERR_InferredRecursivePatternType, typeSyntax.Location);
hasErrors = true;
}
boundDeclType = new BoundTypeExpression(typeSyntax, aliasOpt: null, inferredType: true, type: inputType.StrippedType(), hasErrors: hasErrors);
}
boundDeclType = BindPatternType(typeSyntax, inputType, diagnostics, ref hasErrors);
return boundDeclType.Type;
}
else
......@@ -629,10 +603,6 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
diagnostics.Add(ErrorCode.ERR_DeconstructParameterNameMismatch, subPattern.NameColon.Name.Location, name, parameterName);
}
}
else
{
Debug.Assert(deconstructMethod is ErrorMethodSymbol);
}
}
var boundSubpattern = new BoundSubpattern(
......@@ -677,6 +647,7 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
if (node.DeconstructionPatternClause == null)
{
// ITuple matching only applies if there is a deconstruction pattern part.
// This can only occur as a result of syntax error recovery, if at all.
return false;
}
......@@ -686,11 +657,6 @@ private BoundPattern BindRecursivePattern(RecursivePatternSyntax node, TypeSymbo
return false;
}
if (Compilation.LanguageVersion < MessageID.IDS_FeatureRecursivePatterns.RequiredVersion())
{
return false;
}
iTupleType = Compilation.GetWellKnownType(WellKnownType.System_Runtime_CompilerServices_ITuple);
if (iTupleType.TypeKind != TypeKind.Interface)
{
......@@ -829,7 +795,7 @@ private BoundPattern BindVarDesignation(VarPatternSyntax node, VariableDesignati
{
var location = new SourceLocation(node.SyntaxTree,
new Text.TextSpan(tupleDesignation.OpenParenToken.SpanStart, tupleDesignation.CloseParenToken.Span.End - tupleDesignation.OpenParenToken.SpanStart));
diagnostics.Add(ErrorCode.ERR_WrongNumberOfSubpatterns, location, inputType.TupleElementTypes, elementTypes.Length, tupleDesignation.Variables.Count);
diagnostics.Add(ErrorCode.ERR_WrongNumberOfSubpatterns, location, inputType.ToDisplayString(), elementTypes.Length, tupleDesignation.Variables.Count);
hasErrors = true;
}
for (int i = 0; i < tupleDesignation.Variables.Count; i++)
......
......@@ -19,7 +19,7 @@ namespace Microsoft.CodeAnalysis.CSharp {
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class CSharpResources {
......@@ -5640,15 +5640,6 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to The type &apos;var&apos; is not permitted in recursive patterns. If you want the type inferred, just omit it..
/// </summary>
internal static string ERR_InferredRecursivePatternType {
get {
return ResourceManager.GetString("ERR_InferredRecursivePatternType", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Cannot initialize a by-reference variable with a value.
/// </summary>
......@@ -8368,7 +8359,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to A property subpattern requires a reference to the property or field to be matched, e.g. &apos;{{ Name: {0}}}&apos;.
/// Looks up a localized string similar to A property subpattern requires a reference to the property or field to be matched, e.g. &apos;{{ Name: {0} }}&apos;.
/// </summary>
internal static string ERR_PropertyPatternNameMissing {
get {
......
......@@ -5571,14 +5571,11 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="IDS_FeatureRecursivePatterns" xml:space="preserve">
<value>recursive patterns</value>
</data>
<data name="ERR_InferredRecursivePatternType" xml:space="preserve">
<value>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</value>
</data>
<data name="ERR_WrongNumberOfSubpatterns" xml:space="preserve">
<value>Matching the tuple type '{0}' requires '{1}' subpatterns, but '{2}' subpatterns are present.</value>
</data>
<data name="ERR_PropertyPatternNameMissing" xml:space="preserve">
<value>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</value>
<value>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</value>
</data>
<data name="ERR_DefaultPattern" xml:space="preserve">
<value>A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.</value>
......
......@@ -1595,7 +1595,7 @@ internal enum ErrorCode
ERR_NoConvToIDispWrongAsync = 8418,
#region diagnostics introduced for recursive patterns
ERR_InferredRecursivePatternType = 8501,
// ERR_InferredRecursivePatternType = 8501, // unused
ERR_WrongNumberOfSubpatterns = 8502,
ERR_PropertyPatternNameMissing = 8503,
ERR_MissingPattern = 8504,
......
......@@ -177,6 +177,12 @@ public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstruct
return null;
}
public override BoundNode VisitIncrementOperator(BoundIncrementOperator node)
{
_mightAssignSomething = true;
return null;
}
public override BoundNode VisitDynamicInvocation(BoundDynamicInvocation node)
{
// perhaps we are passing a variable by ref and mutating it that way
......@@ -199,12 +205,14 @@ public override BoundNode VisitDynamicObjectCreationExpression(BoundDynamicObjec
public override BoundNode VisitObjectInitializerMember(BoundObjectInitializerMember node)
{
// Although ref indexers are not declarable in C#, they may be usable
_mightAssignSomething = !node.ArgumentRefKindsOpt.IsDefault;
return base.VisitObjectInitializerMember(node);
}
public override BoundNode VisitIndexerAccess(BoundIndexerAccess node)
{
// Although property arguments with ref indexers are not declarable in C#, they may be usable
_mightAssignSomething = !node.ArgumentRefKindsOpt.IsDefault;
return base.VisitIndexerAccess(node);
}
......@@ -456,6 +464,7 @@ private void EnsureStringHashFunction(int labelsCount, SyntaxNode syntaxNode)
var module = _localRewriter.EmitModule;
if (module == null)
{
// we're not generating code, so we don't need the hash function
return;
}
......@@ -511,22 +520,7 @@ private void LowerWhenClause(BoundWhenDecisionDagNode whenClause)
LabelSymbol labelToSectionScope = GetDagNodeLabel(whenClause);
// We need the section syntax to get the section builder from the map. Unfortunately this is a bit awkward
SyntaxNode sectionSyntax;
switch (whenClause.Syntax)
{
case WhenClauseSyntax w:
sectionSyntax = w.Parent.Parent;
break;
case SwitchLabelSyntax l:
sectionSyntax = l.Parent;
break;
case SwitchExpressionArmSyntax a:
sectionSyntax = a;
break;
default:
throw ExceptionUtilities.UnexpectedValue(whenClause.Syntax.Kind());
}
SyntaxNode sectionSyntax = whenClause.Syntax is SwitchLabelSyntax l ? l.Parent : whenClause.Syntax;
bool foundSectionBuilder = _switchArms.TryGetValue(sectionSyntax, out ArrayBuilder<BoundStatement> sectionBuilder);
Debug.Assert(foundSectionBuilder);
sectionBuilder.Add(_factory.Label(labelToSectionScope));
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -122,11 +122,6 @@
<target state="new">Arguments with 'in' modifier cannot be used in dynamically dispatched expessions.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InferredRecursivePatternType">
<source>The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</source>
<target state="new">The type 'var' is not permitted in recursive patterns. If you want the type inferred, just omit it.</target>
<note />
</trans-unit>
<trans-unit id="ERR_InterfaceImplementedImplicitlyByVariadic">
<source>'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</source>
<target state="new">'{0}' cannot implement interface member '{1}' in type '{2}' because it has an __arglist parameter</target>
......@@ -198,8 +193,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_PropertyPatternNameMissing">
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0}}}'</target>
<source>A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</source>
<target state="new">A property subpattern requires a reference to the property or field to be matched, e.g. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
......
......@@ -1969,5 +1969,118 @@ .maxstack 1
IL_0016: ret
}");
}
[Fact]
public void DoNotShareInputForMutatingWhenClause()
{
var source =
@"using System;
class Program
{
static void Main()
{
Console.Write(M1(1));
Console.Write(M2(1));
Console.Write(M3(1));
Console.Write(M4(1));
Console.Write(M5(1));
Console.Write(M6(1));
}
public static int M1(int x)
{
return x switch { _ when (++x) == 5 => 1, 1 => 2, _ => 3 };
}
public static int M2(int x)
{
return x switch { _ when (x+=1) == 5 => 1, 1 => 2, _ => 3 };
}
public static int M3(int x)
{
return x switch { _ when ((x, _) = (5, 6)) == (0, 0) => 1, 1 => 2, _ => 3 };
}
public static int M4(int x)
{
dynamic d = new Program();
return x switch { _ when d.M(ref x) => 1, 1 => 2, _ => 3 };
}
bool M(ref int x) { x = 100; return false; }
public static int M5(int x)
{
return x switch { _ when new Program(ref x).P => 1, 1 => 2, _ => 3 };
}
public static int M6(int x)
{
dynamic d = x;
return x switch { _ when new Program(d, ref x).P => 1, 1 => 2, _ => 3 };
}
Program() { }
Program(ref int x) { x = 100; }
Program(int a, ref int x) { x = 100; }
bool P => false;
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe, references: new[] { CSharpRef });
compilation.VerifyDiagnostics();
var expectedOutput = @"222222";
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
}
[Fact]
public void GenerateStringHashOnlyOnce()
{
var source =
@"using System;
class Program
{
static void Main()
{
Console.Write(M1(string.Empty));
Console.Write(M2(string.Empty));
}
public static int M1(string s)
{
return s switch { ""a""=>1, ""b""=>2, ""c""=>3, ""d""=>4, ""e""=>5, ""f""=>6, ""g""=>7, ""h""=>8, _ => 9 };
}
public static int M2(string s)
{
return s switch { ""a""=>1, ""b""=>2, ""c""=>3, ""d""=>4, ""e""=>5, ""f""=>6, ""g""=>7, ""h""=>8, _ => 9 };
}
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
compilation.VerifyDiagnostics();
var expectedOutput = @"99";
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
}
[Fact]
public void BindVariablesInWhenClause()
{
var source =
@"using System;
class Program
{
static void Main()
{
var t = (1, 2);
switch (t)
{
case var (x, y) when x+1 == y:
Console.Write(1);
break;
}
Console.Write(t switch
{
var (x, y) when x+1 == y => 1,
_ => 2
});
}
}
";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe);
compilation.VerifyDiagnostics();
var expectedOutput = @"11";
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
}
}
}
......@@ -1489,6 +1489,288 @@ static int M1(bool? b1, bool? b2)
);
}
[Fact]
public void WrongNumberOfDesignatorsForTuple()
{
var source =
@"class Program
{
static void Main()
{
_ = (1, 2) is var (_, _, _);
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (5,27): error CS8502: Matching the tuple type '(int, int)' requires '2' subpatterns, but '3' subpatterns are present.
// _ = (1, 2) is var (_, _, _);
Diagnostic(ErrorCode.ERR_WrongNumberOfSubpatterns, "(_, _, _)").WithArguments("(int, int)", "2", "3").WithLocation(5, 27)
);
}
[Fact]
public void PropertyNameMissing()
{
var source =
@"class Program
{
static void Main()
{
_ = (1, 2) is { 1, 2 };
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (5,25): error CS8503: A property subpattern requires a reference to the property or field to be matched, e.g. '{ Name: 1 }'
// _ = (1, 2) is { 1, 2 };
Diagnostic(ErrorCode.ERR_PropertyPatternNameMissing, "1").WithArguments("1").WithLocation(5, 25)
);
}
[Fact]
public void IndexedProperty_01()
{
var source1 =
@"Imports System
Imports System.Runtime.InteropServices
<Assembly: PrimaryInteropAssembly(0, 0)>
<Assembly: Guid(""165F752D-E9C4-4F7E-B0D0-CDFD7A36E210"")>
<ComImport()>
<Guid(""165F752D-E9C4-4F7E-B0D0-CDFD7A36E211"")>
Public Interface I
Property P(x As Object, Optional y As Object = Nothing) As Object
End Interface";
var reference1 = BasicCompilationUtils.CompileToMetadata(source1);
var source2 =
@"class C
{
static void Main(I i)
{
_ = i is { P: 1 };
}
}";
var compilation2 = CreateCompilation(source2, new[] { reference1 });
compilation2.VerifyDiagnostics(
// (5,20): error CS0857: Indexed property 'I.P' must have all arguments optional
// _ = i is { P: 1 };
Diagnostic(ErrorCode.ERR_IndexedPropertyMustHaveAllOptionalParams, "P").WithArguments("I.P").WithLocation(5, 20)
);
}
[Fact, WorkItem(31209, "https://github.com/dotnet/roslyn/issues/31209")]
public void IndexedProperty_02()
{
var source1 =
@"Imports System
Imports System.Runtime.InteropServices
<Assembly: PrimaryInteropAssembly(0, 0)>
<Assembly: Guid(""165F752D-E9C4-4F7E-B0D0-CDFD7A36E210"")>
<ComImport()>
<Guid(""165F752D-E9C4-4F7E-B0D0-CDFD7A36E211"")>
Public Interface I
Property P(Optional x As Object = Nothing, Optional y As Object = Nothing) As Object
End Interface";
var reference1 = BasicCompilationUtils.CompileToMetadata(source1);
var source2 =
@"class C
{
static void Main(I i)
{
_ = i is { P: 1 };
}
}";
var compilation2 = CreateCompilation(source2, new[] { reference1 });
// https://github.com/dotnet/roslyn/issues/31209 asks what the desired behavior is for this case.
// This test demonstrates that we at least behave rationally and do not crash.
compilation2.VerifyDiagnostics(
// (5,20): error CS0154: The property or indexer 'P' cannot be used in this context because it lacks the get accessor
// _ = i is { P: 1 };
Diagnostic(ErrorCode.ERR_PropertyLacksGet, "P").WithArguments("P").WithLocation(5, 20)
);
}
[Fact]
public void TestMissingIntegralTypes()
{
var source =
@"public class C
{
public static void Main()
{
M(1U);
M(2UL);
M(1);
M(2);
M(3);
}
static void M(object o)
{
System.Console.Write(o switch {
(uint)1 => 1,
(ulong)2 => 2,
1 => 3,
2 => 4,
_ => 5 });
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics();
CompileAndVerify(compilation, expectedOutput: "12345");
}
[Fact]
public void TestConvertInputTupleToInterface()
{
var source =
@"#pragma warning disable CS0436 // The type 'ValueTuple<T1, T2>' conflicts with the imported type
using System.Runtime.CompilerServices;
using System;
public class C
{
public static void Main()
{
Console.Write((1, 2) switch
{
ITuple t => 3
});
}
}
namespace System
{
struct ValueTuple<T1, T2> : ITuple
{
int ITuple.Length => 2;
object ITuple.this[int i] => i switch { 0 => (object)Item1, 1 => (object)Item2, _ => throw null };
public T1 Item1;
public T2 Item2;
public ValueTuple(T1 item1, T2 item2) => (Item1, Item2) = (item1, item2);
}
}";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics();
CompileAndVerify(compilation, expectedOutput: "3");
}
[Fact]
public void TestUnusedTupleInput()
{
var source =
@"using System;
public class C
{
public static void Main()
{
Console.Write((M(1), M(2)) switch { _ => 3 });
}
static int M(int x) { Console.Write(x); return x; }
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics();
CompileAndVerify(compilation, expectedOutput: "123");
}
[Fact]
public void TestNestedTupleOpt()
{
var source =
@"using System;
public class C
{
public static void Main()
{
var x = (1, 20);
Console.Write((x, 300) switch { ((1, int x2), int y) => x2+y });
}
}
";
var compilation = CreatePatternCompilation(source, options: TestOptions.ReleaseExe);
compilation.VerifyDiagnostics(
// (7,32): warning CS8509: The switch expression does not handle all possible inputs (it is not exhaustive).
// Console.Write((x, 300) switch { ((1, int x2), int y) => x2+y });
Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithLocation(7, 32)
);
CompileAndVerify(compilation, expectedOutput: "320");
}
[Fact]
public void TestGotoCaseTypeMismatch()
{
var source =
@"public class C
{
public static void Main()
{
int i = 1;
switch (i)
{
case 1:
if (i == 1)
goto case string.Empty;
break;
}
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (10,21): error CS0029: Cannot implicitly convert type 'string' to 'int'
// goto case string.Empty;
Diagnostic(ErrorCode.ERR_NoImplicitConv, "goto case string.Empty;").WithArguments("string", "int").WithLocation(10, 21)
);
}
[Fact]
public void TestGotoCaseNotConstant()
{
var source =
@"public class C
{
public static void Main()
{
int i = 1;
switch (i)
{
case 1:
if (i == 1)
goto case string.Empty.Length;
break;
}
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (10,21): error CS0150: A constant value is expected
// goto case string.Empty.Length;
Diagnostic(ErrorCode.ERR_ConstantExpected, "goto case string.Empty.Length;").WithLocation(10, 21)
);
}
[Fact]
public void TestExhaustiveWithNullTest()
{
var source =
@"public class C
{
public static void Main()
{
object o = null;
_ = o switch { null => 1 };
}
}
";
var compilation = CreatePatternCompilation(source);
compilation.VerifyDiagnostics(
// (6,15): warning CS8509: The switch expression does not handle all possible inputs (it is not exhaustive).
// _ = o switch { null => 1 };
Diagnostic(ErrorCode.WRN_SwitchExpressionNotExhaustive, "switch").WithLocation(6, 15)
);
}
[Fact, WorkItem(31167, "https://github.com/dotnet/roslyn/issues/31167")]
public void NonExhaustiveBoolSwitchExpression()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册