From 2e5d839c275222a6c9ade7a2f12728642fb0dbe2 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Mon, 19 Feb 2024 12:14:50 -0800 Subject: [PATCH 1/3] Support UnscopedRef attribute on interface methods and properties https://github.com/dotnet/csharplang/blob/main/proposals/ref-struct-interfaces.md#ref-struct-interfaces-1 --- .../Portable/Binder/Binder.ValueChecks.cs | 86 +- .../Portable/Binder/Binder_Invocation.cs | 2 +- .../CSharp/Portable/CSharpResources.resx | 7 +- .../CSharp/Portable/Errors/MessageID.cs | 3 + .../Symbols/MethodSymbolExtensions.cs | 3 +- .../SourceMethodSymbolWithAttributes.cs | 5 + .../Source/SourcePropertySymbolBase.cs | 5 + .../Symbols/Source/ThisParameterSymbol.cs | 151 +- .../CSharp/Portable/Symbols/TypeSymbol.cs | 31 +- .../Portable/xlf/CSharpResources.cs.xlf | 13 +- .../Portable/xlf/CSharpResources.de.xlf | 13 +- .../Portable/xlf/CSharpResources.es.xlf | 13 +- .../Portable/xlf/CSharpResources.fr.xlf | 13 +- .../Portable/xlf/CSharpResources.it.xlf | 13 +- .../Portable/xlf/CSharpResources.ja.xlf | 13 +- .../Portable/xlf/CSharpResources.ko.xlf | 13 +- .../Portable/xlf/CSharpResources.pl.xlf | 13 +- .../Portable/xlf/CSharpResources.pt-BR.xlf | 13 +- .../Portable/xlf/CSharpResources.ru.xlf | 13 +- .../Portable/xlf/CSharpResources.tr.xlf | 13 +- .../Portable/xlf/CSharpResources.zh-Hans.xlf | 13 +- .../Portable/xlf/CSharpResources.zh-Hant.xlf | 13 +- .../Semantics/RefStructInterfacesTests.cs | 2914 +++++++++++++++++ .../Test/Semantic/Semantics/RefFieldTests.cs | 275 +- 24 files changed, 3361 insertions(+), 290 deletions(-) create mode 100644 src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index e8aaa6f0ba0ae..b38c652fbd547 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -2157,7 +2157,7 @@ private void GetInvocationArgumentsForEscape( Debug.Assert(receiverIsSubjectToCloning != ThreeState.Unknown); if (receiverIsSubjectToCloning == ThreeState.True) { - Debug.Assert(receiver is not BoundValuePlaceholderBase && method is not null && receiver.Type?.IsValueType == true); + Debug.Assert(receiver is not BoundValuePlaceholderBase && method is not null && receiver.Type?.IsReferenceType == false); #if DEBUG AssertVisited(receiver); #endif @@ -2251,6 +2251,12 @@ static EscapeArgument getReceiver(MethodSymbol? method, BoundExpression receiver method.TryGetThisParameter(out thisParameter) && thisParameter is not null) { + if (receiver.Type is TypeParameterSymbol typeParameter) + { + // Pretend that the type of the parameter is the type parameter + thisParameter = new TypeParameterThisParameterSymbol(thisParameter, typeParameter); + } + refKind = thisParameter.RefKind; } @@ -2729,6 +2735,84 @@ private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver) { return checkingReceiver ? ErrorCode.ERR_EscapeCall2 : ErrorCode.ERR_EscapeCall; } + +#nullable enable + private sealed class TypeParameterThisParameterSymbol : ThisParameterSymbolBase + { + private readonly TypeParameterSymbol _type; + private readonly ParameterSymbol _underlyingParameter; + + internal TypeParameterThisParameterSymbol(ParameterSymbol underlyingParameter, TypeParameterSymbol type) + { + Debug.Assert(underlyingParameter.IsThis); + Debug.Assert(underlyingParameter.RefKind != RefKind.Out); // Shouldn't get here for a constructor + Debug.Assert(underlyingParameter.ContainingSymbol is MethodSymbol); + + _underlyingParameter = underlyingParameter; + _type = type; + } + + public override TypeWithAnnotations TypeWithAnnotations + => TypeWithAnnotations.Create(_type, NullableAnnotation.NotAnnotated); + + public override RefKind RefKind + { + get + { + if (_underlyingParameter.RefKind is not RefKind.None and var underlyingRefKind) + { + return underlyingRefKind; + } + + if (!_underlyingParameter.ContainingType.IsInterface || _type.IsReferenceType) + { + return RefKind.None; + } + + // Receiver of an interface method could possibly be a structure. + // Let's treat it as by ref parameter for the purpose of ref safety analysis. + return RefKind.Ref; + } + } + + public override ImmutableArray Locations + { + get { return _underlyingParameter.Locations; } + } + + public override Symbol ContainingSymbol + { + get { return _underlyingParameter.ContainingSymbol; } + } + + internal override ScopedKind EffectiveScope + { + get + { + if (HasUnscopedRefAttribute) + { + return ScopedKind.None; + } + + if (!_underlyingParameter.ContainingType.IsInterface || _type.IsReferenceType) + { + return ScopedKind.None; + } + + // Receiver of an interface method could possibly be a structure. + // Let's treat it as scoped ref by ref parameter for the purpose of ref safety analysis. + return ScopedKind.ScopedRef; + } + } + + internal override bool HasUnscopedRefAttribute + => _underlyingParameter.HasUnscopedRefAttribute; + + internal sealed override bool UseUpdatedEscapeRules + => _underlyingParameter.UseUpdatedEscapeRules; + } + +#nullable disable } internal partial class Binder diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs index 01f296438e4f9..be162efefa3e5 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs @@ -1211,7 +1211,7 @@ internal ThreeState ReceiverIsSubjectToCloning(BoundExpression? receiver, Proper internal ThreeState ReceiverIsSubjectToCloning(BoundExpression? receiver, MethodSymbol method) { - if (receiver is BoundValuePlaceholderBase || receiver?.Type?.IsValueType != true) + if (receiver is BoundValuePlaceholderBase || receiver?.Type is null or { IsReferenceType: true }) { return ThreeState.False; } diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx index 171ac911a1444..19ab3fbaecc1e 100644 --- a/src/Compilers/CSharp/Portable/CSharpResources.resx +++ b/src/Compilers/CSharp/Portable/CSharpResources.resx @@ -7480,10 +7480,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ UnscopedRefAttribute cannot be applied to this parameter because it is unscoped by default. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute cannot be applied to an interface implementation. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. '{0}' is defined in a module with an unrecognized RefSafetyRulesAttribute version, expecting '11'. @@ -7845,4 +7845,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ implicit indexer initializer + + ref struct interfaces + \ No newline at end of file diff --git a/src/Compilers/CSharp/Portable/Errors/MessageID.cs b/src/Compilers/CSharp/Portable/Errors/MessageID.cs index 0258897ff46e1..580e8bcdde33a 100644 --- a/src/Compilers/CSharp/Portable/Errors/MessageID.cs +++ b/src/Compilers/CSharp/Portable/Errors/MessageID.cs @@ -279,6 +279,8 @@ internal enum MessageID IDS_StringEscapeCharacter = MessageBase + 12839, IDS_ImplicitIndexerInitializer = MessageBase + 12840, + + IDS_RefStructInterfaces = MessageBase + 12950, // PROTOTYPE(RefStructInterfaces): Pack numbers } // Message IDs may refer to strings that need to be localized. @@ -461,6 +463,7 @@ internal static LanguageVersion RequiredVersion(this MessageID feature) // C# preview features. case MessageID.IDS_StringEscapeCharacter: case MessageID.IDS_ImplicitIndexerInitializer: + case MessageID.IDS_RefStructInterfaces: return LanguageVersion.Preview; // C# 12.0 features. diff --git a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs index 5f85462fcdeb1..b1fee8aae96ac 100644 --- a/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs +++ b/src/Compilers/CSharp/Portable/Symbols/MethodSymbolExtensions.cs @@ -216,7 +216,8 @@ internal static CSharpSyntaxNode ExtractReturnTypeSyntax(this MethodSymbol metho internal static bool IsValidUnscopedRefAttributeTarget(this MethodSymbol method) { return !method.IsStatic && - method.ContainingType?.IsStructType() == true && + method.ContainingType is NamedTypeSymbol containingType && + (containingType.IsStructType() == true || (containingType.IsInterface && method.IsImplementable())) && method.MethodKind is (MethodKind.Ordinary or MethodKind.ExplicitInterfaceImplementation or MethodKind.PropertyGet or MethodKind.PropertySet) && !method.IsInitOnly; } diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs index 60f4d42601b68..0f4440a0e1d5c 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceMethodSymbolWithAttributes.cs @@ -593,6 +593,11 @@ private void DecodeWellKnownAttributeAppliedToMethod(ref DecodeWellKnownAttribut if (this.IsValidUnscopedRefAttributeTarget()) { arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + + if (ContainingType.IsInterface || IsExplicitInterfaceImplementation) + { + MessageID.IDS_RefStructInterfaces.CheckFeatureAvailability(diagnostics, arguments.AttributeSyntaxOpt); + } } else { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs index 53b4fc02f357b..af4f7be725d55 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbolBase.cs @@ -1311,6 +1311,11 @@ protected override void DecodeWellKnownAttributeImpl(ref DecodeWellKnownAttribut if (this.IsValidUnscopedRefAttributeTarget()) { arguments.GetOrCreateData().HasUnscopedRefAttribute = true; + + if (ContainingType.IsInterface || IsExplicitInterfaceImplementation) + { + MessageID.IDS_RefStructInterfaces.CheckFeatureAvailability(diagnostics, arguments.AttributeSyntaxOpt); + } } else { diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs index 4fe1c9c316a02..7a9b161f81639 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs @@ -7,164 +7,167 @@ namespace Microsoft.CodeAnalysis.CSharp.Symbols { - internal sealed class ThisParameterSymbol : ParameterSymbol + internal abstract class ThisParameterSymbolBase : ParameterSymbol { internal const string SymbolName = "this"; - private readonly MethodSymbol? _containingMethod; - private readonly TypeSymbol _containingType; - - internal ThisParameterSymbol(MethodSymbol forMethod) : this(forMethod, forMethod.ContainingType) - { - } - - internal ThisParameterSymbol(MethodSymbol? forMethod, TypeSymbol containingType) - { - Debug.Assert(containingType is not null); - _containingMethod = forMethod; - _containingType = containingType; - } + public sealed override string Name => SymbolName; - public override string Name => SymbolName; + public sealed override bool IsDiscard => false; - public override bool IsDiscard => false; - - public override TypeWithAnnotations TypeWithAnnotations - => TypeWithAnnotations.Create(_containingType, NullableAnnotation.NotAnnotated); - - public override RefKind RefKind - { - get - { - if (ContainingType?.TypeKind != TypeKind.Struct) - { - return RefKind.None; - } - - if (_containingMethod?.MethodKind == MethodKind.Constructor) - { - return RefKind.Out; - } - - if (_containingMethod?.IsEffectivelyReadOnly == true) - { - return RefKind.In; - } - - return RefKind.Ref; - } - } - - public override ImmutableArray Locations - { - get { return _containingMethod is not null ? _containingMethod.Locations : ImmutableArray.Empty; } - } - - public override ImmutableArray DeclaringSyntaxReferences + public sealed override ImmutableArray DeclaringSyntaxReferences { get { return ImmutableArray.Empty; } } - public override Symbol ContainingSymbol - { - get { return (Symbol?)_containingMethod ?? _containingType; } - } - - internal override ConstantValue? ExplicitDefaultConstantValue + internal sealed override ConstantValue? ExplicitDefaultConstantValue { get { return null; } } - internal override bool IsMetadataOptional + internal sealed override bool IsMetadataOptional { get { return false; } } - public override bool IsParams + public sealed override bool IsParams { get { return false; } } - internal override bool IsIDispatchConstant + internal sealed override bool IsIDispatchConstant { get { return false; } } - internal override bool IsIUnknownConstant + internal sealed override bool IsIUnknownConstant { get { return false; } } - internal override bool IsCallerFilePath + internal sealed override bool IsCallerFilePath { get { return false; } } - internal override bool IsCallerLineNumber + internal sealed override bool IsCallerLineNumber { get { return false; } } - internal override bool IsCallerMemberName + internal sealed override bool IsCallerMemberName { get { return false; } } - internal override int CallerArgumentExpressionParameterIndex + internal sealed override int CallerArgumentExpressionParameterIndex { get { return -1; } } - internal override FlowAnalysisAnnotations FlowAnalysisAnnotations + internal sealed override FlowAnalysisAnnotations FlowAnalysisAnnotations { get { return FlowAnalysisAnnotations.None; } } - internal override ImmutableHashSet NotNullIfParameterNotNull + internal sealed override ImmutableHashSet NotNullIfParameterNotNull { get { return ImmutableHashSet.Empty; } } - public override int Ordinal + public sealed override int Ordinal { get { return -1; } } - public override ImmutableArray RefCustomModifiers + public sealed override ImmutableArray RefCustomModifiers { get { return ImmutableArray.Empty; } } // TODO: structs - public override bool IsThis + public sealed override bool IsThis { get { return true; } } // "this" is never explicitly declared. - public override bool IsImplicitlyDeclared + public sealed override bool IsImplicitlyDeclared { get { return true; } } - internal override bool IsMetadataIn + internal sealed override bool IsMetadataIn { get { return false; } } - internal override bool IsMetadataOut + internal sealed override bool IsMetadataOut { get { return false; } } - internal override MarshalPseudoCustomAttributeData? MarshallingInformation + internal sealed override MarshalPseudoCustomAttributeData? MarshallingInformation { get { return null; } } - internal override ImmutableArray InterpolatedStringHandlerArgumentIndexes => ImmutableArray.Empty; + internal sealed override ImmutableArray InterpolatedStringHandlerArgumentIndexes => ImmutableArray.Empty; + + internal sealed override bool HasInterpolatedStringHandlerArgumentError => false; + } + + internal sealed class ThisParameterSymbol : ThisParameterSymbolBase + { + private readonly MethodSymbol? _containingMethod; + private readonly TypeSymbol _containingType; + + internal ThisParameterSymbol(MethodSymbol forMethod) : this(forMethod, forMethod.ContainingType) + { + } + + internal ThisParameterSymbol(MethodSymbol? forMethod, TypeSymbol containingType) + { + Debug.Assert(containingType is not null); + _containingMethod = forMethod; + _containingType = containingType; + } + + public override TypeWithAnnotations TypeWithAnnotations + => TypeWithAnnotations.Create(_containingType, NullableAnnotation.NotAnnotated); - internal override bool HasInterpolatedStringHandlerArgumentError => false; + public override RefKind RefKind + { + get + { + if (ContainingType?.TypeKind != TypeKind.Struct) + { + return RefKind.None; + } + + if (_containingMethod?.MethodKind == MethodKind.Constructor) + { + return RefKind.Out; + } + + if (_containingMethod?.IsEffectivelyReadOnly == true) + { + return RefKind.In; + } + + return RefKind.Ref; + } + } + + public override ImmutableArray Locations + { + get { return _containingMethod is not null ? _containingMethod.Locations : ImmutableArray.Empty; } + } + + public override Symbol ContainingSymbol + { + get { return (Symbol?)_containingMethod ?? _containingType; } + } internal override ScopedKind EffectiveScope { diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index 713a45870fe39..8bc2de75b6e01 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -1883,9 +1883,21 @@ static void checkMethodOverride( if (implementingMethod.HasUnscopedRefAttributeOnMethodOrProperty()) { - diagnostics.Add( - ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, - GetImplicitImplementationDiagnosticLocation(implementedMethod, implementingType, implementingMethod)); + if (implementedMethod.HasUnscopedRefAttributeOnMethodOrProperty()) + { + if (!implementingMethod.IsExplicitInterfaceImplementation && implementingMethod is SourceMethodSymbolWithAttributes && + implementedMethod.ContainingModule != implementingMethod.ContainingModule) + { + checkRefStructInterfacesFeatureAvailabilityOnUnscopedRefAttribute(implementingMethod.HasUnscopedRefAttribute ? implementingMethod : implementingMethod.AssociatedSymbol, diagnostics); + } + } + else + { + diagnostics.Add( + ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, + GetImplicitImplementationDiagnosticLocation(implementedMethod, implementingType, implementingMethod), + implementedMethod); + } } } @@ -1949,6 +1961,19 @@ static void checkMethodOverride( } } } + + static void checkRefStructInterfacesFeatureAvailabilityOnUnscopedRefAttribute(Symbol implementingSymbol, BindingDiagnosticBag diagnostics) + { + foreach (var attributeData in implementingSymbol.GetAttributes()) + { + if (attributeData is SourceAttributeData { ApplicationSyntaxReference: { } applicationSyntaxReference } && + attributeData.IsTargetAttribute(AttributeDescription.UnscopedRefAttribute)) + { + MessageID.IDS_RefStructInterfaces.CheckFeatureAvailability(diagnostics, implementingSymbol.DeclaringCompilation, applicationSyntaxReference.GetLocation()); + break; + } + } + } } /// diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf index 2f344fa37fafb..ea393cb9ac28e 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute nelze použít na implementaci rozhraní. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - Atribut UnscopedRefAttribute lze použít pouze pro metody a vlastnosti instance struktury a nelze ho použít u konstruktorů nebo členů init-only. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + Atribut UnscopedRefAttribute lze použít pouze pro metody a vlastnosti instance struktury a nelze ho použít u konstruktorů nebo členů init-only. @@ -2342,6 +2342,11 @@ přístup k elementu ukazatele + + ref struct interfaces + ref struct interfaces + + array pole diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf index 9901d1ad9015f..744712be7fd77 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - "UnscopedRefAttribute" kann nicht auf eine Schnittstellenimplementierung angewendet werden. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - "UnscopedRefAttribute" kann nur auf Strukturinstanzmethoden und -eigenschaften und nicht auf Konstruktoren oder init-only-Member angewendet werden. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + "UnscopedRefAttribute" kann nur auf Strukturinstanzmethoden und -eigenschaften und nicht auf Konstruktoren oder init-only-Member angewendet werden. @@ -2342,6 +2342,11 @@ Zeigerelementzugriff + + ref struct interfaces + ref struct interfaces + + array Array diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf index b44db9bc4b716..ae647ed28ebc1 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute no se puede aplicar a una implementación de interfaz. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute solo se puede aplicar a propiedades y métodos de instancia de struct, y no se puede aplicar a constructores o miembros de solo inicialización. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute solo se puede aplicar a propiedades y métodos de instancia de struct, y no se puede aplicar a constructores o miembros de solo inicialización. @@ -2342,6 +2342,11 @@ acceso al elemento de puntero + + ref struct interfaces + ref struct interfaces + + array matriz diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf index c7f0fbadea172..a895b8fdafa72 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute ne peut pas être appliqué à une implémentation d’interface. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute peut uniquement être appliqué aux méthodes et propriétés d’instance de struct, et ne peut pas être appliqué aux constructeurs ou aux membres init uniquement. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute peut uniquement être appliqué aux méthodes et propriétés d’instance de struct, et ne peut pas être appliqué aux constructeurs ou aux membres init uniquement. @@ -2342,6 +2342,11 @@ accès à l’élément de pointeur + + ref struct interfaces + ref struct interfaces + + array déployer diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf index 1d66800f68b1f..53a87e1451724 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - Non è possibile applicare UnscopedRefAttribute a un'implementazione di interfaccia. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute può essere applicato solo ai metodi e alle proprietà dell'istanza di struct e non può essere applicato a costruttori o membri solo init. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute può essere applicato solo ai metodi e alle proprietà dell'istanza di struct e non può essere applicato a costruttori o membri solo init. @@ -2342,6 +2342,11 @@ accesso all'elemento puntatore + + ref struct interfaces + ref struct interfaces + + array matrice diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf index 6a8ed4f5871c4..740560db37ecc 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute をインターフェイスの実装に適用することはできません。 + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute は構造体インスタンスのメソッドとプロパティにのみ適用でき、コンストラクターまたは init のみのメンバーには適用できません。 + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute は構造体インスタンスのメソッドとプロパティにのみ適用でき、コンストラクターまたは init のみのメンバーには適用できません。 @@ -2342,6 +2342,11 @@ ポインター要素アクセス + + ref struct interfaces + ref struct interfaces + + array 配列 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf index 68546d1409fda..016490daf6fae 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute는 인터페이스 구현에 적용할 수 없습니다. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute는 구조체 인스턴스 메서드 및 속성에만 적용할 수 있으며 생성자 또는 초기화 전용 멤버에는 적용할 수 없습니다. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute는 구조체 인스턴스 메서드 및 속성에만 적용할 수 있으며 생성자 또는 초기화 전용 멤버에는 적용할 수 없습니다. @@ -2342,6 +2342,11 @@ 포인터 요소 액세스 + + ref struct interfaces + ref struct interfaces + + array 배열 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf index a92b966be17ad..049954aa66269 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - Nie można zastosować atrybutu UnscopedRefAttribute do implementacji interfejsu. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - Atrybut UnscopedRefAttribute można stosować tylko do metod i właściwości wystąpienia struktury i nie można go stosować do konstruktorów ani składowych tylko do inicjowania. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + Atrybut UnscopedRefAttribute można stosować tylko do metod i właściwości wystąpienia struktury i nie można go stosować do konstruktorów ani składowych tylko do inicjowania. @@ -2342,6 +2342,11 @@ dostęp do elementu wskaźnika + + ref struct interfaces + ref struct interfaces + + array tablica diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf index c16fb2e8e4e2b..50fbccd948470 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute não pode ser aplicado a uma implementação de interface. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute só pode ser aplicado a métodos e propriedades de instância struct e não pode ser aplicado a construtores ou membros somente init. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute só pode ser aplicado a métodos e propriedades de instância struct e não pode ser aplicado a construtores ou membros somente init. @@ -2342,6 +2342,11 @@ acesso ao elemento de ponteiro + + ref struct interfaces + ref struct interfaces + + array matriz diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf index ac193c0fff6f0..205de39f8c57b 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute не может применяться к реализации интерфейса. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute может применяться только к методам и свойствам экземпляров структуры и не может применяться к конструкторам или элементам только для инициализации. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute может применяться только к методам и свойствам экземпляров структуры и не может применяться к конструкторам или элементам только для инициализации. @@ -2342,6 +2342,11 @@ доступ к элементу указателя + + ref struct interfaces + ref struct interfaces + + array множество diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf index d75680113008d..7e3507185ab2f 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute bir arabirim uygulamasına uygulanamaz. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute yalnızca örnek metodları ve özellikleri yapılandırmak için uygulanabilir ve oluşturuculara veya yalnızca init üyelerine uygulanamaz. + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute yalnızca örnek metodları ve özellikleri yapılandırmak için uygulanabilir ve oluşturuculara veya yalnızca init üyelerine uygulanamaz. @@ -2342,6 +2342,11 @@ işaretçi öğesi erişimi + + ref struct interfaces + ref struct interfaces + + array dizi diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf index 5fff182a64966..e86cc891523a9 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute 无法应用于接口实现。 + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute 只能应用于结构实例方法和属性,不能应用于构造函数或仅初始化成员。 + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute 只能应用于结构实例方法和属性,不能应用于构造函数或仅初始化成员。 @@ -2342,6 +2342,11 @@ 指针元素访问 + + ref struct interfaces + ref struct interfaces + + array 数组 diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf index 516940936f1f4..92b4dae715114 100644 --- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf +++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf @@ -2033,13 +2033,13 @@ - UnscopedRefAttribute cannot be applied to an interface implementation. - UnscopedRefAttribute 無法套用至介面實作。 + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. + UnscopedRefAttribute cannot be applied to an interface implementation because implemented member '{0}' doesn't have this attribute. - UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - UnscopedRefAttribute 只能套用至結構執行個體方法和屬性,且無法套用至建構函式或僅 init 成員。 + UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + UnscopedRefAttribute 只能套用至結構執行個體方法和屬性,且無法套用至建構函式或僅 init 成員。 @@ -2342,6 +2342,11 @@ 指標元素存取 + + ref struct interfaces + ref struct interfaces + + array 陣列 diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs new file mode 100644 index 0000000000000..a2b4f5da3a080 --- /dev/null +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs @@ -0,0 +1,2914 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Test.Utilities; +using Microsoft.CodeAnalysis.Test.Utilities; +using Roslyn.Test.Utilities; +using Xunit; + +namespace Microsoft.CodeAnalysis.CSharp.UnitTests +{ + public class RefStructInterfacesTests : CSharpTestBase + { + [Fact] + public void UnscopedRefInInterface_Method_01() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + ref int M(); +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.True(m.GlobalNamespace.GetMember("I.M").HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + ); + } + + [Fact] + public void UnscopedRefInInterface_Method_02() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + ref int M() + { + throw null; + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.True(m.GlobalNamespace.GetMember("I.M").HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + ); + } + + [Fact] + public void UnscopedRefInInterface_Method_03() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + sealed ref int M() + { + throw null; + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6) + ); + + Assert.False(comp.GetMember("I.M").HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInInterface_Method_04() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + abstract static ref int M(); +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6) + ); + + Assert.False(comp.GetMember("I.M").HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInInterface_Property_01() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + ref int P { get; } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("I.P"); + Assert.True(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + ); + } + + [Fact] + public void UnscopedRefInInterface_Property_02() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + ref int P => throw null; +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("I.P"); + Assert.True(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + ); + } + + [Fact] + public void UnscopedRefInInterface_Property_03() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + sealed ref int P => throw null; +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6) + ); + + PropertySymbol propertySymbol = comp.GetMember("I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInInterface_Property_04() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + abstract static ref int P { get; } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6) + ); + + PropertySymbol propertySymbol = comp.GetMember("I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInInterface_Property_05() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + ref int P + { + [UnscopedRef] + get; + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 10) + ); + } + + [Fact] + public void UnscopedRefInInterface_Property_06() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + ref int P + { + [UnscopedRef] + get + { + throw null; + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 10) + ); + } + + [Fact] + public void UnscopedRefInInterface_Property_07() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + sealed ref int P + { + [UnscopedRef] + get + { + throw null; + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (8,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 10) + ); + + PropertySymbol propertySymbol = comp.GetMember("I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInInterface_Property_08() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + abstract static ref int P + { + [UnscopedRef] + get; + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (8,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 10) + ); + + PropertySymbol propertySymbol = comp.GetMember("I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInImplementation_Method_01() + { + var src1 = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + ref int M(); +} +"; + var comp1 = CreateCompilation(src1, targetFramework: TargetFramework.Net80); + MetadataReference[] comp1Refs = [comp1.EmitToImageReference(), comp1.ToMetadataReference()]; + + var src2 = @" +using System.Diagnostics.CodeAnalysis; + +class C : I +{ + [UnscopedRef] + public ref int M() + { + throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp2 = CreateCompilation(src2, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp2.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6) + ); + Assert.False(comp2.GetMember("C.M").HasUnscopedRefAttribute); + } + + var src3 = @" +using System.Diagnostics.CodeAnalysis; + +class C : I +{ + [UnscopedRef] + ref int I.M() + { + throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp3 = CreateCompilation(src3, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp3.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6) + ); + Assert.False(comp3.GetMember("C.I.M").HasUnscopedRefAttribute); + } + + var src4 = @" +class C1 : I +{ + int f = 0; + public ref int M() + { + return ref f; + } +} + +class C2 : I +{ + int f = 0; + ref int I.M() + { + return ref f; + } +} + +class C3 +{ + int f = 0; + public ref int M() + { + return ref f; + } +} + +class C4 : C3, I {} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp4 = CreateCompilation(src4, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp4, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.False(m.GlobalNamespace.GetMember("C1.M").HasUnscopedRefAttribute); + Assert.False(m.GlobalNamespace.GetMember("C2.I.M").HasUnscopedRefAttribute); + Assert.False(m.GlobalNamespace.GetMember("C3.M").HasUnscopedRefAttribute); + } + } + + var src5 = @" +using System.Diagnostics.CodeAnalysis; + +interface C : I +{ + [UnscopedRef] + ref int I.M() + { + throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp5 = CreateCompilation(src5, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp5.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6) + ); + Assert.False(comp5.GetMember("C.I.M").HasUnscopedRefAttribute); + } + + var src6 = @" +interface C : I +{ + ref int I.M() + { + throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp6 = CreateCompilation(src6, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp6, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.False(m.GlobalNamespace.GetMember("C.I.M").HasUnscopedRefAttribute); + } + } + + var src7 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + + [UnscopedRef] + public ref int M() + { + return ref f; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp7, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.True(m.GlobalNamespace.GetMember("C.M").HasUnscopedRefAttribute); + } + + CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 6) + ); + } + + var src8 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + + [UnscopedRef] + ref int I.M() + { + return ref f; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp8, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.True(m.GlobalNamespace.GetMember("C.I.M").HasUnscopedRefAttribute); + } + + CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 6) + ); + } + + var src9 = @" +public struct C : I +{ + public ref int M() + { + throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp9 = CreateCompilation(src9, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp9, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.False(m.GlobalNamespace.GetMember("C.M").HasUnscopedRefAttribute); + } + } + + var src10 = @" +public struct C : I +{ + ref int I.M() + { + throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp10 = CreateCompilation(src10, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp10, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.False(m.GlobalNamespace.GetMember("C.I.M").HasUnscopedRefAttribute); + } + } + + var src11 = @" +public struct C : I +{ + public int f; + + public ref int M() + { + return ref f; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp11 = CreateCompilation(src11, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp11.VerifyDiagnostics( + // (8,20): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref f; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "f").WithLocation(8, 20) + ); + } + + var src12 = @" +public struct C : I +{ + public int f; + + ref int I.M() + { + return ref f; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp12 = CreateCompilation(src12, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp12.VerifyDiagnostics( + // (8,20): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref f; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "f").WithLocation(8, 20) + ); + } + } + + [Fact] + public void UnscopedRefInImplementation_Method_02() + { + var src1 = @" +public interface I +{ + ref int M(); +} +"; + var comp1 = CreateCompilation(src1, targetFramework: TargetFramework.Net80); + MetadataReference[] comp1Refs = [comp1.EmitToImageReference(), comp1.ToMetadataReference()]; + + var src7 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + + [UnscopedRef] + public ref int M() + { + return ref f; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp7.VerifyDiagnostics( + // (9,20): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.M()' doesn't have this attribute. + // public ref int M() + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "M").WithArguments("I.M()").WithLocation(9, 20) + ); + + Assert.True(comp7.GetMember("C.M").HasUnscopedRefAttribute); + } + + var src8 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + + [UnscopedRef] + ref int I.M() + { + return ref f; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp8.VerifyDiagnostics( + // (9,15): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.M()' doesn't have this attribute. + // ref int I.M() + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "M").WithArguments("I.M()").WithLocation(9, 15) + ); + + Assert.True(comp8.GetMember("C.I.M").HasUnscopedRefAttribute); + } + } + + [Fact] + public void UnscopedRefInImplementation_Method_03() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ +#line 100 + [UnscopedRef] + ref int M(); +} + +public struct C : I +{ + public int f; + +#line 200 + [UnscopedRef] + public ref int M() + { + return ref f; + } +} +"; + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + ); + } + + [Theory] + [CombinatorialData] + public void UnscopedRefInImplementation_Property_01(bool onInterfaceProperty, bool onInterfaceGet, bool onImplementationProperty, bool onImplementationGet) + { + if (!onInterfaceProperty && !onInterfaceGet) + { + return; + } + + var src1 = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + " + (onInterfaceProperty ? "[UnscopedRef]" : "") + @" + ref int P { " + (onInterfaceGet ? "[UnscopedRef] " : "") + @"get; } +} +"; + var comp1 = CreateCompilation(src1, targetFramework: TargetFramework.Net80); + + var p = comp1.GetMember("I.P"); + Assert.Equal(onInterfaceProperty, p.HasUnscopedRefAttribute); + Assert.Equal(onInterfaceGet, p.GetMethod.HasUnscopedRefAttribute); + + MetadataReference[] comp1Refs = [comp1.EmitToImageReference(), comp1.ToMetadataReference()]; + + if (onImplementationProperty || onImplementationGet) + { + var src2 = @" +using System.Diagnostics.CodeAnalysis; + +class C : I +{ +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + public ref int P + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + => throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp2 = CreateCompilation(src2, references: [comp1Ref], targetFramework: TargetFramework.Net80); + + if (onImplementationProperty) + { + if (onImplementationGet) + { + comp2.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6), + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + else + { + comp2.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6) + ); + } + } + else + { + comp2.VerifyDiagnostics( + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + + PropertySymbol propertySymbol = comp2.GetMember("C.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + var src3 = @" +using System.Diagnostics.CodeAnalysis; + +class C : I +{ +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + ref int I. P + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + => throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp3 = CreateCompilation(src3, references: [comp1Ref], targetFramework: TargetFramework.Net80); + if (onImplementationProperty) + { + if (onImplementationGet) + { + comp3.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6), + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + else + { + comp3.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6) + ); + } + } + else + { + comp3.VerifyDiagnostics( + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + + PropertySymbol propertySymbol = comp3.GetMember("C.I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + + if (!onImplementationProperty && !onImplementationGet) + { + var src4 = @" +class C1 : I +{ + int f = 0; + public ref int P + { get{ + return ref f; + }} +} + +class C2 : I +{ + int f = 0; + ref int I.P + { get{ + return ref f; + }} +} + +class C3 +{ + int f = 0; + public ref int P + { get{ + return ref f; + }} +} + +class C4 : C3, I {} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp4 = CreateCompilation(src4, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp4, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.False(m.GlobalNamespace.GetMember("C1.P").HasUnscopedRefAttribute); + Assert.False(m.GlobalNamespace.GetMember("C2.I.P").HasUnscopedRefAttribute); + Assert.False(m.GlobalNamespace.GetMember("C3.P").HasUnscopedRefAttribute); + } + } + } + + if (onImplementationProperty || onImplementationGet) + { + var src5 = @" +using System.Diagnostics.CodeAnalysis; + +interface C : I +{ +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + ref int I.P + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + => throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp5 = CreateCompilation(src5, references: [comp1Ref], targetFramework: TargetFramework.Net80); + if (onImplementationProperty) + { + if (onImplementationGet) + { + comp5.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6), + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + else + { + comp5.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6) + ); + } + } + else + { + comp5.VerifyDiagnostics( + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + + PropertySymbol propertySymbol = comp5.GetMember("C.I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + + if (!onImplementationProperty && !onImplementationGet) + { + var src6 = @" +interface C : I +{ + ref int I.P => throw null; +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp6 = CreateCompilation(src6, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp6, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.False(m.GlobalNamespace.GetMember("C.I.P").HasUnscopedRefAttribute); + } + } + } + + if (onImplementationProperty || onImplementationGet) + { + var src7 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + public ref int P + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + { + return ref f; + } + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp7, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C.P"); + Assert.Equal(onImplementationProperty, propertySymbol.HasUnscopedRefAttribute); + Assert.Equal(onImplementationGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12); + if (onImplementationGet) + { + comp7.VerifyDiagnostics( + // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + ); + } + else + { + comp7.VerifyDiagnostics( + // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + ); + } + } + + var src8 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + ref int I.P + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + { + return ref f; + } + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp8, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C.I.P"); + Assert.Equal(onImplementationProperty, propertySymbol.HasUnscopedRefAttribute); + Assert.Equal(onImplementationGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12); + if (onImplementationProperty) + { + if (onImplementationGet) + { + comp8.VerifyDiagnostics( + // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6), + // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + ); + } + else + { + comp8.VerifyDiagnostics( + // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + ); + } + } + else + { + comp8.VerifyDiagnostics( + // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + ); + } + } + } + + if (!onImplementationProperty && !onImplementationGet) + { + var src9 = @" +public struct C : I +{ + public ref int P => throw null; +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp9 = CreateCompilation(src9, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp9, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.False(m.GlobalNamespace.GetMember("C.P").HasUnscopedRefAttribute); + } + } + + var src10 = @" +public struct C : I +{ + ref int I.P => throw null; +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp10 = CreateCompilation(src10, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp10, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + Assert.False(m.GlobalNamespace.GetMember("C.I.P").HasUnscopedRefAttribute); + } + } + + var src11 = @" +public struct C : I +{ + public int f; + + public ref int P + { get{ + return ref f; + }} +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp11 = CreateCompilation(src11, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp11.VerifyDiagnostics( + // (8,20): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref f; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "f").WithLocation(8, 20) + ); + } + + var src12 = @" +public struct C : I +{ + public int f; + + ref int I.P + { get{ + return ref f; + }} +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp12 = CreateCompilation(src12, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp12.VerifyDiagnostics( + // (8,20): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref f; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "f").WithLocation(8, 20) + ); + } + } + } + + [Theory] + [CombinatorialData] + public void UnscopedRefInImplementation_Property_02(bool onProperty, bool onGet) + { + if (!onProperty && !onGet) + { + return; + } + + var src1 = @" +public interface I +{ + ref int P { get; } +} +"; + var comp1 = CreateCompilation(src1, targetFramework: TargetFramework.Net80); + MetadataReference[] comp1Refs = [comp1.EmitToImageReference(), comp1.ToMetadataReference()]; + + var src7 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + + " + (onProperty ? "[UnscopedRef]" : "") + @" + public ref int P + { +#line 200 + " + (onGet ? "[UnscopedRef] " : "") + @" + get + { + return ref f; + } + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp7.VerifyDiagnostics( + // (201,9): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.P.get' doesn't have this attribute. + // get + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I.P.get").WithLocation(201, 9) + ); + + PropertySymbol propertySymbol = comp7.GetMember("C.P"); + Assert.Equal(onProperty, propertySymbol.HasUnscopedRefAttribute); + Assert.Equal(onGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + var src8 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + + " + (onProperty ? "[UnscopedRef]" : "") + @" + ref int I.P + { +#line 200 + " + (onGet ? "[UnscopedRef] " : "") + @" + get + { + return ref f; + } + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp8.VerifyDiagnostics( + // (201,9): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.P.get' doesn't have this attribute. + // get + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I.P.get").WithLocation(201, 9) + ); + + PropertySymbol propertySymbol = comp8.GetMember("C.I.P"); + Assert.Equal(onProperty, propertySymbol.HasUnscopedRefAttribute); + Assert.Equal(onGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + + // This is a clone of MethodArgumentsMustMatch_16 from RefFieldTests.cs + [Fact] + public void MethodArgumentsMustMatch_16_DirectInterface() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + interface R + { + public ref int FA(); + [UnscopedRef] public ref int FB(); + } + class Program + { + static void F1(ref R r1, ref int i1) { } + static void F2(ref R r2, [UnscopedRef] ref int i2) { } + static void F(ref R x) + { + R y = default; + F1(ref x, ref y.FA()); + F1(ref x, ref y.FB()); + F2(ref x, ref y.FA()); + F2(ref x, ref y.FB()); // 1 + } + } + """; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics(); + } + + // This is a clone of MethodArgumentsMustMatch_16 from RefFieldTests.cs + [Fact(Skip = "'allow' is not supported yet")] // PROTOTYPE(RefStructInterfaces): Enable once new constraints are supported + public void MethodArgumentsMustMatch_16_ConstrainedTypeParameter() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + interface R + { + public ref int FA(); + [UnscopedRef] public ref int FB(); + } + class Program where T : allows ref struct, R + { + static void F1(ref T r1, ref int i1) { } + static void F2(ref T r2, [UnscopedRef] ref int i2) { } + static void F(ref T x) + { + T y = default; + F1(ref x, ref y.FA()); + F1(ref x, ref y.FB()); + F2(ref x, ref y.FA()); + F2(ref x, ref y.FB()); // 1 + } + } + """; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics( + // (17,9): error CS8350: This combination of arguments to 'Program.F2(ref R, ref int)' is disallowed because it may expose variables referenced by parameter 'i2' outside of their declaration scope + // F2(ref x, ref y.FB()); // 1 + Diagnostic(ErrorCode.ERR_CallArgMixing, "F2(ref x, ref y.FB())").WithArguments("Program.F2(ref R, ref int)", "i2").WithLocation(17, 9), + // (17,23): error CS8168: Cannot return local 'y' by reference because it is not a ref local + // F2(ref x, ref y.FB()); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "y").WithArguments("y").WithLocation(17, 23)); + } + + // This is a clone of MethodArgumentsMustMatch_16 from RefFieldTests.cs + [Fact] + public void MethodArgumentsMustMatch_16_ClassConstrainedTypeParameter() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + interface R + { + public ref int FA(); + [UnscopedRef] public ref int FB(); + } + class Program where T : class, R + { + static void F1(ref T r1, ref int i1) { } + static void F2(ref T r2, [UnscopedRef] ref int i2) { } + static void F(ref T x) + { + T y = default; + F1(ref x, ref y.FA()); + F1(ref x, ref y.FB()); + F2(ref x, ref y.FA()); + F2(ref x, ref y.FB()); // 1 + } + } + """; + var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); + comp.VerifyDiagnostics(); + } + + // PROTOTYPE(RefStructInterfaces): Clone from RefFieldTests.cs once new constraints are supported: + // - MethodArgumentsMustMatch_17 + // - MethodArgumentsMustMatch_18 + // - ReturnOnlyScope_01 + // - ReturnRefToRefStruct_ValEscape_01 + // - ReturnRefToRefStruct_ValEscape_02 + // - ReturnRefToRefStruct_ValEscape_03 + // - ReturnRefToRefStruct_ValEscape_04 + // + // Also LocalScope_DeclarationExpression_06 from RefEscapingTests.cs + + // This is a clone of UnscopedRefAttribute_Method_03 from RefFieldTests.cs + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Method_03_DirectInterface(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public interface S +{ + public ref T F1(); + [UnscopedRef] public ref T F2(); +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program +{ + static ref int F1() + { + var s = GetS(); + return ref s.F1(); + } + static ref int F2() + { + var s = GetS(); + return ref s.F2(); // 1 + } + + static S GetS() => throw null; +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of UnscopedRefAttribute_Method_03 from RefFieldTests.cs + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Method_03_ConstrainedTypeParameter(bool useCompilationReference, bool addStructConstraint) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public interface S +{ + public ref T F1(); + [UnscopedRef] public ref T F2(); +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program where T : " + (addStructConstraint ? "struct, " : "") + @"S +{ + static ref int F1() + { + var s = GetS(); + return ref s.F1(); + } + static ref int F2() + { + var s = GetS(); + return ref s.F2(); // 1 + } + + static T GetS() => throw null; +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (11,20): error CS8168: Cannot return local 's' by reference because it is not a ref local + // return ref s.F2(); // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(11, 20)); + } + + // This is a clone of UnscopedRefAttribute_Method_03 from RefFieldTests.cs + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Method_03_ClassConstrainedTypeParameter(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public interface S +{ + public ref T F1(); + [UnscopedRef] public ref T F2(); +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program where T : class, S +{ + static ref int F1() + { + var s = GetS(); + return ref s.F1(); + } + static ref int F2() + { + var s = GetS(); + return ref s.F2(); // 1 + } + + static T GetS() => throw null; +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of UnscopedRefAttribute_Property_02 from RefFieldTests.cs + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Property_02_DirectInterface(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public interface S +{ + public ref T P1 {get;} + [UnscopedRef] public ref T P2 {get;} +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program +{ + static ref int F1() + { + var s = default(S); + return ref s.P1; + } + static ref int F2() + { + var s = default(S); + return ref s.P2; // 1 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of UnscopedRefAttribute_Property_02 from RefFieldTests.cs + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Property_02_ConstrainedTypeParameter(bool useCompilationReference, bool addStructConstraint) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public interface S +{ + public ref T P1 {get;} + [UnscopedRef] public ref T P2 {get;} +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program where T : " + (addStructConstraint ? "struct, " : "") + @"S" + (!addStructConstraint ? ", new()" : "") + @" +{ + static ref int F1() + { + var s = new T(); + return ref s.P1; + } + static ref int F2() + { + var s = new T(); + return ref s.P2; // 1 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics( + // (11,20): error CS8168: Cannot return local 's' by reference because it is not a ref local + // return ref s.P2; // 1 + Diagnostic(ErrorCode.ERR_RefReturnLocal, "s").WithArguments("s").WithLocation(11, 20)); + } + + // This is a clone of UnscopedRefAttribute_Property_02 from RefFieldTests.cs + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_Property_02_ClassConstrainedTypeParameter(bool useCompilationReference) + { + var sourceA = +@"using System.Diagnostics.CodeAnalysis; +public interface S +{ + public ref T P1 {get;} + [UnscopedRef] public ref T P2 {get;} +}"; + var comp = CreateCompilation(new[] { sourceA, UnscopedRefAttributeDefinition }); + comp.VerifyEmitDiagnostics(); + var refA = AsReference(comp, useCompilationReference); + + var sourceB = +@"class Program where T : class, S, new() +{ + static ref int F1() + { + var s = new T(); + return ref s.P1; + } + static ref int F2() + { + var s = new T(); + return ref s.P2; // 1 + } +}"; + comp = CreateCompilation(sourceB, references: new[] { refA }); + comp.VerifyEmitDiagnostics(); + } + + public enum ThreeState : byte + { + Unknown = 0, + False = 1, + True = 2, + } + + // This is a clone of UnscopedRefAttribute_NestedAccess_MethodOrProperty from RefFieldTests.cs + [Theory, CombinatorialData] + public void UnscopedRefAttribute_NestedAccess_MethodOrProperty(bool firstIsMethod, bool secondIsMethod, ThreeState tS1IsClass, ThreeState tS2IsClass) + { + var source = $$""" +using System.Diagnostics.CodeAnalysis; + +{{(tS1IsClass == ThreeState.True || tS2IsClass == ThreeState.True ? "" : """ +var c = new C, S2>(); +c.Value() = 12; +System.Console.WriteLine(c.Value()); +""")}} + +class C + where TS1 : {{(tS1IsClass switch { ThreeState.False => "struct, ", ThreeState.True => "class, ", _ => "" })}}IS1 + where TS2 : {{(tS2IsClass switch { ThreeState.False => "struct, ", ThreeState.True => "class, ", _ => "" })}}IS2 +{ + public ref int Value() => ref s1.S2{{csharp(firstIsMethod)}}.Value{{csharp(secondIsMethod)}}; +#line 100 + private TS1 s1; +} + +struct S1 : IS1 where TS2 : IS2 +{ + private TS2 s2; + [UnscopedRef] public ref TS2 S2{{csharp(firstIsMethod)}} => ref s2; +} + +struct S2 : IS2 +{ + private int value; + [UnscopedRef] public ref int Value{{csharp(secondIsMethod)}} => ref value; +} + +interface IS1 where TS2 : IS2 +{ + [UnscopedRef] public ref TS2 S2{{(firstIsMethod ? "();" : "{get;}")}} +} + +interface IS2 +{ + [UnscopedRef] public ref int Value{{(secondIsMethod ? "();" : "{get;}")}} +} +"""; + var verifier = CompileAndVerify(new[] { source, UnscopedRefAttributeDefinition }, expectedOutput: (tS1IsClass == ThreeState.True || tS2IsClass == ThreeState.True ? null : "12"), verify: Verification.Fails); + verifier.VerifyDiagnostics( + // 0.cs(100,17): warning CS0649: Field 'C.s1' is never assigned to, and will always have its default value + // private TS1 s1; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s1").WithArguments("C.s1", tS1IsClass == ThreeState.True ? "null" : "").WithLocation(100, 17) + ); + verifier.VerifyMethodBody("C.Value", + tS1IsClass == ThreeState.True ? $$""" +{ + // Code size 28 (0x1c) + .maxstack 1 + // sequence point: s1.S2{{csharp(firstIsMethod)}}.Value{{csharp(secondIsMethod)}} + IL_0000: ldarg.0 + IL_0001: ldfld "TS1 C.s1" + IL_0006: box "TS1" + IL_000b: callvirt "ref TS2 IS1.S2{{il(firstIsMethod)}}" + IL_0010: constrained. "TS2" + IL_0016: callvirt "ref int IS2.Value{{il(secondIsMethod)}}" + IL_001b: ret +} +""" : $$""" +{ + // Code size 29 (0x1d) + .maxstack 1 + // sequence point: s1.S2{{csharp(firstIsMethod)}}.Value{{csharp(secondIsMethod)}} + IL_0000: ldarg.0 + IL_0001: ldflda "TS1 C.s1" + IL_0006: constrained. "TS1" + IL_000c: callvirt "ref TS2 IS1.S2{{il(firstIsMethod)}}" + IL_0011: constrained. "TS2" + IL_0017: callvirt "ref int IS2.Value{{il(secondIsMethod)}}" + IL_001c: ret +} +"""); + + static string csharp(bool method) => method ? "()" : ""; + static string il(bool method) => method ? "()" : ".get"; + } + + // This is a clone of UnscopedRefAttribute_NestedAccess_Properties_Invalid from RefFieldTests.cs + [Fact] + public void UnscopedRefAttribute_NestedAccess_Properties_Invalid_DirectInterface() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + + class C + { + private S1 s1; + public ref int Value() => ref s1.S2.Value; + } + + struct S1 + { + private S2 s2; + public S2 S2 => s2; + } + + interface S2 + { + [UnscopedRef] public ref int Value {get;} + } + """; + CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }).VerifyDiagnostics( + // 0.cs(11,16): warning CS0649: Field 'S1.s2' is never assigned to, and will always have its default value null + // private S2 s2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s2").WithArguments("S1.s2", "null").WithLocation(11, 16)); + } + + // This is a clone of UnscopedRefAttribute_NestedAccess_Properties_Invalid from RefFieldTests.cs + [CombinatorialData] + [Theory] + public void UnscopedRefAttribute_NestedAccess_Properties_Invalid_ConstrainedTypeParameter(bool addStructConstraint) + { + var source = +@"using System.Diagnostics.CodeAnalysis; + +class C where T : " + (addStructConstraint ? "struct, " : "") + @"S2 +{ + private S1 s1; + public ref int Value() => ref s1.S2.Value; +} + +struct S1 where T : S2 +{ + private T s2; + public T S2 => s2; +} + +interface S2 +{ + [UnscopedRef] public ref int Value {get;} +} +"; + CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }).VerifyDiagnostics( + // 0.cs(6,35): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // public ref int Value() => ref s1.S2.Value; + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "s1.S2").WithLocation(6, 35), + // 0.cs(11,15): warning CS0649: Field 'S1.s2' is never assigned to, and will always have its default value + // private T s2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s2").WithArguments("S1.s2", "").WithLocation(11, 15)); + } + + // This is a clone of UnscopedRefAttribute_NestedAccess_Properties_Invalid from RefFieldTests.cs + [Fact] + public void UnscopedRefAttribute_NestedAccess_Properties_Invalid_ClassConstrainedTypeParameter() + { + var source = +@"using System.Diagnostics.CodeAnalysis; + +class C where T : class, S2 +{ + private S1 s1; + public ref int Value() => ref s1.S2.Value; +} + +struct S1 where T : S2 +{ + private T s2; + public T S2 => s2; +} + +interface S2 +{ + [UnscopedRef] public ref int Value {get;} +} +"; + CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }).VerifyDiagnostics( + // 0.cs(11,15): warning CS0649: Field 'S1.s2' is never assigned to, and will always have its default value + // private T s2; + Diagnostic(ErrorCode.WRN_UnassignedInternalField, "s2").WithArguments("S1.s2", "").WithLocation(11, 15)); + } + + // This is a clone of UnscopedRef_ArgumentsMustMatch_01 from RefFieldTests.cs + [Fact] + public void UnscopedRef_ArgumentsMustMatch_01_DirectInterface() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + + ref struct RefByteContainer + { + public ref byte RB; + + public RefByteContainer(ref byte rb) + { + RB = ref rb; + } + } + + interface ByteContainer + { + [UnscopedRef] + public RefByteContainer ByteRef {get;} + + [UnscopedRef] + public RefByteContainer GetByteRef(); + } + + public class Program + { + static void M11(ref ByteContainer bc) + { + // ok. because ref-safe-to-escape of 'this' in 'ByteContainer.ByteRef.get' is 'ReturnOnly', + // we know that 'ref bc' will not end up written to a ref field within 'bc'. + _ = bc.ByteRef; + } + static void M12(ref ByteContainer bc) + { + // ok. because ref-safe-to-escape of 'this' in 'ByteContainer.GetByteRef()' is 'ReturnOnly', + // we know that 'ref bc' will not end up written to a ref field within 'bc'. + _ = bc.GetByteRef(); + } + + static void M21(ref ByteContainer bc, ref RefByteContainer rbc) + { + // error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter. + rbc = bc.ByteRef; // 1 + } + static void M22(ref ByteContainer bc, ref RefByteContainer rbc) + { + // error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter. + rbc = bc.GetByteRef(); // 2 + } + + static RefByteContainer M31(ref ByteContainer bc) + // ok. ref-safe-to-escape of 'bc' is 'ReturnOnly'. + => bc.ByteRef; + + static RefByteContainer M32(ref ByteContainer bc) + // ok. ref-safe-to-escape of 'bc' is 'ReturnOnly'. + => bc.GetByteRef(); + + static RefByteContainer M41(scoped ref ByteContainer bc) + // error: `bc.ByteRef` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod. + => bc.ByteRef; // 3 + + static RefByteContainer M42(scoped ref ByteContainer bc) + // error: `bc.GetByteRef()` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod. + => bc.GetByteRef(); // 4 + } + """; + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics(); + } + + // This is a clone of UnscopedRef_ArgumentsMustMatch_01 from RefFieldTests.cs + [Theory] + [CombinatorialData] + public void UnscopedRef_ArgumentsMustMatch_0_ConstrainedTypeParameter(bool addStructConstraint) + { + var source = $$""" + using System.Diagnostics.CodeAnalysis; + + ref struct RefByteContainer + { + public ref byte RB; + + public RefByteContainer(ref byte rb) + { + RB = ref rb; + } + } + + interface ByteContainer + { + [UnscopedRef] + public RefByteContainer ByteRef {get;} + + [UnscopedRef] + public RefByteContainer GetByteRef(); + } + + class Program where TByteContainer : {{(addStructConstraint ? "struct, " : "")}} ByteContainer + { + static void M11(ref TByteContainer bc) + { + // ok. because ref-safe-to-escape of 'this' in 'ByteContainer.ByteRef.get' is 'ReturnOnly', + // we know that 'ref bc' will not end up written to a ref field within 'bc'. + _ = bc.ByteRef; + } + static void M12(ref TByteContainer bc) + { + // ok. because ref-safe-to-escape of 'this' in 'ByteContainer.GetByteRef()' is 'ReturnOnly', + // we know that 'ref bc' will not end up written to a ref field within 'bc'. + _ = bc.GetByteRef(); + } + + static void M21(ref TByteContainer bc, ref RefByteContainer rbc) + { + // error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter. + rbc = bc.ByteRef; // 1 + } + static void M22(ref TByteContainer bc, ref RefByteContainer rbc) + { + // error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter. + rbc = bc.GetByteRef(); // 2 + } + + static RefByteContainer M31(ref TByteContainer bc) + // ok. ref-safe-to-escape of 'bc' is 'ReturnOnly'. + => bc.ByteRef; + + static RefByteContainer M32(ref TByteContainer bc) + // ok. ref-safe-to-escape of 'bc' is 'ReturnOnly'. + => bc.GetByteRef(); + + static RefByteContainer M41(scoped ref TByteContainer bc) + // error: `bc.ByteRef` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod. + => bc.ByteRef; // 3 + + static RefByteContainer M42(scoped ref TByteContainer bc) + // error: `bc.GetByteRef()` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod. + => bc.GetByteRef(); // 4 + } + """; + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (40,15): error CS9077: Cannot return a parameter by reference 'bc' through a ref parameter; it can only be returned in a return statement + // rbc = bc.ByteRef; // 1 + Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "bc").WithArguments("bc").WithLocation(40, 15), + // (45,15): error CS9077: Cannot return a parameter by reference 'bc' through a ref parameter; it can only be returned in a return statement + // rbc = bc.GetByteRef(); // 2 + Diagnostic(ErrorCode.ERR_RefReturnOnlyParameter, "bc").WithArguments("bc").WithLocation(45, 15), + // (58,12): error CS9075: Cannot return a parameter by reference 'bc' because it is scoped to the current method + // => bc.ByteRef; // 3 + Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "bc").WithArguments("bc").WithLocation(58, 12), + // (62,12): error CS9075: Cannot return a parameter by reference 'bc' because it is scoped to the current method + // => bc.GetByteRef(); // 4 + Diagnostic(ErrorCode.ERR_RefReturnScopedParameter, "bc").WithArguments("bc").WithLocation(62, 12) + ); + } + + // This is a clone of UnscopedRef_ArgumentsMustMatch_01 from RefFieldTests.cs + [Fact] + public void UnscopedRef_ArgumentsMustMatch_0_ClassConstrainedTypeParameter() + { + var source = """ + using System.Diagnostics.CodeAnalysis; + + ref struct RefByteContainer + { + public ref byte RB; + + public RefByteContainer(ref byte rb) + { + RB = ref rb; + } + } + + interface ByteContainer + { + [UnscopedRef] + public RefByteContainer ByteRef {get;} + + [UnscopedRef] + public RefByteContainer GetByteRef(); + } + + class Program where TByteContainer : class, ByteContainer + { + static void M11(ref TByteContainer bc) + { + // ok. because ref-safe-to-escape of 'this' in 'ByteContainer.ByteRef.get' is 'ReturnOnly', + // we know that 'ref bc' will not end up written to a ref field within 'bc'. + _ = bc.ByteRef; + } + static void M12(ref TByteContainer bc) + { + // ok. because ref-safe-to-escape of 'this' in 'ByteContainer.GetByteRef()' is 'ReturnOnly', + // we know that 'ref bc' will not end up written to a ref field within 'bc'. + _ = bc.GetByteRef(); + } + + static void M21(ref TByteContainer bc, ref RefByteContainer rbc) + { + // error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter. + rbc = bc.ByteRef; // 1 + } + static void M22(ref TByteContainer bc, ref RefByteContainer rbc) + { + // error. ref-safe-to-escape of 'bc' is 'ReturnOnly', therefore 'bc.ByteRef' can't be assigned to a ref parameter. + rbc = bc.GetByteRef(); // 2 + } + + static RefByteContainer M31(ref TByteContainer bc) + // ok. ref-safe-to-escape of 'bc' is 'ReturnOnly'. + => bc.ByteRef; + + static RefByteContainer M32(ref TByteContainer bc) + // ok. ref-safe-to-escape of 'bc' is 'ReturnOnly'. + => bc.GetByteRef(); + + static RefByteContainer M41(scoped ref TByteContainer bc) + // error: `bc.ByteRef` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod. + => bc.ByteRef; // 3 + + static RefByteContainer M42(scoped ref TByteContainer bc) + // error: `bc.GetByteRef()` may contain a reference to `bc`, whose ref-safe-to-escape is CurrentMethod. + => bc.GetByteRef(); // 4 + } + """; + + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics(); + } + + // PROTOTYPE(RefStructInterfaces): Add flavor of UnscopedRef_ArgumentsMustMatch_0 tests with RefByteContainer as an interface + + // This is a clone of PatternIndex_01 from RefFieldTests.cs + [Fact] + public void PatternIndex_01_DirectInterface() + { + string source = """ + using System; + using System.Diagnostics.CodeAnalysis; + interface R + { + public int Length {get;} + [UnscopedRef] public ref int this[int i] {get;} + } + class Program + { + static ref int F1(ref R r1) + { + ref int i1 = ref r1[^1]; + return ref i1; + } + static ref int F2(ref R r2, Index i) + { + ref int i2 = ref r2[i]; + return ref i2; + } + static ref int F3() + { + R r3 = GetR(); + ref int i3 = ref r3[^3]; + return ref i3; // 1 + } + static ref int F4(Index i) + { + R r4 = GetR(); + ref int i4 = ref r4[i]; + return ref i4; // 2 + } + + static R GetR() => null; + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics(); + } + + // This is a clone of PatternIndex_01 from RefFieldTests.cs + [Theory] + [CombinatorialData] + public void PatternIndex_01_ConstrainedTypeParameter(bool addStructConstraint) + { + string source = $$""" + using System; + using System.Diagnostics.CodeAnalysis; + interface R + { + public int Length {get;} + [UnscopedRef] public ref int this[int i] {get;} + } + class Program where TR : {{(addStructConstraint ? "struct, " : "")}} R {{(!addStructConstraint ? ", new()" : "")}} + { + static ref int F1(ref TR r1) + { + ref int i1 = ref r1[^1]; + return ref i1; + } + static ref int F2(ref TR r2, Index i) + { + ref int i2 = ref r2[i]; + return ref i2; + } + static ref int F3() + { + TR r3 = new TR(); + ref int i3 = ref r3[^3]; + return ref i3; // 1 + } + static ref int F4(Index i) + { + TR r4 = new TR(); + ref int i4 = ref r4[i]; + return ref i4; // 2 + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics( + // (24,20): error CS8157: Cannot return 'i3' by reference because it was initialized to a value that cannot be returned by reference + // return ref i3; // 1 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i3").WithArguments("i3").WithLocation(24, 20), + // (30,20): error CS8157: Cannot return 'i4' by reference because it was initialized to a value that cannot be returned by reference + // return ref i4; // 2 + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "i4").WithArguments("i4").WithLocation(30, 20)); + } + + // This is a clone of PatternIndex_01 from RefFieldTests.cs + [Fact] + public void PatternIndex_01_ClassConstrainedTypeParameter() + { + string source = """ + using System; + using System.Diagnostics.CodeAnalysis; + interface R + { + public int Length {get;} + [UnscopedRef] public ref int this[int i] {get;} + } + class Program where TR : class, R, new() + { + static ref int F1(ref TR r1) + { + ref int i1 = ref r1[^1]; + return ref i1; + } + static ref int F2(ref TR r2, Index i) + { + ref int i2 = ref r2[i]; + return ref i2; + } + static ref int F3() + { + TR r3 = new TR(); + ref int i3 = ref r3[^3]; + return ref i3; // 1 + } + static ref int F4(Index i) + { + TR r4 = new TR(); + ref int i4 = ref r4[i]; + return ref i4; // 2 + } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyDiagnostics(); + } + + // This is a clone of MemberOfReadonlyRefLikeEscape from RefEscapingTests.cs + [Fact] + public void MemberOfReadonlyRefLikeEscape_DirectInterface() + { + var text = @" + using System; + using System.Diagnostics.CodeAnalysis; + public static class Program + { + public static void Main() + { + Span value1 = stackalloc int[1]; + + // Ok, the new value can be copied into SW but not the + // ref to the value + Get_SW().TryGet(out value1); + + // Error as the ref of this can escape into value2 + Span value2 = default; + Get_SW().TryGet2(out value2); + } + + static SW Get_SW() => throw null; + } + + interface SW + { + public void TryGet(out Span result); + + [UnscopedRef] + public void TryGet2(out Span result); + } +"; + CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }).VerifyDiagnostics(); + } + + // This is a clone of MemberOfReadonlyRefLikeEscape from RefEscapingTests.cs + [Theory] + [CombinatorialData] + public void MemberOfReadonlyRefLikeEscape_ConstrainedTypeParameter(bool addStructConstraint) + { + var text = @" + using System; + using System.Diagnostics.CodeAnalysis; + static class Program where TSW : " + (addStructConstraint ? "struct, " : "") + @"SW" + (!addStructConstraint ? ", new()" : "") + @" + { + public static void Main() + { + Span value1 = stackalloc int[1]; + + // Ok, the new value can be copied into SW but not the + // ref to the value + new TSW().TryGet(out value1); + + // Error as the ref of this can escape into value2 + Span value2 = default; + new TSW().TryGet2(out value2); + } + } + + interface SW + { + public void TryGet(out Span result); + + [UnscopedRef] + public void TryGet2(out Span result); + } +"; + CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }).VerifyDiagnostics( + // 0.cs(16,13): error CS8156: An expression cannot be used in this context because it may not be passed or returned by reference + // new TSW().TryGet2(out value2); + Diagnostic(ErrorCode.ERR_RefReturnLvalueExpected, "new TSW()").WithLocation(16, 13), + // 0.cs(16,13): error CS8350: This combination of arguments to 'SW.TryGet2(out Span)' is disallowed because it may expose variables referenced by parameter 'this' outside of their declaration scope + // new TSW().TryGet2(out value2); + Diagnostic(ErrorCode.ERR_CallArgMixing, "new TSW().TryGet2(out value2)").WithArguments("SW.TryGet2(out System.Span)", "this").WithLocation(16, 13) + ); + } + + // This is a clone of MemberOfReadonlyRefLikeEscape from RefEscapingTests.cs + [Fact] + public void MemberOfReadonlyRefLikeEscape_ClassConstrainedTypeParameter() + { + var text = @" + using System; + using System.Diagnostics.CodeAnalysis; + static class Program where TSW : class, SW, new() + { + public static void Main() + { + Span value1 = stackalloc int[1]; + + // Ok, the new value can be copied into SW but not the + // ref to the value + new TSW().TryGet(out value1); + + // Error as the ref of this can escape into value2 + Span value2 = default; + new TSW().TryGet2(out value2); + } + } + + interface SW + { + public void TryGet(out Span result); + + [UnscopedRef] + public void TryGet2(out Span result); + } +"; + CreateCompilationWithMscorlibAndSpan(new[] { text, UnscopedRefAttributeDefinition }).VerifyDiagnostics(); + } + + // This is a clone of DefensiveCopy_01 from RefEscapingTests.cs + [Fact] + public void DefensiveCopy_01_DirectInterface() + { + var source = +@" +using System; +using System.Diagnostics.CodeAnalysis; + +internal class Program +{ + private static readonly Vec4 ReadOnlyVec = GetVec4(); + + static void Main() + { + // This refers to stack memory that has already been left out. + ref Vec4 local = ref Test1(); + Console.WriteLine(local); + } + + private static ref Vec4 Test1() + { + // Defensive copy occurs and it is placed in stack memory implicitly. + // The method returns a reference to the copy, which happens invalid memory access. + ref Vec4 xyzw1 = ref ReadOnlyVec.Self; + return ref xyzw1; + } + + private static ref Vec4 Test2() + { + var copy = ReadOnlyVec; + ref Vec4 xyzw2 = ref copy.Self; + return ref xyzw2; + } + + private static ref Vec4 Test3() + { + ref Vec4 xyzw3 = ref ReadOnlyVec.Self2(); + return ref xyzw3; + } + + private static ref Vec4 Test4() + { + var copy = ReadOnlyVec; + ref Vec4 xyzw4 = ref copy.Self2(); + return ref xyzw4; + } + + static Vec4 GetVec4() => throw null; +} + +public interface Vec4 +{ + [UnscopedRef] + public ref Vec4 Self {get;} + + [UnscopedRef] + public ref Vec4 Self2(); +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of DefensiveCopy_01 from RefEscapingTests.cs + [Theory] + [CombinatorialData] + public void DefensiveCopy_01_ConstrainedTypeParameter(bool addStructConstraint) + { + var source = +@" +using System; +using System.Runtime.CompilerServices; +using System.Diagnostics.CodeAnalysis; + +internal class Program where TVec4 : " + (addStructConstraint ? "struct, " : "") + @" Vec4 +{ + private static readonly TVec4 ReadOnlyVec = GetVec4(); + + static void Main() + { + // This refers to stack memory that has already been left out. + ref TVec4 local = ref Test1(); + Console.WriteLine(local); + } + + private static ref TVec4 Test1() + { + // Defensive copy occurs and it is placed in stack memory implicitly. + // The method returns a reference to the copy, which happens invalid memory access. + ref TVec4 xyzw1 = ref ReadOnlyVec.Self; + return ref xyzw1; + } + + private static ref TVec4 Test2() + { + var copy = ReadOnlyVec; + ref TVec4 xyzw2 = ref copy.Self; + return ref xyzw2; + } + + private static ref TVec4 Test3() + { + ref TVec4 xyzw3 = ref ReadOnlyVec.Self2(); + return ref xyzw3; + } + + private static ref TVec4 Test4() + { + var copy = ReadOnlyVec; + ref TVec4 xyzw4 = ref copy.Self2(); + return ref xyzw4; + } + + static TVec4 GetVec4() => throw null; +} + +public interface Vec4 where TVec4 : Vec4 +{ + [UnscopedRef] + public ref TVec4 Self {get;} + + [UnscopedRef] + public ref TVec4 Self2(); +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (22,20): error CS8157: Cannot return 'xyzw1' by reference because it was initialized to a value that cannot be returned by reference + // return ref xyzw1; + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "xyzw1").WithArguments("xyzw1").WithLocation(22, 20), + // (29,20): error CS8157: Cannot return 'xyzw2' by reference because it was initialized to a value that cannot be returned by reference + // return ref xyzw2; + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "xyzw2").WithArguments("xyzw2").WithLocation(29, 20), + // (35,20): error CS8157: Cannot return 'xyzw3' by reference because it was initialized to a value that cannot be returned by reference + // return ref xyzw3; + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "xyzw3").WithArguments("xyzw3").WithLocation(35, 20), + // (42,20): error CS8157: Cannot return 'xyzw4' by reference because it was initialized to a value that cannot be returned by reference + // return ref xyzw4; + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "xyzw4").WithArguments("xyzw4").WithLocation(42, 20) + ); + } + + // This is a clone of DefensiveCopy_01 from RefEscapingTests.cs + [Fact] + public void DefensiveCopy_01_ClassConstrainedTypeParameter() + { + var source = +@" +using System; +using System.Diagnostics.CodeAnalysis; + +internal class Program where TVec4 : class, Vec4 +{ + private static readonly TVec4 ReadOnlyVec = GetVec4(); + + static void Main() + { + // This refers to stack memory that has already been left out. + ref TVec4 local = ref Test1(); + Console.WriteLine(local); + } + + private static ref TVec4 Test1() + { + // Defensive copy occurs and it is placed in stack memory implicitly. + // The method returns a reference to the copy, which happens invalid memory access. + ref TVec4 xyzw1 = ref ReadOnlyVec.Self; + return ref xyzw1; + } + + private static ref TVec4 Test2() + { + var copy = ReadOnlyVec; + ref TVec4 xyzw2 = ref copy.Self; + return ref xyzw2; + } + + private static ref TVec4 Test3() + { + ref TVec4 xyzw3 = ref ReadOnlyVec.Self2(); + return ref xyzw3; + } + + private static ref TVec4 Test4() + { + var copy = ReadOnlyVec; + ref TVec4 xyzw4 = ref copy.Self2(); + return ref xyzw4; + } + + static TVec4 GetVec4() => throw null; +} + +public interface Vec4 where TVec4 : Vec4 +{ + [UnscopedRef] + public ref TVec4 Self {get;} + + [UnscopedRef] + public ref TVec4 Self2(); +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of DefensiveCopy_02 from RefEscapingTests.cs + [Fact] + public void DefensiveCopy_02() + { + var source = +@"using System.Diagnostics.CodeAnalysis; + +class Program +{ + static ref Wrap m1(in Wrap i) + { + ref Wrap r1 = ref i.Self; // defensive copy + return ref r1; // ref to the local copy + } + + static ref Wrap m2(in Wrap i) + { + var copy = i; + ref Wrap r2 = ref copy.Self; + return ref r2; // ref to the local copy + } + + static ref Wrap m3(in Wrap i) + { + ref Wrap r3 = ref i.Self2(); + return ref r3; + } + + static ref Wrap m4(in Wrap i) + { + var copy = i; + ref Wrap r4 = ref copy.Self2(); + return ref r4; // ref to the local copy + } +} + +struct Wrap +{ + public float X; + + [UnscopedRef] + public ref Wrap Self => ref this; + + [UnscopedRef] + public ref Wrap Self2() => ref this; +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (8,20): error CS8157: Cannot return 'r1' by reference because it was initialized to a value that cannot be returned by reference + // return ref r1; // ref to the local copy + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r1").WithArguments("r1").WithLocation(8, 20), + // (15,20): error CS8157: Cannot return 'r2' by reference because it was initialized to a value that cannot be returned by reference + // return ref r2; // ref to the local copy + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r2").WithArguments("r2").WithLocation(15, 20), + // (21,20): error CS8157: Cannot return 'r3' by reference because it was initialized to a value that cannot be returned by reference + // return ref r3; + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r3").WithArguments("r3").WithLocation(21, 20), + // (28,20): error CS8157: Cannot return 'r4' by reference because it was initialized to a value that cannot be returned by reference + // return ref r4; // ref to the local copy + Diagnostic(ErrorCode.ERR_RefReturnNonreturnableLocal, "r4").WithArguments("r4").WithLocation(28, 20) + ); + } + + // This is a clone of DefensiveCopy_05 from RefEscapingTests.cs + [Fact] + public void DefensiveCopy_05_DirectInterface() + { + var source = +@" +using System; +using System.Diagnostics.CodeAnalysis; + +internal class Program +{ + private static readonly Vec4 ReadOnlyVec = default; + + static void Main() + { + } + + private static Span Test1() + { + var xyzw1 = ReadOnlyVec.Self; + return xyzw1; + } + + private static Span Test2() + { + var r2 = ReadOnlyVec; + var xyzw2 = r2.Self; + return xyzw2; + } +} + +public interface Vec4 +{ + [UnscopedRef] + public Span Self + { get; set; } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of DefensiveCopy_05 from RefEscapingTests.cs + [Theory] + [CombinatorialData] + public void DefensiveCopy_05_ConstrainedTypeParameter(bool addStructConstraint) + { + var source = +@" +using System; +using System.Diagnostics.CodeAnalysis; + +internal class Program where TVec4 : " + (addStructConstraint ? "struct, " : "") + @" Vec4 +{ + private static readonly TVec4 ReadOnlyVec = default; + + static void Main() + { + } + + private static Span Test1() + { + var xyzw1 = ReadOnlyVec.Self; + return xyzw1; + } + + private static Span Test2() + { + var r2 = ReadOnlyVec; + var xyzw2 = r2.Self; + return xyzw2; + } +} + +public interface Vec4 +{ + [UnscopedRef] + public Span Self + { get; set; } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (16,16): error CS8352: Cannot use variable 'xyzw1' in this context because it may expose referenced variables outside of their declaration scope + // return xyzw1; + Diagnostic(ErrorCode.ERR_EscapeVariable, "xyzw1").WithArguments("xyzw1").WithLocation(16, 16), + // (23,16): error CS8352: Cannot use variable 'xyzw2' in this context because it may expose referenced variables outside of their declaration scope + // return xyzw2; + Diagnostic(ErrorCode.ERR_EscapeVariable, "xyzw2").WithArguments("xyzw2").WithLocation(23, 16) + ); + } + + // This is a clone of DefensiveCopy_05 from RefEscapingTests.cs + [Fact] + public void DefensiveCopy_05_ClassdConstrainedTypeParameter() + { + var source = +@" +using System; +using System.Diagnostics.CodeAnalysis; + +internal class Program where TVec4 : class, Vec4 +{ + private static readonly TVec4 ReadOnlyVec = default; + + static void Main() + { + } + + private static Span Test1() + { + var xyzw1 = ReadOnlyVec.Self; + return xyzw1; + } + + private static Span Test2() + { + var r2 = ReadOnlyVec; + var xyzw2 = r2.Self; + return xyzw2; + } +} + +public interface Vec4 +{ + [UnscopedRef] + public Span Self + { get; set; } +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of DefensiveCopy_21 from RefEscapingTests.cs + [Fact] + public void DefensiveCopy_21_DirectInterface() + { + var source = +@" +using System; +using System.Diagnostics.CodeAnalysis; + +internal class Program +{ + private static readonly Vec4 ReadOnlyVec = default; + + static void Main() + { + } + + private static Span Test1() + { + var (xyzw1, _) = ReadOnlyVec; + return xyzw1; + } + + private static Span Test2() + { + var r2 = ReadOnlyVec; + var (xyzw2, _) = r2; + return xyzw2; + } + + private static Span Test3() + { + ReadOnlyVec.Deconstruct(out var xyzw3, out _); + return xyzw3; + } + + private static Span Test4() + { + var r4 = ReadOnlyVec; + r4.Deconstruct(out var xyzw4, out _); + return xyzw4; + } +} + +public interface Vec4 +{ + [UnscopedRef] + public void Deconstruct(out Span x, out int i); +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of DefensiveCopy_21 from RefEscapingTests.cs + [Theory] + [CombinatorialData] + public void DefensiveCopy_21_ConstrainedTypeParameter(bool addStructConstraint) + { + var source = +@" +using System; +using System.Diagnostics.CodeAnalysis; + +internal class Program where TVec4 : " + (addStructConstraint ? "struct, " : "") + @" Vec4 +{ + private static readonly TVec4 ReadOnlyVec = default; + + static void Main() + { + } + + private static Span Test1() + { + var (xyzw1, _) = ReadOnlyVec; + return xyzw1; + } + + private static Span Test2() + { + var r2 = ReadOnlyVec; + var (xyzw2, _) = r2; + return xyzw2; + } + + private static Span Test3() + { + ReadOnlyVec.Deconstruct(out var xyzw3, out _); + return xyzw3; + } + + private static Span Test4() + { + var r4 = ReadOnlyVec; + r4.Deconstruct(out var xyzw4, out _); + return xyzw4; + } +} + +public interface Vec4 +{ + [UnscopedRef] + public void Deconstruct(out Span x, out int i); +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics( + // (16,16): error CS8352: Cannot use variable 'xyzw1' in this context because it may expose referenced variables outside of their declaration scope + // return xyzw1; + Diagnostic(ErrorCode.ERR_EscapeVariable, "xyzw1").WithArguments("xyzw1").WithLocation(16, 16), + // (23,16): error CS8352: Cannot use variable 'xyzw2' in this context because it may expose referenced variables outside of their declaration scope + // return xyzw2; + Diagnostic(ErrorCode.ERR_EscapeVariable, "xyzw2").WithArguments("xyzw2").WithLocation(23, 16), + // (29,16): error CS8352: Cannot use variable 'xyzw3' in this context because it may expose referenced variables outside of their declaration scope + // return xyzw3; + Diagnostic(ErrorCode.ERR_EscapeVariable, "xyzw3").WithArguments("xyzw3").WithLocation(29, 16), + // (36,16): error CS8352: Cannot use variable 'xyzw4' in this context because it may expose referenced variables outside of their declaration scope + // return xyzw4; + Diagnostic(ErrorCode.ERR_EscapeVariable, "xyzw4").WithArguments("xyzw4").WithLocation(36, 16) + ); + } + + // This is a clone of DefensiveCopy_21 from RefEscapingTests.cs + [Fact] + public void DefensiveCopy_21_ClassConstrainedTypeParameter() + { + var source = +@" +using System; +using System.Diagnostics.CodeAnalysis; + +internal class Program where TVec4 : class, Vec4 +{ + private static readonly TVec4 ReadOnlyVec = default; + + static void Main() + { + } + + private static Span Test1() + { + var (xyzw1, _) = ReadOnlyVec; + return xyzw1; + } + + private static Span Test2() + { + var r2 = ReadOnlyVec; + var (xyzw2, _) = r2; + return xyzw2; + } + + private static Span Test3() + { + ReadOnlyVec.Deconstruct(out var xyzw3, out _); + return xyzw3; + } + + private static Span Test4() + { + var r4 = ReadOnlyVec; + r4.Deconstruct(out var xyzw4, out _); + return xyzw4; + } +} + +public interface Vec4 +{ + [UnscopedRef] + public void Deconstruct(out Span x, out int i); +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + } +} diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs index a787c577b41e6..d216daf72365d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/RefFieldTests.cs @@ -22058,10 +22058,10 @@ object P6 }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition, IsExternalInitTypeDefinition }); comp.VerifyDiagnostics( - // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object P3 { get; init; } // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6), - // (15,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (15,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] init; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 10)); } @@ -22161,7 +22161,7 @@ R this[int i] // (11,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. // init { value.F = ref this; } // 1 Diagnostic(ErrorCode.ERR_RefAssignNarrower, "value.F = ref this").WithArguments("F", "this").WithLocation(11, 16), - // (19,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (19,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(19, 10), // (20,16): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. @@ -22193,22 +22193,22 @@ [UnscopedRef] event D E6 { add { } remove { } } // 6 }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net60); comp.VerifyDiagnostics( - // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D E1; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6), - // (7,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (7,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D E2 { add { } remove { } } // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 6), - // (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D E3; // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6), - // (12,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (12,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D E4 { add { } remove { } } // 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 6), - // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D E5; // 5 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6), - // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D E6 { add { } remove { } } // 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6)); } @@ -22238,22 +22238,22 @@ event D E6 { add { } [UnscopedRef] remove { } } // 6 "; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyDiagnostics( - // (6,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (6,19): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D E1 { [UnscopedRef] add { } remove { } } // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 19), - // (7,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (7,27): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D E2 { add { } [UnscopedRef] remove { } } // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 27), - // (11,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (11,19): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D E3 { [UnscopedRef] add { } remove { } } // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 19), - // (12,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (12,27): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D E4 { add { } [UnscopedRef] remove { } } // 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 27), - // (16,19): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,19): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D E5 { [UnscopedRef] add { } remove { } } // 5 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 19), - // (17,27): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (17,27): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D E6 { add { } [UnscopedRef] remove { } } // 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 27)); } @@ -22278,10 +22278,10 @@ void F() "; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (6,18): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (6,18): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // var d = [UnscopedRef] (ref int i) => ref i; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 18), - // (7,10): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (7,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] ref int Local() => throw null; Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(7, 10)); } @@ -22467,7 +22467,7 @@ struct B // (15,6): warning CS0436: The type 'UnscopedRefAttribute' in '1.cs' conflicts with the imported type 'UnscopedRefAttribute' in 'System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. Using the type defined in ''. // [UnscopedRef] Diagnostic(ErrorCode.WRN_SameFullNameThisAggAgg, "UnscopedRef").WithArguments("1.cs", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute", "System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Diagnostics.CodeAnalysis.UnscopedRefAttribute").WithLocation(15, 6), - // (15,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (15,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 6), // (18,9): error CS8374: Cannot ref-assign 'this' to 'F' because 'this' has a narrower escape scope than 'F'. @@ -22486,7 +22486,7 @@ class C }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] ~C() { } Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6)); } @@ -22504,13 +22504,13 @@ [UnscopedRef] static S() { } // 1 }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static S() { } // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6), - // (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static object F() => null; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6), - // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static object P => null; // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6)); } @@ -22534,10 +22534,10 @@ record struct S }"; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyDiagnostics( - // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (4,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object F1() => null; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(4, 6), - // (8,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (8,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] object F2() => null; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 6)); } @@ -25038,30 +25038,31 @@ [UnscopedRef] void I.F2() { } // 6 """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (23,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // (23,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.F1()' doesn't have this attribute. // [UnscopedRef] public ref int F1() => ref _f2; // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(23, 34), - // (24,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithArguments("I.F1()").WithLocation(23, 34), + // (24,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.F2()' doesn't have this attribute. // [UnscopedRef] public void F2() { } // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(24, 31), - // (25,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithArguments("I.F2()").WithLocation(24, 31), + // (25,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.F3(out R)' doesn't have this attribute. // [UnscopedRef] public void F3(out R r) { r = new R(ref _f2); } // 3 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(25, 31), - // (26,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithArguments("I.F3(out R)").WithLocation(25, 31), + // (26,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.P.get' doesn't have this attribute. // [UnscopedRef] public ref int P => ref _f2; // 4 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f2").WithLocation(26, 39), - // (38,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f2").WithArguments("I.P.get").WithLocation(26, 39), + // (38,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.F1()' doesn't have this attribute. // [UnscopedRef] ref int I.F1() => ref _f4; // 5 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(38, 34), - // (39,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithArguments("I.F1()").WithLocation(38, 34), + // (39,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.F2()' doesn't have this attribute. // [UnscopedRef] void I.F2() { } // 6 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(39, 31), - // (40,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithArguments("I.F2()").WithLocation(39, 31), + // (40,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.F3(out R)' doesn't have this attribute. // [UnscopedRef] void I.F3(out R r) { r = new R(ref _f4); } // 7 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(40, 31), - // (41,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithArguments("I.F3(out R)").WithLocation(40, 31), + // (41,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.P.get' doesn't have this attribute. // [UnscopedRef] ref int I.P => ref _f4; // 8 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f4").WithLocation(41, 39)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f4").WithArguments("I.P.get").WithLocation(41, 39) + ); } // As above, but interface members are also marked [UnscopedRef]. @@ -25077,10 +25078,10 @@ public R(ref T t) { } } interface I { - [UnscopedRef] ref T F1(); // 1 - [UnscopedRef] void F2(); // 2 - [UnscopedRef] void F3(out R r); // 3 - [UnscopedRef] ref T P { get; } // 4 + [UnscopedRef] ref T F1(); + [UnscopedRef] void F2(); + [UnscopedRef] void F3(out R r); + [UnscopedRef] ref T P { get; } } struct S1 : I { @@ -25092,10 +25093,10 @@ public void F2() { } struct S2 : I { private int _f2; - [UnscopedRef] public ref int F1() => ref _f2; // 5 - [UnscopedRef] public void F2() { } // 6 - [UnscopedRef] public void F3(out R r) { r = new R(ref _f2); } // 7 - [UnscopedRef] public ref int P => ref _f2; // 8 + [UnscopedRef] public ref int F1() => ref _f2; + [UnscopedRef] public void F2() { } + [UnscopedRef] public void F3(out R r) { r = new R(ref _f2); } + [UnscopedRef] public ref int P => ref _f2; } struct S3 : I { @@ -25107,50 +25108,14 @@ void I.F2() { } struct S4 : I { private int _f4; - [UnscopedRef] ref int I.F1() => ref _f4; // 9 - [UnscopedRef] void I.F2() { } // 10 - [UnscopedRef] void I.F3(out R r) { r = new R(ref _f4); } // 11 - [UnscopedRef] ref int I.P => ref _f4; // 12 + [UnscopedRef] ref int I.F1() => ref _f4; + [UnscopedRef] void I.F2() { } + [UnscopedRef] void I.F3(out R r) { r = new R(ref _f4); } + [UnscopedRef] ref int I.P => ref _f4; } """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); - comp.VerifyEmitDiagnostics( - // (8,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - // [UnscopedRef] ref T F1(); // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 6), - // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - // [UnscopedRef] void F2(); // 2 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6), - // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - // [UnscopedRef] void F3(out R r); // 3 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6), - // (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - // [UnscopedRef] ref T P { get; } // 4 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6), - // (23,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. - // [UnscopedRef] public ref int F1() => ref _f2; // 5 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(23, 34), - // (24,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. - // [UnscopedRef] public void F2() { } // 6 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(24, 31), - // (25,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. - // [UnscopedRef] public void F3(out R r) { r = new R(ref _f2); } // 7 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(25, 31), - // (26,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. - // [UnscopedRef] public ref int P => ref _f2; // 8 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f2").WithLocation(26, 39), - // (38,34): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. - // [UnscopedRef] ref int I.F1() => ref _f4; // 9 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F1").WithLocation(38, 34), - // (39,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. - // [UnscopedRef] void I.F2() { } // 10 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F2").WithLocation(39, 31), - // (40,31): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. - // [UnscopedRef] void I.F3(out R r) { r = new R(ref _f4); } // 11 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "F3").WithLocation(40, 31), - // (41,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. - // [UnscopedRef] ref int I.P => ref _f4; // 12 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "ref _f4").WithLocation(41, 39)); + comp.VerifyEmitDiagnostics(); } [Fact] @@ -25189,27 +25154,28 @@ public int P3 { [UnscopedRef] set { } } // 7 """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (16,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + // (16,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I1.P1.get' doesn't have this attribute. // [UnscopedRef] public ref int P1 => throw null; // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "throw null").WithLocation(16, 40), - // (17,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "throw null").WithArguments("I1.P1.get").WithLocation(16, 40), + // (17,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I2.P2.get' doesn't have this attribute. // [UnscopedRef] public int P2 { get; set; } // 2, 3 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(17, 35), - // (17,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I2.P2.get").WithLocation(17, 35), + // (17,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I2.P2.set' doesn't have this attribute. // [UnscopedRef] public int P2 { get; set; } // 2, 3 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(17, 40), - // (21,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithArguments("I2.P2.set").WithLocation(17, 40), + // (21,39): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I1.P1.get' doesn't have this attribute. // public ref int P1 { [UnscopedRef] get => throw null; } // 4 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(21, 39), - // (22,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I1.P1.get").WithLocation(21, 39), + // (22,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I2.P2.get' doesn't have this attribute. // public int P2 { [UnscopedRef] get; set; } // 5 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithLocation(22, 35), - // (26,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I2.P2.get").WithLocation(22, 35), + // (26,40): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I2.P2.set' doesn't have this attribute. // public int P2 { get; [UnscopedRef] set; } // 6 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(26, 40), - // (27,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation. + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithArguments("I2.P2.set").WithLocation(26, 40), + // (27,35): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I3.P3.set' doesn't have this attribute. // public int P3 { [UnscopedRef] set { } } // 7 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithLocation(27, 35)); + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "set").WithArguments("I3.P3.set").WithLocation(27, 35) + ); } [Fact] @@ -25243,7 +25209,7 @@ public void UnscopedRefAttribute_InterfaceImplementation_05() interface I { ref T F1(); - [UnscopedRef] ref T F2(); // 1 + [UnscopedRef] ref T F2(); } class C1 : I { @@ -25260,19 +25226,16 @@ class C2 : I """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. - // [UnscopedRef] ref T F2(); // 1 - Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6), - // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public ref int F1() => ref _f1; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6), - // (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (11,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public ref int F2() => ref _f1; // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 6), - // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] ref int I.F1() => ref _f2; // 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6), - // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] ref int I.F2() => ref _f2; // 5 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6)); } @@ -25298,10 +25261,10 @@ class B : A, I """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public ref int F() => throw null; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6), - // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public ref int P => throw null; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6)); } @@ -25324,10 +25287,10 @@ interface IB : IA """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] ref int IA.F() => throw null; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6), - // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] ref int IA.P => throw null; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6)); } @@ -25370,22 +25333,22 @@ [UnscopedRef] event D I.E { add { } remove { } } // 6 """; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public event D E; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6), - // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public event D E { add { } remove { } } // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6), - // (18,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (18,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D I.E { add { } remove { } } // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(18, 6), - // (22,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (22,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public event D E; // 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 6), - // (26,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (26,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public event D E { add { } remove { } } // 5 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(26, 6), - // (30,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (30,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D I.E { add { } remove { } } // 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(30, 6)); } @@ -25425,28 +25388,28 @@ event D I.E2 { add { } [UnscopedRef] remove { } } // 8 """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (11,31): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (11,31): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // public event D E1 { [UnscopedRef] add { } remove { } } // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(11, 31), - // (12,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (12,39): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // public event D E2 { add { } [UnscopedRef] remove { } } // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(12, 39), - // (16,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,37): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D I.E1 { [UnscopedRef] add { } remove { } } // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 37), - // (17,45): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (17,45): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D I.E2 { add { } [UnscopedRef] remove { } } // 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 45), - // (21,31): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (21,31): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // public event D E1 { [UnscopedRef] add { } remove { } } // 5 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(21, 31), - // (22,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (22,39): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // public event D E2 { add { } [UnscopedRef] remove { } } // 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 39), - // (26,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (26,37): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D I.E1 { [UnscopedRef] add { } remove { } } // 7 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(26, 37), - // (27,45): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (27,45): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D I.E2 { add { } [UnscopedRef] remove { } } // 8 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(27, 45)); } @@ -25476,13 +25439,13 @@ event D I.E { add { } [UnscopedRef] remove { } } // 3 """; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }, targetFramework: TargetFramework.Net60); comp.VerifyEmitDiagnostics( - // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (9,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D I.E { add { } remove { } } // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(9, 6), - // (13,36): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (13,36): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D I.E { [UnscopedRef] add { } remove { } } // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 36), - // (17,44): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (17,44): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // event D I.E { add { } [UnscopedRef] remove { } } // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 44)); } @@ -25509,13 +25472,13 @@ [UnscopedRef] event D I.E { add { } remove { } } // 3 """; var comp = CreateCompilation(new[] { source, UnscopedRefAttributeDefinition }); comp.VerifyEmitDiagnostics( - // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D E; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6), - // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (10,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public event D E; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(10, 6), - // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] event D I.E { add { } remove { } } // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6)); } @@ -25553,40 +25516,40 @@ interface I """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (13,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (13,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public static R F() => default; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 6), - // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public static R P1 { get { return default; } set { } } // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6), - // (15,32): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (15,32): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // public static R P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 32), - // (15,70): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (15,70): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // public static R P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 70), - // (16,37): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,37): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // public static event D E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 37), - // (16,59): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,59): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // public static event D E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 59), - // (20,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (20,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static R I.F() => default; // 7 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(20, 6), - // (21,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (21,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static R I.P1 => default; // 8 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(21, 6), - // (22,38): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (22,38): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // static R I.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 9, 10 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 38), - // (22,76): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (22,76): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // static R I.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 9, 10 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(22, 76), - // (23,43): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (23,43): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // static event D I.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 11, 12 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(23, 43), - // (23,65): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (23,65): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // static event D I.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 11, 12 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(23, 65)); } @@ -25615,22 +25578,22 @@ interface IB : IA """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (13,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (13,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static R IA.F() => default; // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(13, 6), - // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (14,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] static R IA.P1 => default; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(14, 6), - // (15,39): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (15,39): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // static R IA.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 39), - // (15,77): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (15,77): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // static R IA.P2 { [UnscopedRef] get { return default; } [UnscopedRef] set { } } // 3, 4 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(15, 77), - // (16,44): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,44): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // static event D IA.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 44), - // (16,66): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,66): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // static event D IA.E { [UnscopedRef] add { } [UnscopedRef] remove { } } // 5, 6 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 66)); } @@ -25660,13 +25623,13 @@ class B2 : A """; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); comp.VerifyEmitDiagnostics( - // (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (5,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public abstract ref T F2(); // 1 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(5, 6), - // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (16,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public override ref string F1() => ref _f2; // 2 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(16, 6), - // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct instance methods and properties, and cannot be applied to constructors or init-only members. + // (17,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. // [UnscopedRef] public override ref string F2() => ref _f2; // 3 Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(17, 6)); } From 004452ee649fc2114865dbc83cc52d53c807dbda Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Tue, 20 Feb 2024 07:58:11 -0800 Subject: [PATCH 2/3] PR feedback --- .../Portable/Binder/Binder.ValueChecks.cs | 3 - .../Symbols/Source/ThisParameterSymbol.cs | 1 - .../CSharp/Portable/Symbols/TypeSymbol.cs | 4 +- .../Semantics/RefStructInterfacesTests.cs | 868 +++++++++++++++++- 4 files changed, 857 insertions(+), 19 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs index b38c652fbd547..6515c5752778c 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder.ValueChecks.cs @@ -2729,14 +2729,11 @@ private static bool AllParametersConsideredInEscapeAnalysisHaveArguments( } #endif -#nullable disable - private static ErrorCode GetStandardCallEscapeError(bool checkingReceiver) { return checkingReceiver ? ErrorCode.ERR_EscapeCall2 : ErrorCode.ERR_EscapeCall; } -#nullable enable private sealed class TypeParameterThisParameterSymbol : ThisParameterSymbolBase { private readonly TypeParameterSymbol _type; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs index 7a9b161f81639..f4cdfb242f6aa 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/ThisParameterSymbol.cs @@ -85,7 +85,6 @@ public sealed override ImmutableArray RefCustomModifiers get { return ImmutableArray.Empty; } } - // TODO: structs public sealed override bool IsThis { get { return true; } diff --git a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs index 8bc2de75b6e01..50cc1672d2bf1 100644 --- a/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/TypeSymbol.cs @@ -1970,9 +1970,11 @@ static void checkRefStructInterfacesFeatureAvailabilityOnUnscopedRefAttribute(Sy attributeData.IsTargetAttribute(AttributeDescription.UnscopedRefAttribute)) { MessageID.IDS_RefStructInterfaces.CheckFeatureAvailability(diagnostics, implementingSymbol.DeclaringCompilation, applicationSyntaxReference.GetLocation()); - break; + return; } } + + Debug.Assert(false); } } diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs index a2b4f5da3a080..ad78d61f1f706 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.CodeAnalysis.CSharp.Symbols; +using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE; using Microsoft.CodeAnalysis.CSharp.Test.Utilities; using Microsoft.CodeAnalysis.Test.Utilities; using Roslyn.Test.Utilities; @@ -12,8 +13,9 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests { public class RefStructInterfacesTests : CSharpTestBase { - [Fact] - public void UnscopedRefInInterface_Method_01() + [Theory] + [CombinatorialData] + public void UnscopedRefInInterface_Method_01(bool isVirtual) { var src = @" using System.Diagnostics.CodeAnalysis; @@ -21,12 +23,12 @@ public void UnscopedRefInInterface_Method_01() public interface I { [UnscopedRef] - ref int M(); + " + (isVirtual ? "virtual " : "") + @" ref int M()" + (isVirtual ? " => throw null" : "") + @"; } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); - CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify).VerifyDiagnostics(); + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: ExecutionConditionUtil.IsMonoOrCoreClr || !isVirtual ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); void verify(ModuleSymbol m) { @@ -124,8 +126,9 @@ public interface I Assert.False(comp.GetMember("I.M").HasUnscopedRefAttribute); } - [Fact] - public void UnscopedRefInInterface_Property_01() + [Theory] + [CombinatorialData] + public void UnscopedRefInInterface_Property_01(bool isVirtual) { var src = @" using System.Diagnostics.CodeAnalysis; @@ -133,12 +136,12 @@ public void UnscopedRefInInterface_Property_01() public interface I { [UnscopedRef] - ref int P { get; } + " + (isVirtual ? "virtual " : "") + @" ref int P { get" + (isVirtual ? " => throw null" : "") + @"; } } "; var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); - CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify).VerifyDiagnostics(); + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: ExecutionConditionUtil.IsMonoOrCoreClr || !isVirtual ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); void verify(ModuleSymbol m) { @@ -370,6 +373,255 @@ abstract static ref int P Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); } + [Theory] + [CombinatorialData] + public void UnscopedRefInInterface_Indexer_01(bool isVirtual) + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + " + (isVirtual ? "virtual " : "") + @" ref int this[int i] { get" + (isVirtual ? " => throw null" : "") + @"; } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: ExecutionConditionUtil.IsMonoOrCoreClr || !isVirtual ? Verification.Passes : Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.True(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + ); + } + + [Fact] + public void UnscopedRefInInterface_Indexer_02() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + ref int this[int i] => throw null; +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.True(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (6,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(6, 6) + ); + } + + [Fact] + public void UnscopedRefInInterface_Indexer_03() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + sealed ref int this[int i] => throw null; +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (6,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(6, 6) + ); + + PropertySymbol propertySymbol = comp.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInInterface_Indexer_04() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + [UnscopedRef] + abstract static ref int this[int i] { get; } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (7,29): error CS0106: The modifier 'static' is not valid for this item + // abstract static ref int this[int i] { get; } + Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("static").WithLocation(7, 29) + ); + + PropertySymbol propertySymbol = comp.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.IsStatic); + Assert.True(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInInterface_Indexer_05() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + ref int this[int i] + { + [UnscopedRef] + get; + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 10) + ); + } + + [Fact] + public void UnscopedRefInInterface_Indexer_06() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + ref int this[int i] + { + [UnscopedRef] + get + { + throw null; + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + CompileAndVerify(comp, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + CreateCompilation(src, targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12).VerifyDiagnostics( + // (8,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(8, 10) + ); + } + + [Fact] + public void UnscopedRefInInterface_Indexer_07() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + sealed ref int this[int i] + { + [UnscopedRef] + get + { + throw null; + } + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (8,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(8, 10) + ); + + PropertySymbol propertySymbol = comp.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + [Fact] + public void UnscopedRefInInterface_Indexer_08() + { + var src = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + abstract static ref int this[int i] + { + [UnscopedRef] + get; + } +} +"; + var comp = CreateCompilation(src, targetFramework: TargetFramework.Net80); + + comp.VerifyDiagnostics( + // (6,29): error CS0106: The modifier 'static' is not valid for this item + // abstract static ref int this[int i] + Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("static").WithLocation(6, 29) + ); + + PropertySymbol propertySymbol = comp.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.IsStatic); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.True(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + [Fact] public void UnscopedRefInImplementation_Method_01() { @@ -959,9 +1211,15 @@ class C4 : C3, I {} void verify(ModuleSymbol m) { - Assert.False(m.GlobalNamespace.GetMember("C1.P").HasUnscopedRefAttribute); - Assert.False(m.GlobalNamespace.GetMember("C2.I.P").HasUnscopedRefAttribute); - Assert.False(m.GlobalNamespace.GetMember("C3.P").HasUnscopedRefAttribute); + PropertySymbol c1P = m.GlobalNamespace.GetMember("C1.P"); + Assert.False(c1P.HasUnscopedRefAttribute); + Assert.False(c1P.GetMethod.HasUnscopedRefAttribute); + PropertySymbol c2P = m.GlobalNamespace.GetMember("C2.I.P"); + Assert.False(c2P.HasUnscopedRefAttribute); + Assert.False(c2P.GetMethod.HasUnscopedRefAttribute); + PropertySymbol c3P = m.GlobalNamespace.GetMember("C3.P"); + Assert.False(c3P.HasUnscopedRefAttribute); + Assert.False(c3P.GetMethod.HasUnscopedRefAttribute); } } } @@ -1041,7 +1299,9 @@ interface C : I void verify(ModuleSymbol m) { - Assert.False(m.GlobalNamespace.GetMember("C.I.P").HasUnscopedRefAttribute); + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C.I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); } } } @@ -1186,7 +1446,9 @@ public struct C : I void verify(ModuleSymbol m) { - Assert.False(m.GlobalNamespace.GetMember("C.P").HasUnscopedRefAttribute); + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); } } @@ -1204,7 +1466,9 @@ public struct C : I void verify(ModuleSymbol m) { - Assert.False(m.GlobalNamespace.GetMember("C.I.P").HasUnscopedRefAttribute); + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C.I.P"); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); } } @@ -1341,6 +1605,582 @@ ref int I.P } } + [Theory] + [CombinatorialData] + public void UnscopedRefInImplementation_Indexer_01(bool onInterfaceProperty, bool onInterfaceGet, bool onImplementationProperty, bool onImplementationGet) + { + if (!onInterfaceProperty && !onInterfaceGet) + { + return; + } + + var src1 = @" +using System.Diagnostics.CodeAnalysis; + +public interface I +{ + " + (onInterfaceProperty ? "[UnscopedRef]" : "") + @" + ref int this[int i] { " + (onInterfaceGet ? "[UnscopedRef] " : "") + @"get; } +} +"; + var comp1 = CreateCompilation(src1, targetFramework: TargetFramework.Net80); + + var p = comp1.GetMember("I." + WellKnownMemberNames.Indexer); + Assert.Equal(onInterfaceProperty, p.HasUnscopedRefAttribute); + Assert.Equal(onInterfaceGet, p.GetMethod.HasUnscopedRefAttribute); + + MetadataReference[] comp1Refs = [comp1.EmitToImageReference(), comp1.ToMetadataReference()]; + + if (onImplementationProperty || onImplementationGet) + { + var src2 = @" +using System.Diagnostics.CodeAnalysis; + +class C : I +{ +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + public ref int this[int i] + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + => throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp2 = CreateCompilation(src2, references: [comp1Ref], targetFramework: TargetFramework.Net80); + + if (onImplementationProperty) + { + if (onImplementationGet) + { + comp2.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6), + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + else + { + comp2.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6) + ); + } + } + else + { + comp2.VerifyDiagnostics( + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + + PropertySymbol propertySymbol = comp2.GetMember("C." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + var src3 = @" +using System.Diagnostics.CodeAnalysis; + +class C : I +{ +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + ref int I. this[int i] + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + => throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp3 = CreateCompilation(src3, references: [comp1Ref], targetFramework: TargetFramework.Net80); + if (onImplementationProperty) + { + if (onImplementationGet) + { + comp3.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6), + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + else + { + comp3.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6) + ); + } + } + else + { + comp3.VerifyDiagnostics( + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + + PropertySymbol propertySymbol = comp3.GetMember("C.I." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + + if (!onImplementationProperty && !onImplementationGet) + { + var src4 = @" +class C1 : I +{ + int f = 0; + public ref int this[int i] + { get{ + return ref f; + }} +} + +class C2 : I +{ + int f = 0; + ref int I.this[int i] + { get{ + return ref f; + }} +} + +class C3 +{ + int f = 0; + public ref int this[int i] + { get{ + return ref f; + }} +} + +class C4 : C3, I {} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp4 = CreateCompilation(src4, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp4, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol c1P = m.GlobalNamespace.GetMember("C1." + WellKnownMemberNames.Indexer); + Assert.False(c1P.HasUnscopedRefAttribute); + Assert.False(c1P.GetMethod.HasUnscopedRefAttribute); + PropertySymbol c2P = m.GlobalNamespace.GetMember("C2.I." + (m is PEModuleSymbol ? "Item" : WellKnownMemberNames.Indexer)); + Assert.False(c2P.HasUnscopedRefAttribute); + Assert.False(c2P.GetMethod.HasUnscopedRefAttribute); + PropertySymbol c3P = m.GlobalNamespace.GetMember("C3." + WellKnownMemberNames.Indexer); + Assert.False(c3P.HasUnscopedRefAttribute); + Assert.False(c3P.GetMethod.HasUnscopedRefAttribute); + } + } + } + + if (onImplementationProperty || onImplementationGet) + { + var src5 = @" +using System.Diagnostics.CodeAnalysis; + +interface C : I +{ +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + ref int I.this[int i] + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + => throw null; + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp5 = CreateCompilation(src5, references: [comp1Ref], targetFramework: TargetFramework.Net80); + if (onImplementationProperty) + { + if (onImplementationGet) + { + comp5.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6), + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + else + { + comp5.VerifyDiagnostics( + // (100,6): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(100, 6) + ); + } + } + else + { + comp5.VerifyDiagnostics( + // (200,10): error CS9101: UnscopedRefAttribute can only be applied to struct or virtual interface instance methods and properties, and cannot be applied to constructors or init-only members. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeUnsupportedMemberTarget, "UnscopedRef").WithLocation(200, 10) + ); + } + + PropertySymbol propertySymbol = comp5.GetMember("C.I." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + + if (!onImplementationProperty && !onImplementationGet) + { + var src6 = @" +interface C : I +{ + ref int I.this[int i] => throw null; +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp6 = CreateCompilation(src6, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp6, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C.I." + (m is PEModuleSymbol ? "Item" : WellKnownMemberNames.Indexer)); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + } + + if (onImplementationProperty || onImplementationGet) + { + var src7 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + public ref int this[int i] + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + { + return ref f; + } + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp7, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C." + WellKnownMemberNames.Indexer); + Assert.Equal(onImplementationProperty, propertySymbol.HasUnscopedRefAttribute); + Assert.Equal(onImplementationGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12); + if (onImplementationGet) + { + comp7.VerifyDiagnostics( + // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + ); + } + else + { + comp7.VerifyDiagnostics( + // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + ); + } + } + + var src8 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; +#line 100 + " + (onImplementationProperty ? "[UnscopedRef]" : "") + @" + ref int I.this[int i] + { +#line 200 + " + (onImplementationGet ? "[UnscopedRef] " : "") + @" + get + { + return ref f; + } + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp8, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C.I." + (m is PEModuleSymbol ? "Item" : WellKnownMemberNames.Indexer)); + Assert.Equal(onImplementationProperty, propertySymbol.HasUnscopedRefAttribute); + Assert.Equal(onImplementationGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.RegularNext).VerifyDiagnostics(); + + comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80, parseOptions: TestOptions.Regular12); + if (onImplementationProperty) + { + if (onImplementationGet) + { + comp8.VerifyDiagnostics( + // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6), + // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + ); + } + else + { + comp8.VerifyDiagnostics( + // (100,6): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(100, 6) + ); + } + } + else + { + comp8.VerifyDiagnostics( + // (200,10): error CS8652: The feature 'ref struct interfaces' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version. + // [UnscopedRef] + Diagnostic(ErrorCode.ERR_FeatureInPreview, "UnscopedRef").WithArguments("ref struct interfaces").WithLocation(200, 10) + ); + } + } + } + + if (!onImplementationProperty && !onImplementationGet) + { + var src9 = @" +public struct C : I +{ + public ref int this[int i] => throw null; +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp9 = CreateCompilation(src9, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp9, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C." + WellKnownMemberNames.Indexer); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + + var src10 = @" +public struct C : I +{ + ref int I.this[int i] => throw null; +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp10 = CreateCompilation(src10, references: [comp1Ref], targetFramework: TargetFramework.Net80); + CompileAndVerify(comp10, sourceSymbolValidator: verify, symbolValidator: verify, verify: Verification.Skipped).VerifyDiagnostics(); + + void verify(ModuleSymbol m) + { + PropertySymbol propertySymbol = m.GlobalNamespace.GetMember("C.I." + (m is PEModuleSymbol ? "Item" : WellKnownMemberNames.Indexer)); + Assert.False(propertySymbol.HasUnscopedRefAttribute); + Assert.False(propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + + var src11 = @" +public struct C : I +{ + public int f; + + public ref int this[int i] + { get{ + return ref f; + }} +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp11 = CreateCompilation(src11, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp11.VerifyDiagnostics( + // (8,20): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref f; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "f").WithLocation(8, 20) + ); + } + + var src12 = @" +public struct C : I +{ + public int f; + + ref int I.this[int i] + { get{ + return ref f; + }} +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp12 = CreateCompilation(src12, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp12.VerifyDiagnostics( + // (8,20): error CS8170: Struct members cannot return 'this' or other instance members by reference + // return ref f; + Diagnostic(ErrorCode.ERR_RefReturnStructThis, "f").WithLocation(8, 20) + ); + } + } + } + + [Theory] + [CombinatorialData] + public void UnscopedRefInImplementation_Indexer_02(bool onProperty, bool onGet) + { + if (!onProperty && !onGet) + { + return; + } + + var src1 = @" +public interface I +{ + ref int this[int i] { get; } +} +"; + var comp1 = CreateCompilation(src1, targetFramework: TargetFramework.Net80); + MetadataReference[] comp1Refs = [comp1.EmitToImageReference(), comp1.ToMetadataReference()]; + + var src7 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + + " + (onProperty ? "[UnscopedRef]" : "") + @" + public ref int this[int i] + { +#line 200 + " + (onGet ? "[UnscopedRef] " : "") + @" + get + { + return ref f; + } + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp7 = CreateCompilation(src7, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp7.VerifyDiagnostics( + // (201,9): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.P.get' doesn't have this attribute. + // get + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I.this[int].get").WithLocation(201, 9) + ); + + PropertySymbol propertySymbol = comp7.GetMember("C." + WellKnownMemberNames.Indexer); + Assert.Equal(onProperty, propertySymbol.HasUnscopedRefAttribute); + Assert.Equal(onGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + + var src8 = @" +using System.Diagnostics.CodeAnalysis; + +public struct C : I +{ + public int f; + + " + (onProperty ? "[UnscopedRef]" : "") + @" + ref int I.this[int i] + { +#line 200 + " + (onGet ? "[UnscopedRef] " : "") + @" + get + { + return ref f; + } + } +} +"; + + foreach (var comp1Ref in comp1Refs) + { + var comp8 = CreateCompilation(src8, references: [comp1Ref], targetFramework: TargetFramework.Net80); + comp8.VerifyDiagnostics( + // (201,9): error CS9102: UnscopedRefAttribute cannot be applied to an interface implementation because implemented member 'I.P.get' doesn't have this attribute. + // get + Diagnostic(ErrorCode.ERR_UnscopedRefAttributeInterfaceImplementation, "get").WithArguments("I.this[int].get").WithLocation(201, 9) + ); + + PropertySymbol propertySymbol = comp8.GetMember("C.I." + WellKnownMemberNames.Indexer); + Assert.Equal(onProperty, propertySymbol.HasUnscopedRefAttribute); + Assert.Equal(onGet, propertySymbol.GetMethod.HasUnscopedRefAttribute); + } + } + // This is a clone of MethodArgumentsMustMatch_16 from RefFieldTests.cs [Fact] public void MethodArgumentsMustMatch_16_DirectInterface() From e3b87b8bda3625ccc24435eb7ffe0f721996bfb7 Mon Sep 17 00:00:00 2001 From: AlekseyTs Date: Thu, 22 Feb 2024 10:21:37 -0800 Subject: [PATCH 3/3] Adjust tests --- .../Semantics/RefStructInterfacesTests.cs | 115 ++++++++++++++++-- 1 file changed, 106 insertions(+), 9 deletions(-) diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs index ad78d61f1f706..e882e45cf91b5 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/RefStructInterfacesTests.cs @@ -2762,7 +2762,7 @@ static RefByteContainer M42(scoped ref ByteContainer bc) // This is a clone of UnscopedRef_ArgumentsMustMatch_01 from RefFieldTests.cs [Theory] [CombinatorialData] - public void UnscopedRef_ArgumentsMustMatch_0_ConstrainedTypeParameter(bool addStructConstraint) + public void UnscopedRef_ArgumentsMustMatch_01_ConstrainedTypeParameter(bool addStructConstraint) { var source = $$""" using System.Diagnostics.CodeAnalysis; @@ -2849,7 +2849,7 @@ static RefByteContainer M42(scoped ref TByteContainer bc) // This is a clone of UnscopedRef_ArgumentsMustMatch_01 from RefFieldTests.cs [Fact] - public void UnscopedRef_ArgumentsMustMatch_0_ClassConstrainedTypeParameter() + public void UnscopedRef_ArgumentsMustMatch_01_ClassConstrainedTypeParameter() { var source = """ using System.Diagnostics.CodeAnalysis; @@ -2921,7 +2921,7 @@ static RefByteContainer M42(scoped ref TByteContainer bc) comp.VerifyDiagnostics(); } - // PROTOTYPE(RefStructInterfaces): Add flavor of UnscopedRef_ArgumentsMustMatch_0 tests with RefByteContainer as an interface + // PROTOTYPE(RefStructInterfaces): Add flavor of UnscopedRef_ArgumentsMustMatch_01 tests with RefByteContainer as an interface // This is a clone of PatternIndex_01 from RefFieldTests.cs [Fact] @@ -3379,7 +3379,7 @@ public interface Vec4 where TVec4 : Vec4 // This is a clone of DefensiveCopy_02 from RefEscapingTests.cs [Fact] - public void DefensiveCopy_02() + public void DefensiveCopy_02_DirectInterface() { var source = @"using System.Diagnostics.CodeAnalysis; @@ -3413,15 +3413,63 @@ static ref Wrap m4(in Wrap i) } } -struct Wrap +interface Wrap { - public float X; + [UnscopedRef] + public ref Wrap Self {get;} + + [UnscopedRef] + public ref Wrap Self2(); +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + + // This is a clone of DefensiveCopy_02 from RefEscapingTests.cs + [Theory] + [CombinatorialData] + public void DefensiveCopy_02_ConstrainedTypeParameter(bool addStructConstraint) + { + var source = +@"using System.Diagnostics.CodeAnalysis; + +class Program where TWrap : " + (addStructConstraint ? "struct, " : "") + @"Wrap +{ + static ref TWrap m1(in TWrap i) + { + ref TWrap r1 = ref i.Self; // defensive copy + return ref r1; // ref to the local copy + } + + static ref TWrap m2(in TWrap i) + { + var copy = i; + ref TWrap r2 = ref copy.Self; + return ref r2; // ref to the local copy + } + + static ref TWrap m3(in TWrap i) + { + ref TWrap r3 = ref i.Self2(); + return ref r3; + } + static ref TWrap m4(in TWrap i) + { + var copy = i; + ref TWrap r4 = ref copy.Self2(); + return ref r4; // ref to the local copy + } +} + +interface Wrap where T : Wrap +{ [UnscopedRef] - public ref Wrap Self => ref this; + public ref T Self {get;} [UnscopedRef] - public ref Wrap Self2() => ref this; + public ref T Self2(); } "; var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); @@ -3441,6 +3489,55 @@ struct Wrap ); } + // This is a clone of DefensiveCopy_02 from RefEscapingTests.cs + [Fact] + public void DefensiveCopy_02_ClassConstrainedTypeParameter() + { + var source = +@"using System.Diagnostics.CodeAnalysis; + +class Program where TWrap : class, Wrap +{ + static ref TWrap m1(in TWrap i) + { + ref TWrap r1 = ref i.Self; // defensive copy + return ref r1; // ref to the local copy + } + + static ref TWrap m2(in TWrap i) + { + var copy = i; + ref TWrap r2 = ref copy.Self; + return ref r2; // ref to the local copy + } + + static ref TWrap m3(in TWrap i) + { + ref TWrap r3 = ref i.Self2(); + return ref r3; + } + + static ref TWrap m4(in TWrap i) + { + var copy = i; + ref TWrap r4 = ref copy.Self2(); + return ref r4; // ref to the local copy + } +} + +interface Wrap where T : Wrap +{ + [UnscopedRef] + public ref T Self {get;} + + [UnscopedRef] + public ref T Self2(); +} +"; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net70); + comp.VerifyEmitDiagnostics(); + } + // This is a clone of DefensiveCopy_05 from RefEscapingTests.cs [Fact] public void DefensiveCopy_05_DirectInterface() @@ -3535,7 +3632,7 @@ public Span Self // This is a clone of DefensiveCopy_05 from RefEscapingTests.cs [Fact] - public void DefensiveCopy_05_ClassdConstrainedTypeParameter() + public void DefensiveCopy_05_ClassConstrainedTypeParameter() { var source = @"