Skip to content

Commit f020a37

Browse files
authored
1 parent c44c7e8 commit f020a37

30 files changed

+7469
-164
lines changed

src/Compilers/CSharp/Portable/Binder/Binder_Deconstruct.cs

Lines changed: 84 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -409,9 +409,10 @@ private void FailRemainingInferencesAndSetValEscape(ArrayBuilder<DeconstructionV
409409
{
410410
case BoundKind.Local:
411411
var local = (BoundLocal)variable.Single;
412-
if (local.DeclarationKind != BoundLocalDeclarationKind.None)
412+
if (local.DeclarationKind != BoundLocalDeclarationKind.None &&
413+
local.LocalSymbol is SourceLocalSymbol { ValEscapeScope: CallingMethodScope } localSymbol)
413414
{
414-
((SourceLocalSymbol)local.LocalSymbol).SetValEscape(rhsValEscape);
415+
localSymbol.SetValEscape(rhsValEscape);
415416
}
416417
break;
417418
case BoundKind.DeconstructionVariablePendingInference:
@@ -760,7 +761,7 @@ private DeconstructionVariable BindDeconstructionVariables(
760761
bool isVar;
761762
bool isConst = false;
762763
AliasSymbol alias;
763-
var declType = BindVariableTypeWithAnnotations(component.Designation, diagnostics, component.Type, ref isConst, out isVar, out alias);
764+
var declType = BindVariableTypeWithAnnotations(component.Designation, diagnostics, component.Type.SkipScoped(out _).SkipRef(out _), ref isConst, out isVar, out alias);
764765
Debug.Assert(isVar == !declType.HasType);
765766
if (component.Designation.Kind() == SyntaxKind.ParenthesizedVariableDesignation && !isVar)
766767
{
@@ -814,6 +815,23 @@ private DeconstructionVariable BindDeconstructionVariables(
814815
case SyntaxKind.DiscardDesignation:
815816
{
816817
var discarded = (DiscardDesignationSyntax)node;
818+
819+
if (discarded.Parent is DeclarationExpressionSyntax declExpr && declExpr.Designation == discarded)
820+
{
821+
TypeSyntax typeSyntax = declExpr.Type;
822+
823+
if (typeSyntax is ScopedTypeSyntax scopedType)
824+
{
825+
diagnostics.Add(ErrorCode.ERR_ScopedDiscard, scopedType.ScopedKeyword.GetLocation());
826+
typeSyntax = scopedType.Type;
827+
}
828+
829+
if (typeSyntax is RefTypeSyntax refType)
830+
{
831+
diagnostics.Add(ErrorCode.ERR_DeconstructVariableCannotBeByRef, refType.RefKeyword.GetLocation());
832+
}
833+
}
834+
817835
return new DeconstructionVariable(BindDiscardExpression(syntax, declTypeWithAnnotations), syntax);
818836
}
819837
case SyntaxKind.ParenthesizedVariableDesignation:
@@ -855,6 +873,29 @@ private BoundExpression BindDeconstructionVariable(
855873
// is this a local?
856874
if ((object)localSymbol != null)
857875
{
876+
if (designation.Parent is DeclarationExpressionSyntax declExpr && declExpr.Designation == designation)
877+
{
878+
TypeSyntax typeSyntax = declExpr.Type;
879+
880+
if (typeSyntax is ScopedTypeSyntax scopedType)
881+
{
882+
// Check for support for 'scoped'.
883+
ModifierUtils.CheckScopedModifierAvailability(typeSyntax, scopedType.ScopedKeyword, diagnostics);
884+
typeSyntax = scopedType.Type;
885+
}
886+
887+
if (typeSyntax is RefTypeSyntax refType)
888+
{
889+
diagnostics.Add(ErrorCode.ERR_DeconstructVariableCannotBeByRef, refType.RefKeyword.GetLocation());
890+
}
891+
892+
if (declTypeWithAnnotations.HasType &&
893+
localSymbol.Scope == DeclarationScope.ValueScoped && !declTypeWithAnnotations.Type.IsErrorTypeOrRefLikeType())
894+
{
895+
diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location);
896+
}
897+
}
898+
858899
// Check for variable declaration errors.
859900
// Use the binder that owns the scope for the local because this (the current) binder
860901
// might own nested scope.
@@ -867,33 +908,51 @@ private BoundExpression BindDeconstructionVariable(
867908

868909
return new DeconstructionVariablePendingInference(syntax, localSymbol, receiverOpt: null);
869910
}
911+
else
912+
{
913+
// Is this a field?
914+
GlobalExpressionVariable field = LookupDeclaredField(designation);
870915

871-
// Is this a field?
872-
GlobalExpressionVariable field = LookupDeclaredField(designation);
916+
if ((object)field == null)
917+
{
918+
// We should have the right binder in the chain, cannot continue otherwise.
919+
throw ExceptionUtilities.Unreachable();
920+
}
873921

874-
if ((object)field == null)
875-
{
876-
// We should have the right binder in the chain, cannot continue otherwise.
877-
throw ExceptionUtilities.Unreachable();
878-
}
922+
if (designation.Parent is DeclarationExpressionSyntax declExpr && declExpr.Designation == designation)
923+
{
924+
TypeSyntax typeSyntax = declExpr.Type;
879925

880-
BoundThisReference receiver = ThisReference(designation, this.ContainingType, hasErrors: false,
881-
wasCompilerGenerated: true);
926+
if (typeSyntax is ScopedTypeSyntax scopedType)
927+
{
928+
diagnostics.Add(ErrorCode.ERR_UnexpectedToken, scopedType.ScopedKeyword.GetLocation(), scopedType.ScopedKeyword.ValueText);
929+
typeSyntax = scopedType.Type;
930+
}
882931

883-
if (declTypeWithAnnotations.HasType)
884-
{
885-
var fieldType = field.GetFieldType(this.FieldsBeingBound);
886-
Debug.Assert(TypeSymbol.Equals(declTypeWithAnnotations.Type, fieldType.Type, TypeCompareKind.ConsiderEverything2));
887-
return new BoundFieldAccess(syntax,
888-
receiver,
889-
field,
890-
constantValueOpt: null,
891-
resultKind: LookupResultKind.Viable,
892-
isDeclaration: true,
893-
type: fieldType.Type);
894-
}
932+
if (typeSyntax is RefTypeSyntax refType)
933+
{
934+
diagnostics.Add(ErrorCode.ERR_UnexpectedToken, refType.RefKeyword.GetLocation(), refType.RefKeyword.ValueText);
935+
}
936+
}
937+
938+
BoundThisReference receiver = ThisReference(designation, this.ContainingType, hasErrors: false,
939+
wasCompilerGenerated: true);
895940

896-
return new DeconstructionVariablePendingInference(syntax, field, receiver);
941+
if (declTypeWithAnnotations.HasType)
942+
{
943+
var fieldType = field.GetFieldType(this.FieldsBeingBound);
944+
Debug.Assert(TypeSymbol.Equals(declTypeWithAnnotations.Type, fieldType.Type, TypeCompareKind.ConsiderEverything2));
945+
return new BoundFieldAccess(syntax,
946+
receiver,
947+
field,
948+
constantValueOpt: null,
949+
resultKind: LookupResultKind.Viable,
950+
isDeclaration: true,
951+
type: fieldType.Type);
952+
}
953+
954+
return new DeconstructionVariablePendingInference(syntax, field, receiver);
955+
}
897956
}
898957
}
899958
}

src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -889,7 +889,7 @@ private BoundExpression BindDeclarationExpressionAsError(DeclarationExpressionSy
889889
bool isVar;
890890
bool isConst = false;
891891
AliasSymbol alias;
892-
var declType = BindVariableTypeWithAnnotations(node.Designation, diagnostics, node.Type, ref isConst, out isVar, out alias);
892+
var declType = BindVariableTypeWithAnnotations(node.Designation, diagnostics, node.Type.SkipScoped(out _).SkipRef(out _), ref isConst, out isVar, out alias);
893893
Error(diagnostics, ErrorCode.ERR_DeclarationExpressionNotPermitted, node);
894894
return BindDeclarationVariablesForErrorRecovery(declType, node.Designation, node, diagnostics);
895895
}
@@ -2792,16 +2792,23 @@ private BoundExpression BindOutDeclarationArgument(DeclarationExpressionSyntax d
27922792
TypeSyntax typeSyntax = declarationExpression.Type;
27932793
VariableDesignationSyntax designation = declarationExpression.Designation;
27942794

2795-
Debug.Assert(typeSyntax is not ScopedTypeSyntax);
2796-
if (typeSyntax.SkipScoped(out _).GetRefKind() != RefKind.None)
2797-
{
2798-
diagnostics.Add(ErrorCode.ERR_OutVariableCannotBeByRef, declarationExpression.Type.Location);
2799-
}
28002795

28012796
switch (designation.Kind())
28022797
{
28032798
case SyntaxKind.DiscardDesignation:
28042799
{
2800+
if (typeSyntax is ScopedTypeSyntax scopedType)
2801+
{
2802+
diagnostics.Add(ErrorCode.ERR_ScopedDiscard, scopedType.ScopedKeyword.GetLocation());
2803+
typeSyntax = scopedType.Type;
2804+
}
2805+
2806+
if (typeSyntax is RefTypeSyntax refType)
2807+
{
2808+
diagnostics.Add(ErrorCode.ERR_OutVariableCannotBeByRef, refType.Location);
2809+
typeSyntax = refType.Type;
2810+
}
2811+
28052812
bool isVar;
28062813
bool isConst = false;
28072814
AliasSymbol alias;
@@ -2831,6 +2838,19 @@ private BoundExpression BindOutVariableDeclarationArgument(
28312838
SourceLocalSymbol localSymbol = this.LookupLocal(designation.Identifier);
28322839
if ((object)localSymbol != null)
28332840
{
2841+
if (typeSyntax is ScopedTypeSyntax scopedType)
2842+
{
2843+
// Check for support for 'scoped'.
2844+
ModifierUtils.CheckScopedModifierAvailability(typeSyntax, scopedType.ScopedKeyword, diagnostics);
2845+
typeSyntax = scopedType.Type;
2846+
}
2847+
2848+
if (typeSyntax is RefTypeSyntax refType)
2849+
{
2850+
diagnostics.Add(ErrorCode.ERR_OutVariableCannotBeByRef, refType.Location);
2851+
typeSyntax = refType.Type;
2852+
}
2853+
28342854
Debug.Assert(localSymbol.DeclarationKind == LocalDeclarationKind.OutVariable);
28352855
if ((InConstructorInitializer || InFieldInitializer) && ContainingMemberOrLambda.ContainingSymbol.Kind == SymbolKind.NamedType)
28362856
{
@@ -2850,38 +2870,57 @@ private BoundExpression BindOutVariableDeclarationArgument(
28502870

28512871
CheckRestrictedTypeInAsyncMethod(this.ContainingMemberOrLambda, declType.Type, diagnostics, typeSyntax);
28522872

2873+
if (localSymbol.Scope == DeclarationScope.ValueScoped && !declType.Type.IsErrorTypeOrRefLikeType())
2874+
{
2875+
diagnostics.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly, typeSyntax.Location);
2876+
}
2877+
28532878
return new BoundLocal(declarationExpression, localSymbol, BoundLocalDeclarationKind.WithExplicitType, constantValueOpt: null, isNullableUnknown: false, type: declType.Type);
28542879
}
2880+
else
2881+
{
2882+
// Is this a field?
2883+
GlobalExpressionVariable expressionVariableField = LookupDeclaredField(designation);
28552884

2856-
// Is this a field?
2857-
GlobalExpressionVariable expressionVariableField = LookupDeclaredField(designation);
2885+
if ((object)expressionVariableField == null)
2886+
{
2887+
// We should have the right binder in the chain, cannot continue otherwise.
2888+
throw ExceptionUtilities.Unreachable();
2889+
}
28582890

2859-
if ((object)expressionVariableField == null)
2860-
{
2861-
// We should have the right binder in the chain, cannot continue otherwise.
2862-
throw ExceptionUtilities.Unreachable();
2863-
}
2891+
BoundExpression receiver = SynthesizeReceiver(designation, expressionVariableField, diagnostics);
28642892

2865-
BoundExpression receiver = SynthesizeReceiver(designation, expressionVariableField, diagnostics);
2893+
if (typeSyntax is ScopedTypeSyntax scopedType)
2894+
{
2895+
diagnostics.Add(ErrorCode.ERR_UnexpectedToken, scopedType.ScopedKeyword.GetLocation(), scopedType.ScopedKeyword.ValueText);
2896+
typeSyntax = scopedType.Type;
2897+
}
28662898

2867-
if (typeSyntax.IsVar)
2868-
{
2869-
BindTypeOrAliasOrVarKeyword(typeSyntax, BindingDiagnosticBag.Discarded, out isVar);
2899+
if (typeSyntax is RefTypeSyntax refType)
2900+
{
2901+
diagnostics.Add(ErrorCode.ERR_UnexpectedToken, refType.RefKeyword.GetLocation(), refType.RefKeyword.ValueText);
2902+
typeSyntax = refType.Type;
2903+
}
28702904

2871-
if (isVar)
2905+
if (typeSyntax.IsVar)
28722906
{
2873-
return new OutVariablePendingInference(declarationExpression, expressionVariableField, receiver);
2907+
BindTypeOrAliasOrVarKeyword(typeSyntax, BindingDiagnosticBag.Discarded, out isVar);
2908+
2909+
if (isVar)
2910+
{
2911+
return new OutVariablePendingInference(declarationExpression, expressionVariableField, receiver);
2912+
}
28742913
}
2875-
}
28762914

2877-
TypeSymbol fieldType = expressionVariableField.GetFieldType(this.FieldsBeingBound).Type;
2878-
return new BoundFieldAccess(declarationExpression,
2879-
receiver,
2880-
expressionVariableField,
2881-
null,
2882-
LookupResultKind.Viable,
2883-
isDeclaration: true,
2884-
type: fieldType);
2915+
TypeSymbol fieldType = expressionVariableField.GetFieldType(this.FieldsBeingBound).Type;
2916+
return new BoundFieldAccess(declarationExpression,
2917+
receiver,
2918+
expressionVariableField,
2919+
null,
2920+
LookupResultKind.Viable,
2921+
isDeclaration: true,
2922+
type: fieldType);
2923+
}
28852924
}
28862925

28872926
/// <summary>

src/Compilers/CSharp/Portable/BoundTree/VariablePendingInference.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ internal BoundExpression SetInferredTypeWithAnnotations(TypeWithAnnotations type
6363
this.Syntax;
6464

6565
Binder.CheckRestrictedTypeInAsyncMethod(localSymbol.ContainingSymbol, type.Type, diagnosticsOpt, typeOrDesignationSyntax);
66+
67+
if (localSymbol.Scope == DeclarationScope.ValueScoped && !type.Type.IsErrorTypeOrRefLikeType())
68+
{
69+
diagnosticsOpt.Add(ErrorCode.ERR_ScopedRefAndRefStructOnly,
70+
(typeOrDesignationSyntax is TypeSyntax typeSyntax ? typeSyntax.SkipScoped(out _).SkipRef(out _) : typeOrDesignationSyntax).Location);
71+
}
6672
}
6773
}
6874

src/Compilers/CSharp/Portable/CSharpResources.resx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7376,4 +7376,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
73767376
<data name="ERR_ReadOnlyNotSuppAsParamModDidYouMeanIn" xml:space="preserve">
73777377
<value>'readonly' is not supported as a parameter modifier. Did you mean 'in'?</value>
73787378
</data>
7379+
<data name="ERR_ScopedDiscard" xml:space="preserve">
7380+
<value>The 'scoped' modifier cannot be used with discard.</value>
7381+
</data>
7382+
<data name="ERR_DeconstructVariableCannotBeByRef" xml:space="preserve">
7383+
<value>A deconstruction variable cannot be declared as a ref local</value>
7384+
</data>
73797385
</root>

src/Compilers/CSharp/Portable/Compilation/SyntaxTreeSemanticModel.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -366,7 +366,7 @@ private Symbol GetSemanticInfoSymbolInNonMemberContext(CSharpSyntaxNode node, bo
366366
// However, we can return fieldSymbol.Type for implicitly typed field symbols in both cases.
367367
// Note that for regular C#, fieldSymbol.Type would be an error type.
368368

369-
var variableDecl = type.Parent as VariableDeclarationSyntax;
369+
var variableDecl = type.ModifyingScopedOrRefTypeOrSelf().Parent as VariableDeclarationSyntax;
370370
if (variableDecl != null && variableDecl.Variables.Any())
371371
{
372372
var fieldSymbol = GetDeclaredFieldSymbol(variableDecl.Variables.First());

src/Compilers/CSharp/Portable/Errors/ErrorCode.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2112,7 +2112,7 @@ internal enum ErrorCode
21122112
ERR_FeatureNotAvailableInVersion11 = 9058,
21132113
ERR_RefFieldInNonRefStruct = 9059,
21142114
ERR_CannotMatchOnINumberBase = 9060,
2115-
// Available 9061,
2115+
ERR_ScopedDiscard = 9061,
21162116
ERR_ScopedTypeNameDisallowed = 9062,
21172117
ERR_UnscopedRefAttributeUnsupportedTarget = 9063,
21182118
ERR_RuntimeDoesNotSupportRefFields = 9064,
@@ -2123,7 +2123,7 @@ internal enum ErrorCode
21232123
ERR_FilePathCannotBeConvertedToUtf8 = 9069,
21242124
ERR_ReadOnlyNotSuppAsParamModDidYouMeanIn = 9070,
21252125
ERR_FileLocalDuplicateNameInNS = 9071,
2126-
// Available 9072,
2126+
ERR_DeconstructVariableCannotBeByRef = 9072,
21272127
WRN_ScopedMismatchInParameterOfTarget = 9073,
21282128
WRN_ScopedMismatchInParameterOfOverrideOrImplementation = 9074,
21292129
ERR_RefReturnScopedParameter = 9075,

src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1820,6 +1820,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
18201820
case ErrorCode.ERR_InvalidObjectCreation:
18211821
case ErrorCode.WRN_TypeParameterSameAsOuterMethodTypeParameter:
18221822
case ErrorCode.ERR_OutVariableCannotBeByRef:
1823+
case ErrorCode.ERR_DeconstructVariableCannotBeByRef:
18231824
case ErrorCode.ERR_OmittedTypeArgument:
18241825
case ErrorCode.ERR_FeatureNotAvailableInVersion8:
18251826
case ErrorCode.ERR_AltInterpolatedVerbatimStringsNotAvailable:
@@ -2219,6 +2220,7 @@ internal static bool IsBuildOnlyDiagnostic(ErrorCode code)
22192220
case ErrorCode.ERR_BadAbstractEqualityOperatorSignature:
22202221
case ErrorCode.ERR_BadBinaryReadOnlySpanConcatenation:
22212222
case ErrorCode.ERR_ScopedRefAndRefStructOnly:
2223+
case ErrorCode.ERR_ScopedDiscard:
22222224
case ErrorCode.ERR_FixedFieldMustNotBeRef:
22232225
case ErrorCode.ERR_RefFieldCannotReferToRefStruct:
22242226
case ErrorCode.ERR_FileTypeDisallowedInSignature:

0 commit comments

Comments
 (0)