diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
index e8ce99e6c877f..79d4b61d2aebb 100644
--- a/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
+++ b/src/Compilers/CSharp/Portable/Binder/Binder_Invocation.cs
@@ -1153,7 +1153,7 @@ ContainingMemberOrLambda is MethodSymbol containingMethod &&
!method.IsEffectivelyReadOnly &&
!method.IsStatic)
{
- Error(diagnostics, ErrorCode.WRN_ImplicitCopyInReadOnlyMember, receiver.Syntax, method.Name, ThisParameterSymbol.SymbolName);
+ Error(diagnostics, ErrorCode.WRN_ImplicitCopyInReadOnlyMember, receiver.Syntax, method, ThisParameterSymbol.SymbolName);
return false;
}
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
index 7e433b68eebd9..4cd42183324de 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
+++ b/src/Compilers/CSharp/Portable/CSharpResources.Designer.cs
@@ -8763,6 +8763,15 @@ internal static string ERR_RbraceExpected {
}
}
+ ///
+ /// Looks up a localized string similar to '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor.
+ ///
+ internal static string ERR_ReadOnlyModMissingAccessor {
+ get {
+ return ResourceManager.GetString("ERR_ReadOnlyModMissingAccessor", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Members of readonly field '{0}' of type '{1}' cannot be assigned with an object initializer because it is of a value type.
///
@@ -9664,7 +9673,7 @@ internal static string ERR_StaticLocalFunctionCannotCaptureVariable {
}
///
- /// Looks up a localized string similar to Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter..
+ /// Looks up a localized string similar to Static member '{0}' cannot be marked 'readonly'..
///
internal static string ERR_StaticMemberCantBeReadOnly {
get {
diff --git a/src/Compilers/CSharp/Portable/CSharpResources.resx b/src/Compilers/CSharp/Portable/CSharpResources.resx
index ac50b96df76a7..a54ea8a393563 100644
--- a/src/Compilers/CSharp/Portable/CSharpResources.resx
+++ b/src/Compilers/CSharp/Portable/CSharpResources.resx
@@ -5431,7 +5431,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Call to non-readonly member from a 'readonly' member results in an implicit copy.
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ Static member '{0}' cannot be marked 'readonly'.Auto-implemented 'set' accessor '{0}' cannot be marked 'readonly'.
@@ -5451,6 +5451,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
Both partial method declarations must be readonly or neither may be readonly
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types.
diff --git a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
index d3109183f418c..5ca4b45bb68cd 100644
--- a/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
+++ b/src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
@@ -1691,6 +1691,7 @@ internal enum ErrorCode
ERR_DuplicatePropertyReadOnlyMods = 8660,
ERR_FieldLikeEventCantBeReadOnly = 8661,
ERR_PartialMethodReadOnlyDifference = 8662,
+ ERR_ReadOnlyModMissingAccessor = 8663
#endregion diagnostics introduced for C# 8.0
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs
index 934d1bedb3d98..3b3132eabbfef 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceEventSymbol.cs
@@ -480,7 +480,7 @@ protected void CheckModifiersAndType(DiagnosticBag diagnostics)
}
else if (IsReadOnly && IsStatic)
{
- // Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // Static member '{0}' cannot be marked 'readonly'.
diagnostics.Add(ErrorCode.ERR_StaticMemberCantBeReadOnly, location, this);
}
else if (IsReadOnly && HasAssociatedField)
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs
index 976e84b621717..866dc30581168 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceOrdinaryMethodSymbol.cs
@@ -940,7 +940,7 @@ private void CheckModifiers(bool hasBody, Location location, DiagnosticBag diagn
}
else if (IsStatic && IsDeclaredReadOnly)
{
- // Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // Static member '{0}' cannot be marked 'readonly'.
diagnostics.Add(ErrorCode.ERR_StaticMemberCantBeReadOnly, location, this);
}
else if (IsAbstract && !ContainingType.IsAbstract && (ContainingType.TypeKind == TypeKind.Class || ContainingType.TypeKind == TypeKind.Submission))
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
index 3621187ba38a7..1a38b3d4e3bbc 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertyAccessorSymbol.cs
@@ -477,7 +477,7 @@ private void CheckModifiers(Location location, bool hasBody, bool isAutoProperty
}
else if (LocalDeclaredReadOnly && IsStatic)
{
- // Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // Static member '{0}' cannot be marked 'readonly'.
diagnostics.Add(ErrorCode.ERR_StaticMemberCantBeReadOnly, location, this);
}
else if (LocalDeclaredReadOnly && _isAutoPropertyAccessor && MethodKind == MethodKind.PropertySet)
diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
index f987626ce4a37..d8625339963f2 100644
--- a/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
+++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourcePropertySymbol.cs
@@ -385,6 +385,12 @@ private SourcePropertySymbol(
{
diagnostics.Add(ErrorCode.ERR_AccessModMissingAccessor, location, this);
}
+
+ // Check that 'readonly' is not set on the one accessor.
+ if (accessor.LocalDeclaredReadOnly)
+ {
+ diagnostics.Add(ErrorCode.ERR_ReadOnlyModMissingAccessor, location, this);
+ }
}
}
}
@@ -910,7 +916,7 @@ private void CheckModifiers(Location location, bool isIndexer, DiagnosticBag dia
}
else if (IsStatic && HasReadOnlyModifier)
{
- // Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // Static member '{0}' cannot be marked 'readonly'.
diagnostics.Add(ErrorCode.ERR_StaticMemberCantBeReadOnly, location, this);
}
else if (IsOverride && (IsNew || IsVirtual))
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
index cb1182d4ebfb4..9f7986ccf71fa 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf
@@ -292,6 +292,11 @@
Dílčí vzor vlastnosti vyžaduje odkaz na vlastnost nebo pole k přiřazení, např. „{{ Name: {0} }}“.
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ Přiřazení odkazu {1} k {0} nelze provést, protože {1} má užší řídicí obor než {0}.
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
index 83706da6278ab..02acca338acc9 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf
@@ -292,6 +292,11 @@
Ein Eigenschaftsteilmuster erfordert einen Verweis auf die abzugleichende Eigenschaft oder das abzugleichende Feld. Beispiel: "{{ Name: {0} }}"
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ ref-assign von "{1}" zu "{0}" ist nicht möglich, weil "{1}" einen geringeren Escapebereich als "{0}" aufweist.
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
index 4b7f83794f0fe..7c72c53406526 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf
@@ -292,6 +292,11 @@
El subpatrón de una propiedad requiere una referencia a la propiedad o al campo que debe coincidir; por ejemplo, "{{ Name: {0} }}"
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ No se puede asignar referencia "{1}" a "{0}" porque "{1}" tiene un ámbito de escape más limitado que "{0}".
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
index a32054f842dfb..8758aba111443 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf
@@ -292,6 +292,11 @@
Un sous-modèle de propriété nécessite une correspondance de la référence à la propriété ou au champ. Exemple : '{{ Nom: {0} }}'
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ Impossible d'effectuer une assignation par référence de '{1}' vers '{0}', car '{1}' a une portée de sortie plus limitée que '{0}'.
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
index d5b069e99d2a0..d999b15dec79c 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf
@@ -292,6 +292,11 @@
Con un criterio secondario di proprietà è richiesto un riferimento alla proprietà o al campo da abbinare, ad esempio '{{ Name: {0} }}'
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ Non è possibile assegnare '{1}' a '{0}' come ref perché l'ambito di escape di '{1}' è ridotto rispetto a quello di '{0}'.
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
index 424d0f5001507..c68c4ddb2e125 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf
@@ -292,6 +292,11 @@
プロパティ サブパターンには、一致させるプロパティまたはフィールドへの参照が必要です。例: '{{ Name: {0} }}'
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ '{1}' を '{0}' に ref 割り当てすることはできません。'{1}' のエスケープ スコープが '{0}' より狭いためです。
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
index ff030dc9dc548..4dba4aef41bed 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ko.xlf
@@ -292,6 +292,11 @@
속성 하위 패턴은 일치시킬 속성 또는 필드에 대한 참조가 필요합니다(예: '{{ Name: {0} }}')
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ '{1}'을(를) '{0}'에 참조 할당할 수 없습니다. '{1}'이(가) '{0}'보다 이스케이프 범위가 좁기 때문입니다.
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
index bd7cbdef1ecb9..6813b048708d9 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pl.xlf
@@ -292,6 +292,11 @@
Wzorzec podrzędny właściwości wymaga odwołania do właściwości lub pola, które należy dopasować, na przykład „{{ Name: {0} }}”
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ Nie można przypisać odwołania elementu „{1}” do elementu „{0}”, ponieważ element „{1}” ma węższy zakres wyjścia niż element „{0}”.
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
index 410f65360beac..cdbd4d1900c31 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.pt-BR.xlf
@@ -292,6 +292,11 @@
Um subpadrão de propriedade requer que uma referência à propriedade ou ao campo seja correspondida, por exemplo, '{{ Name: {0} }}'
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ Não é possível atribuir ref '{1}' a '{0}' porque '{1}' tem um escopo de escape mais limitado que '{0}'.
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
index 257ce817a2bd5..7765d62f1af5b 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.ru.xlf
@@ -292,6 +292,11 @@
Для вложенного шаблона свойств требуется ссылка на свойство или поле для сопоставления, например, "{{ Name: {0} }}".
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ Не удается присвоить по ссылке "{1}" для "{0}", так как escape-область у "{1}" уже, чем у "{0}".
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
index 53b887fc7cb13..28c76f64fbc7f 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.tr.xlf
@@ -292,6 +292,11 @@
Bir özellik alt deseni, özellik veya alan başvurusunun eşleşmesini gerektiriyor, ör. '{{ Name: {0} }}'
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ '{1}', '{0}' öğesinden daha dar bir kaçış kapsamı içerdiğinden '{0}' öğesine '{1}' ref ataması yapılamıyor.
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
index 31f73e9e4e18d..af9281203bead 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hans.xlf
@@ -292,6 +292,11 @@
属性子模式需要引用要匹配的属性或字段,例如,"{{ Name: {0} }}"
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ 无法将“{1}”重新赋值为“{0}”,因为“{1}”具有比“{0}”更窄的转义范围。
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
index 593efd8bf8b3f..543c440fddacd 100644
--- a/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
+++ b/src/Compilers/CSharp/Portable/xlf/CSharpResources.zh-Hant.xlf
@@ -292,6 +292,11 @@
屬性子模式需要對屬性或欄位的參考才能比對,例如 '{{ Name: {0} }}'
+
+
+ '{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+
+ 不能將 '{1}' 參考指派至 '{0}',因為 '{1}' 的逸出範圍比 '{0}' 還要窄。
@@ -318,8 +323,8 @@
-
- Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+
+ Static member '{0}' cannot be marked 'readonly'.
diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadonlyStructTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadonlyStructTests.cs
index b9238f6dd9356..ac974bdb566ba 100644
--- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadonlyStructTests.cs
+++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenReadonlyStructTests.cs
@@ -1319,8 +1319,8 @@ public readonly void M2() {}
public int P1 { get; set; }
public readonly int P2 => 42;
- public int P3 { readonly get => 123; }
- public int P4 { readonly set {} }
+ public int P3 { readonly get => 123; set {} }
+ public int P4 { get => 123; readonly set {} }
public static int P5 { get; set; }
}
";
@@ -1358,8 +1358,12 @@ void validate(ModuleSymbol module)
Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEPropertySymbol)p3).Handle));
Assert.True(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p3.GetMethod).Handle));
Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p3.GetMethod).Signature.ReturnParam.Handle));
+ Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p3.SetMethod).Handle));
+ Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p3.SetMethod).Signature.ReturnParam.Handle));
Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEPropertySymbol)p4).Handle));
+ Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p4.GetMethod).Handle));
+ Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p4.GetMethod).Signature.ReturnParam.Handle));
Assert.True(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p4.SetMethod).Handle));
Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p4.SetMethod).Signature.ReturnParam.Handle));
@@ -1453,8 +1457,8 @@ public readonly void M2() {}
public int P1 { get; }
public readonly int P2 => 42;
- public int P3 { readonly get => 123; }
- public int P4 { readonly set {} }
+ public int P3 { readonly get => 123; set {} }
+ public int P4 { get => 123; readonly set {} }
public static int P5 { get; set; }
}
";
@@ -1490,8 +1494,12 @@ void validate(ModuleSymbol module)
Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEPropertySymbol)p3).Handle));
Assert.True(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p3.GetMethod).Handle));
Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p3.GetMethod).Signature.ReturnParam.Handle));
+ Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p3.SetMethod).Handle));
+ Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p3.SetMethod).Signature.ReturnParam.Handle));
Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEPropertySymbol)p4).Handle));
+ Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p4.GetMethod).Handle));
+ Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p4.GetMethod).Signature.ReturnParam.Handle));
Assert.True(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p4.SetMethod).Handle));
Assert.False(peModule.Module.HasIsReadOnlyAttribute(((PEMethodSymbol)p4.SetMethod).Signature.ReturnParam.Handle));
@@ -1518,8 +1526,8 @@ public readonly void M2() {}
public int P1 { get; set; }
public readonly int P2 => 42;
- public int P3 { readonly get => 123; }
- public int P4 { readonly set {} }
+ public int P3 { readonly get => 123; set {} }
+ public int P4 { get => 123; readonly set {} }
public static int P5 { get; set; }
public readonly event Action E { add {} remove {} }
}
@@ -1535,6 +1543,7 @@ public event Action E { add {} remove {} }
}
";
var externalComp = CreateCompilation(external);
+ externalComp.VerifyDiagnostics();
verify(externalComp);
var comp = CreateCompilation("", references: new[] { externalComp.EmitToImageReference() });
@@ -1554,7 +1563,11 @@ void verify(CSharpCompilation comp)
verifyReadOnly(s1.GetProperty("P1").SetMethod, false, false, RefKind.Ref);
verifyReadOnly(s1.GetProperty("P2").GetMethod, true, true, RefKind.RefReadOnly);
+
verifyReadOnly(s1.GetProperty("P3").GetMethod, true, true, RefKind.RefReadOnly);
+ verifyReadOnly(s1.GetProperty("P3").SetMethod, false, false, RefKind.Ref);
+
+ verifyReadOnly(s1.GetProperty("P4").GetMethod, false, false, RefKind.Ref);
verifyReadOnly(s1.GetProperty("P4").SetMethod, true, true, RefKind.RefReadOnly);
verifyReadOnly(s1.GetProperty("P5").GetMethod, false, false, null);
@@ -1696,9 +1709,9 @@ static void Main()
var verifier = CompileAndVerify(csharp, expectedOutput: "123");
verifier.VerifyDiagnostics(
- // (9,9): warning CS8655: Call to non-readonly member 'M2' from a 'readonly' member results in an implicit copy of 'this'.
+ // (9,9): warning CS8655: Call to non-readonly member 'S.M2()' from a 'readonly' member results in an implicit copy of 'this'.
// M2();
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "M2").WithArguments("M2", "this").WithLocation(9, 9));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "M2").WithArguments("S.M2()", "this").WithLocation(9, 9));
verifier.VerifyIL("S.M1", @"
{
@@ -2195,15 +2208,15 @@ readonly void M()
var verifier = CompileAndVerify(csharp);
verifier.VerifyDiagnostics(
- // (12,9): warning CS8655: Call to non-readonly member 'ToString' from a 'readonly' member results in an implicit copy of 'this'.
+ // (12,9): warning CS8655: Call to non-readonly member 'S.ToString()' from a 'readonly' member results in an implicit copy of 'this'.
// ToString();
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "ToString").WithArguments("ToString", "this").WithLocation(12, 9),
- // (13,9): warning CS8655: Call to non-readonly member 'GetHashCode' from a 'readonly' member results in an implicit copy of 'this'.
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "ToString").WithArguments("S.ToString()", "this").WithLocation(12, 9),
+ // (13,9): warning CS8655: Call to non-readonly member 'S.GetHashCode()' from a 'readonly' member results in an implicit copy of 'this'.
// GetHashCode();
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "GetHashCode").WithArguments("GetHashCode", "this").WithLocation(13, 9),
- // (14,9): warning CS8655: Call to non-readonly member 'Equals' from a 'readonly' member results in an implicit copy of 'this'.
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "GetHashCode").WithArguments("S.GetHashCode()", "this").WithLocation(13, 9),
+ // (14,9): warning CS8655: Call to non-readonly member 'S.Equals(object)' from a 'readonly' member results in an implicit copy of 'this'.
// Equals(null);
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "Equals").WithArguments("Equals", "this").WithLocation(14, 9));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "Equals").WithArguments("S.Equals(object)", "this").WithLocation(14, 9));
// Verify that calls to non-readonly overrides pass the address of a temp, not the address of 'this'
verifier.VerifyIL("S.M", @"
@@ -2348,18 +2361,18 @@ readonly void M()
var verifier = CompileAndVerify(csharp);
verifier.VerifyDiagnostics(
- // (12,9): warning CS8655: Call to non-readonly member 'GetType' from a 'readonly' member results in an implicit copy of 'this'.
+ // (12,9): warning CS8655: Call to non-readonly member 'S.GetType()' from a 'readonly' member results in an implicit copy of 'this'.
// GetType();
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "GetType").WithArguments("GetType", "this").WithLocation(12, 9),
- // (13,9): warning CS8655: Call to non-readonly member 'ToString' from a 'readonly' member results in an implicit copy of 'this'.
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "GetType").WithArguments("S.GetType()", "this").WithLocation(12, 9),
+ // (13,9): warning CS8655: Call to non-readonly member 'S.ToString()' from a 'readonly' member results in an implicit copy of 'this'.
// ToString();
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "ToString").WithArguments("ToString", "this").WithLocation(13, 9),
- // (14,9): warning CS8655: Call to non-readonly member 'GetHashCode' from a 'readonly' member results in an implicit copy of 'this'.
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "ToString").WithArguments("S.ToString()", "this").WithLocation(13, 9),
+ // (14,9): warning CS8655: Call to non-readonly member 'S.GetHashCode()' from a 'readonly' member results in an implicit copy of 'this'.
// GetHashCode();
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "GetHashCode").WithArguments("GetHashCode", "this").WithLocation(14, 9),
- // (15,9): warning CS8655: Call to non-readonly member 'Equals' from a 'readonly' member results in an implicit copy of 'this'.
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "GetHashCode").WithArguments("S.GetHashCode()", "this").WithLocation(14, 9),
+ // (15,9): warning CS8655: Call to non-readonly member 'S.Equals(object)' from a 'readonly' member results in an implicit copy of 'this'.
// Equals(null);
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "Equals").WithArguments("Equals", "this").WithLocation(15, 9));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "Equals").WithArguments("S.Equals(object)", "this").WithLocation(15, 9));
// Verify that calls to new non-readonly members pass an address to a temp and that calls to base members use a box.
verifier.VerifyIL("S.M", @"
diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs
index 6962bec7c028c..6c1c461694ec6 100644
--- a/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs
+++ b/src/Compilers/CSharp/Test/Semantic/Semantics/ReadOnlyStructsTests.cs
@@ -508,9 +508,9 @@ readonly void M2()
";
var comp = CreateCompilation(csharp, options: TestOptions.UnsafeReleaseDll);
comp.VerifyDiagnostics(
- // (12,25): warning CS8655: Call to non-readonly member 'GetPinnableReference' from a 'readonly' member results in an implicit copy of 'this'.
+ // (12,25): warning CS8655: Call to non-readonly member 'S1.GetPinnableReference()' from a 'readonly' member results in an implicit copy of 'this'.
// fixed (int *i = this) {} // warn
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("GetPinnableReference", "this").WithLocation(12, 25));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("S1.GetPinnableReference()", "this").WithLocation(12, 25));
}
[Fact]
@@ -582,9 +582,9 @@ public struct S
{
public int i;
- public int P
+ public readonly int P
{
- readonly get
+ get
{
// should create local copy
M();
@@ -614,9 +614,9 @@ static void Main()
var verifier = CompileAndVerify(csharp, expectedOutput: "123");
verifier.VerifyDiagnostics(
- // (11,13): warning CS8655: Call to non-readonly member 'M' from a 'readonly' member results in an implicit copy of 'this'.
+ // (11,13): warning CS8655: Call to non-readonly member 'S.M()' from a 'readonly' member results in an implicit copy of 'this'.
// M();
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "M").WithArguments("M", "this").WithLocation(11, 13));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "M").WithArguments("S.M()", "this").WithLocation(11, 13));
}
[Fact]
@@ -627,9 +627,9 @@ public struct S
{
public int i;
- public int P1
+ public readonly int P1
{
- readonly get
+ get
{
// should create local copy
_ = P2; // warning
@@ -656,9 +656,9 @@ static void Main()
var verifier = CompileAndVerify(csharp, expectedOutput: "123");
verifier.VerifyDiagnostics(
- // (11,17): warning CS8655: Call to non-readonly member 'get_P2' from a 'readonly' member results in an implicit copy of 'this'.
- // _ = P2;
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "P2").WithArguments("get_P2", "this").WithLocation(11, 17));
+ // (11,17): warning CS8655: Call to non-readonly member 'S.P2.get' from a 'readonly' member results in an implicit copy of 'this'.
+ // _ = P2; // warning
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "P2").WithArguments("S.P2.get", "this").WithLocation(11, 17));
}
[Fact]
@@ -1123,7 +1123,7 @@ public static readonly int M()
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (5,32): error CS8656: Static member 'S.M()' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // (5,32): error CS8656: Static member 'S.M()' cannot be marked 'readonly'.
// public static readonly int M()
Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "M").WithArguments("S.M()").WithLocation(5, 32));
@@ -1139,9 +1139,9 @@ public void ReadOnlyStructProperty()
public struct S
{
public int i;
- public int P
+ public readonly int P
{
- readonly get
+ get
{
return i;
}
@@ -1165,12 +1165,16 @@ readonly get
{
return i;
}
+ set
+ {
+ i = value;
+ }
}
}
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (7,18): error CS8656: Static member 'S.P.get' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // (7,18): error CS8656: Static member 'S.P.get' cannot be marked 'readonly'.
// readonly get
Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.P.get").WithLocation(7, 18));
}
@@ -1187,7 +1191,7 @@ public struct S
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (5,32): error CS8656: Static member 'S.P' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // (5,32): error CS8656: Static member 'S.P' cannot be marked 'readonly'.
// public static readonly int P => i;
Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "P").WithArguments("S.P").WithLocation(5, 32));
}
@@ -1238,6 +1242,9 @@ public struct S
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
+ // (4,16): error CS8663: 'S.P1': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+ // public int P1 { readonly get; }
+ Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P1").WithArguments("S.P1").WithLocation(4, 16),
// (7,16): error CS8660: Cannot specify 'readonly' modifiers on both accessors of property or indexer 'S.P4'. Instead, put a 'readonly' modifier on the property itself.
// public int P4 { readonly get; readonly set; }
Diagnostic(ErrorCode.ERR_DuplicatePropertyReadOnlyMods, "P4").WithArguments("S.P4").WithLocation(7, 16),
@@ -1247,6 +1254,9 @@ public struct S
// (8,25): error CS8658: Auto-implemented property 'S.P5' cannot be marked 'readonly' because it has a 'set' accessor.
// public readonly int P5 { get; set; }
Diagnostic(ErrorCode.ERR_AutoPropertyWithSetterCantBeReadOnly, "P5").WithArguments("S.P5").WithLocation(8, 25),
+ // (9,25): error CS8663: 'S.P6': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+ // public readonly int P6 { readonly get; }
+ Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "P6").WithArguments("S.P6").WithLocation(9, 25),
// (9,39): error CS8659: Cannot specify 'readonly' modifiers on both property or indexer 'S.P6' and its accessor. Remove one of them.
// public readonly int P6 { readonly get; }
Diagnostic(ErrorCode.ERR_InvalidPropertyReadOnlyMods, "get").WithArguments("S.P6").WithLocation(9, 39),
@@ -1267,7 +1277,7 @@ public void ReadOnlyProperty_RedundantReadOnlyAccessor()
var csharp = @"
public struct S
{
- public readonly int P { readonly get => 42; }
+ public readonly int P { readonly get => 42; set {} }
}
";
var comp = CreateCompilation(csharp);
@@ -1284,15 +1294,15 @@ public void ReadOnlyStaticAutoProperty()
public struct S
{
public static readonly int P1 { get; set; }
- public static int P2 { readonly get; }
+ public static int P2 { readonly get; set; }
}
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (4,32): error CS8656: Static member 'S.P1' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // (4,32): error CS8656: Static member 'S.P1' cannot be marked 'readonly'.
// public static readonly int P1 { get; set; }
Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "P1").WithArguments("S.P1").WithLocation(4, 32),
- // (5,37): error CS8656: Static member 'S.P2.get' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // (5,37): error CS8656: Static member 'S.P2.get' cannot be marked 'readonly'.
// public static int P2 { readonly get; }
Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "get").WithArguments("S.P2.get").WithLocation(5, 37));
}
@@ -1406,9 +1416,9 @@ readonly void M2()
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (13,27): warning CS8655: Call to non-readonly member 'GetEnumerator' from a 'readonly' member results in an implicit copy of 'this'.
+ // (13,27): warning CS8655: Call to non-readonly member 'S1.GetEnumerator()' from a 'readonly' member results in an implicit copy of 'this'.
// foreach (var x in this) {} // warning-- implicit copy
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("GetEnumerator", "this").WithLocation(13, 27));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("S1.GetEnumerator()", "this").WithLocation(13, 27));
}
[Fact]
@@ -1469,9 +1479,9 @@ public readonly async Task M2()
";
var comp = CreateCompilationWithTasksExtensions(new[] { csharp, AsyncStreamsTypes });
comp.VerifyDiagnostics(
- // (16,33): warning CS8655: Call to non-readonly member 'GetAsyncEnumerator' from a 'readonly' member results in an implicit copy of 'this'.
+ // (16,33): warning CS8655: Call to non-readonly member 'S1.GetAsyncEnumerator()' from a 'readonly' member results in an implicit copy of 'this'.
// await foreach (var x in this) {} // warn
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("GetAsyncEnumerator", "this").WithLocation(16, 33));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("S1.GetAsyncEnumerator()", "this").WithLocation(16, 33));
}
[Fact]
@@ -1513,9 +1523,9 @@ readonly void M2()
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (13,16): warning CS8655: Call to non-readonly member 'Dispose' from a 'readonly' member results in an implicit copy of 'this'.
+ // (13,16): warning CS8655: Call to non-readonly member 'S1.Dispose()' from a 'readonly' member results in an implicit copy of 'this'.
// using (this) { } // should warn
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("Dispose", "this").WithLocation(13, 16));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("S1.Dispose()", "this").WithLocation(13, 16));
}
[Fact]
@@ -1562,9 +1572,9 @@ public readonly void Deconstruct(out int x, out int y)
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (11,22): warning CS8655: Call to non-readonly member 'Deconstruct' from a 'readonly' member results in an implicit copy of 'this'.
+ // (11,22): warning CS8655: Call to non-readonly member 'S1.Deconstruct(out int, out int)' from a 'readonly' member results in an implicit copy of 'this'.
// var (x, y) = this; // should warn
- Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("Deconstruct", "this").WithLocation(11, 22));
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "this").WithArguments("S1.Deconstruct(out int, out int)", "this").WithLocation(11, 22));
}
[Fact]
@@ -1758,13 +1768,23 @@ readonly set {}
public struct S4
{
// error
- public readonly int this[int i]
+ public int this[int i]
{
readonly get { return i; }
}
}
public struct S5
+{
+ // error
+ public readonly int this[int i]
+ {
+ readonly get { return i; }
+ set { }
+ }
+}
+
+public struct S6
{
// error
public static readonly int this[int i] => i;
@@ -1775,12 +1795,15 @@ public struct S5
// (21,16): error CS8660: Cannot specify 'readonly' modifiers on both accessors of property or indexer 'S3.this[int]'. Instead, put a 'readonly' modifier on the property itself.
// public int this[int i]
Diagnostic(ErrorCode.ERR_DuplicatePropertyReadOnlyMods, "this").WithArguments("S3.this[int]").WithLocation(21, 16),
- // (33,18): error CS8659: Cannot specify 'readonly' modifiers on both property or indexer 'S4.this[int]' and its accessor. Remove one of them.
+ // (31,16): error CS8663: 'S4.this[int]': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor
+ // public int this[int i]
+ Diagnostic(ErrorCode.ERR_ReadOnlyModMissingAccessor, "this").WithArguments("S4.this[int]").WithLocation(31, 16),
+ // (42,18): error CS8659: Cannot specify 'readonly' modifiers on both property or indexer 'S5.this[int]' and its accessor. Remove one of them.
// readonly get { return i; }
- Diagnostic(ErrorCode.ERR_InvalidPropertyReadOnlyMods, "get").WithArguments("S4.this[int]").WithLocation(33, 18),
- // (40,32): error CS0106: The modifier 'static' is not valid for this item
+ Diagnostic(ErrorCode.ERR_InvalidPropertyReadOnlyMods, "get").WithArguments("S5.this[int]").WithLocation(42, 18),
+ // (50,32): error CS0106: The modifier 'static' is not valid for this item
// public static readonly int this[int i] => i;
- Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("static").WithLocation(40, 32));
+ Diagnostic(ErrorCode.ERR_BadMemberFlag, "this").WithArguments("static").WithLocation(50, 32));
}
[Fact]
@@ -1838,7 +1861,7 @@ public static readonly event Action E
";
var comp = CreateCompilation(csharp);
comp.VerifyDiagnostics(
- // (6,52): error CS8656: Static member 'S1.E' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.
+ // (6,52): error CS8656: Static member 'S1.E' cannot be marked 'readonly'.
// public static readonly event Action E
Diagnostic(ErrorCode.ERR_StaticMemberCantBeReadOnly, "E").WithArguments("S1.E").WithLocation(6, 52));
}
@@ -1879,11 +1902,11 @@ public struct S
public readonly void M() {}
public readonly int P1 => 42;
- public int P2 { readonly get => 123; }
- public int P3 { readonly set {} }
+ public int P2 { readonly get => 123; set {} }
+ public int P3 { get => 123; readonly set {} }
public readonly int this[int i] => i;
- public int this[int i, int j] { readonly get => i + j; }
+ public int this[int i, int j] { readonly get => i + j; set {} }
public readonly event Action E { add {} remove {} }
}
@@ -1891,22 +1914,22 @@ public readonly event Action E { add {} remove {} }
var comp = CreateCompilation(csharp, parseOptions: TestOptions.Regular7_3);
comp.VerifyDiagnostics(
// (6,12): error CS8652: The feature 'readonly members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
- // public readonly void M1() {}
+ // public readonly void M() {}
Diagnostic(ErrorCode.ERR_FeatureInPreview, "readonly").WithArguments("readonly members").WithLocation(6, 12),
// (8,12): error CS8652: The feature 'readonly members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public readonly int P1 => 42;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "readonly").WithArguments("readonly members").WithLocation(8, 12),
// (9,21): error CS8652: The feature 'readonly members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
- // public int P2 { readonly get => 123; }
+ // public int P2 { readonly get => 123; set {} }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "readonly").WithArguments("readonly members").WithLocation(9, 21),
- // (10,21): error CS8652: The feature 'readonly members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
- // public int P3 { readonly set {} }
- Diagnostic(ErrorCode.ERR_FeatureInPreview, "readonly").WithArguments("readonly members").WithLocation(10, 21),
+ // (10,33): error CS8652: The feature 'readonly members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
+ // public int P3 { get => 123; readonly set {} }
+ Diagnostic(ErrorCode.ERR_FeatureInPreview, "readonly").WithArguments("readonly members").WithLocation(10, 33),
// (12,12): error CS8652: The feature 'readonly members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public readonly int this[int i] => i;
Diagnostic(ErrorCode.ERR_FeatureInPreview, "readonly").WithArguments("readonly members").WithLocation(12, 12),
// (13,37): error CS8652: The feature 'readonly members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
- // public int this[int i, int j] { readonly get => i + j; }
+ // public int this[int i, int j] { readonly get => i + j; set {} }
Diagnostic(ErrorCode.ERR_FeatureInPreview, "readonly").WithArguments("readonly members").WithLocation(13, 37),
// (15,12): error CS8652: The feature 'readonly members' is currently in Preview and *unsupported*. To use Preview features, use the 'preview' language version.
// public readonly event Action E { add {} remove {} }
@@ -1915,5 +1938,46 @@ public readonly event Action E { add {} remove {} }
comp = CreateCompilation(csharp);
comp.VerifyDiagnostics();
}
+
+ [Fact]
+ public void ReadOnlyMethod_CompoundPropertyAssignment()
+ {
+ var csharp = @"
+struct S
+{
+ int P1 { get => 123; set {} }
+ int P2 { readonly get => 123; set {} }
+ int P3 { get => 123; readonly set {} }
+ readonly int P4 { get => 123; set {} }
+
+ void M1()
+ {
+ // ok
+ P1 += 1;
+ P2 += 1;
+ P3 += 1;
+ P4 += 1;
+ }
+
+ readonly void M2()
+ {
+ P1 += 1; // error
+ P2 += 1; // error
+ P3 += 1; // warning
+ P4 += 1; // ok
+ }
+}";
+ var comp = CreateCompilation(csharp);
+ comp.VerifyDiagnostics(
+ // (20,9): error CS1604: Cannot assign to 'P1' because it is read-only
+ // P1 += 1; // error
+ Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "P1").WithArguments("P1").WithLocation(20, 9),
+ // (21,9): error CS1604: Cannot assign to 'P2' because it is read-only
+ // P2 += 1; // error
+ Diagnostic(ErrorCode.ERR_AssgReadonlyLocal, "P2").WithArguments("P2").WithLocation(21, 9),
+ // (22,9): warning CS8655: Call to non-readonly member 'S.P3.get' from a 'readonly' member results in an implicit copy of 'this'.
+ // P3 += 1; // warning
+ Diagnostic(ErrorCode.WRN_ImplicitCopyInReadOnlyMember, "P3").WithArguments("S.P3.get", "this").WithLocation(22, 9));
+ }
}
}
diff --git a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs
index 9fb0b11fae15e..1522282190ccc 100644
--- a/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs
+++ b/src/Compilers/CSharp/Test/Syntax/Parsing/DeclarationParsingTests.cs
@@ -2907,6 +2907,27 @@ public void TestStructGetterPropertyWithReadonly()
Assert.Equal(SyntaxKind.ReadOnlyKeyword, accessors[0].Modifiers[0].Kind());
}
+ [Fact]
+ public void TestStructBadExpressionProperty()
+ {
+ var text =
+@"public struct S
+{
+ public int P readonly => 0;
+}
+";
+ var file = this.ParseFile(text, TestOptions.Regular);
+
+ Assert.NotNull(file);
+ Assert.Equal(1, file.Members.Count);
+ Assert.Equal(text, file.ToString());
+
+ Assert.Equal(3, file.Errors().Length);
+ Assert.Equal(ErrorCode.ERR_SemicolonExpected, (ErrorCode)file.Errors()[0].Code);
+ Assert.Equal(ErrorCode.ERR_InvalidMemberDecl, (ErrorCode)file.Errors()[1].Code);
+ Assert.Equal(ErrorCode.ERR_InvalidMemberDecl, (ErrorCode)file.Errors()[2].Code);
+ }
+
[Fact]
public void TestClassMethodWithParameter()
{