未验证 提交 0d15dd1a 编写于 作者: R Rikki Gibson 提交者: GitHub

Readonly members more test coverage (#34602)

* Check parser behavior for bad expression property declaration

* Make readonly modifiers more strict on accessors to match accessibility behavior

* Fix tests

* Improve implicit copy warning message. Add compound property assignment test.

* Test ErrorCode.ERR_ReadOnlyModMissingAccessor with an indexer

* Simplify error message for 'static readonly' members
上级 56214c6c
......@@ -1153,7 +1153,7 @@ internal bool CheckImplicitThisCopyInReadOnlyMember(BoundExpression receiver, Me
!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;
}
......
......@@ -8763,6 +8763,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to &apos;{0}&apos;: &apos;readonly&apos; can only be used on accessors if the property or indexer has both a get and a set accessor.
/// </summary>
internal static string ERR_ReadOnlyModMissingAccessor {
get {
return ResourceManager.GetString("ERR_ReadOnlyModMissingAccessor", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Members of readonly field &apos;{0}&apos; of type &apos;{1}&apos; cannot be assigned with an object initializer because it is of a value type.
/// </summary>
......@@ -9664,7 +9673,7 @@ internal class CSharpResources {
}
/// <summary>
/// Looks up a localized string similar to Static member &apos;{0}&apos; cannot be marked &apos;readonly&apos; because readonly members cannot modify &apos;this&apos; and static members do not have a &apos;this&apos; parameter..
/// Looks up a localized string similar to Static member &apos;{0}&apos; cannot be marked &apos;readonly&apos;..
/// </summary>
internal static string ERR_StaticMemberCantBeReadOnly {
get {
......
......@@ -5431,7 +5431,7 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<value>Call to non-readonly member from a 'readonly' member results in an implicit copy.</value>
</data>
<data name="ERR_StaticMemberCantBeReadOnly" xml:space="preserve">
<value>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</value>
<value>Static member '{0}' cannot be marked 'readonly'.</value>
</data>
<data name="ERR_AutoSetterCantBeReadOnly" xml:space="preserve">
<value>Auto-implemented 'set' accessor '{0}' cannot be marked 'readonly'.</value>
......@@ -5451,6 +5451,9 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_PartialMethodReadOnlyDifference" xml:space="preserve">
<value>Both partial method declarations must be readonly or neither may be readonly</value>
</data>
<data name="ERR_ReadOnlyModMissingAccessor" xml:space="preserve">
<value>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</value>
</data>
<data name="WRN_NullabilityMismatchInArgument" xml:space="preserve">
<value>Argument of type '{0}' cannot be used for parameter '{2}' of type '{1}' in '{3}' due to differences in the nullability of reference types.</value>
</data>
......
......@@ -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
......
......@@ -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)
......
......@@ -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))
......
......@@ -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)
......
......@@ -385,6 +385,12 @@ internal sealed class SourcePropertySymbol : PropertySymbol, IAttributeTargetSym
{
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))
......
......@@ -292,6 +292,11 @@
<target state="translated">Dílčí vzor vlastnosti vyžaduje odkaz na vlastnost nebo pole k přiřazení, např. „{{ Name: {0} }}“.</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">Přiřazení odkazu {1} k {0} nelze provést, protože {1} má užší řídicí obor než {0}.</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">Ein Eigenschaftsteilmuster erfordert einen Verweis auf die abzugleichende Eigenschaft oder das abzugleichende Feld. Beispiel: "{{ Name: {0} }}"</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">ref-assign von "{1}" zu "{0}" ist nicht möglich, weil "{1}" einen geringeren Escapebereich als "{0}" aufweist.</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">El subpatrón de una propiedad requiere una referencia a la propiedad o al campo que debe coincidir; por ejemplo, "{{ Name: {0} }}"</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">No se puede asignar referencia "{1}" a "{0}" porque "{1}" tiene un ámbito de escape más limitado que "{0}".</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">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} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">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}'.</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">Con un criterio secondario di proprietà è richiesto un riferimento alla proprietà o al campo da abbinare, ad esempio '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">Non è possibile assegnare '{1}' a '{0}' come ref perché l'ambito di escape di '{1}' è ridotto rispetto a quello di '{0}'.</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">プロパティ サブパターンには、一致させるプロパティまたはフィールドへの参照が必要です。例: '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">'{1}' を '{0}' に ref 割り当てすることはできません。'{1}' のエスケープ スコープが '{0}' より狭いためです。</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">속성 하위 패턴은 일치시킬 속성 또는 필드에 대한 참조가 필요합니다(예: '{{ Name: {0} }}')</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">'{1}'을(를) '{0}'에 참조 할당할 수 없습니다. '{1}'이(가) '{0}'보다 이스케이프 범위가 좁기 때문입니다.</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">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} }}”</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">Nie można przypisać odwołania elementu „{1}” do elementu „{0}”, ponieważ element „{1}” ma węższy zakres wyjścia niż element „{0}”.</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">Um subpadrão de propriedade requer que uma referência à propriedade ou ao campo seja correspondida, por exemplo, '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">Não é possível atribuir ref '{1}' a '{0}' porque '{1}' tem um escopo de escape mais limitado que '{0}'.</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">Для вложенного шаблона свойств требуется ссылка на свойство или поле для сопоставления, например, "{{ Name: {0} }}".</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">Не удается присвоить по ссылке "{1}" для "{0}", так как escape-область у "{1}" уже, чем у "{0}".</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">Bir özellik alt deseni, özellik veya alan başvurusunun eşleşmesini gerektiriyor, ör. '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">'{1}', '{0}' öğesinden daha dar bir kaçış kapsamı içerdiğinden '{0}' öğesine '{1}' ref ataması yapılamıyor.</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">属性子模式需要引用要匹配的属性或字段,例如,"{{ Name: {0} }}"</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">无法将“{1}”重新赋值为“{0}”,因为“{1}”具有比“{0}”更窄的转义范围。</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -292,6 +292,11 @@
<target state="translated">屬性子模式需要對屬性或欄位的參考才能比對,例如 '{{ Name: {0} }}'</target>
<note />
</trans-unit>
<trans-unit id="ERR_ReadOnlyModMissingAccessor">
<source>'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</source>
<target state="new">'{0}': 'readonly' can only be used on accessors if the property or indexer has both a get and a set accessor</target>
<note />
</trans-unit>
<trans-unit id="ERR_RefAssignNarrower">
<source>Cannot ref-assign '{1}' to '{0}' because '{1}' has a narrower escape scope than '{0}'.</source>
<target state="translated">不能將 '{1}' 參考指派至 '{0}',因為 '{1}' 的逸出範圍比 '{0}' 還要窄。</target>
......@@ -318,8 +323,8 @@
<note />
</trans-unit>
<trans-unit id="ERR_StaticMemberCantBeReadOnly">
<source>Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly' because readonly members cannot modify 'this' and static members do not have a 'this' parameter.</target>
<source>Static member '{0}' cannot be marked 'readonly'.</source>
<target state="new">Static member '{0}' cannot be marked 'readonly'.</target>
<note />
</trans-unit>
<trans-unit id="ERR_SwitchArmSubsumed">
......
......@@ -1319,8 +1319,8 @@ public struct S
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 void ReadOnlyStruct_ReadOnlyMembers_Metadata()
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 struct S1
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<EventArgs> E { add {} remove {} }
}
......@@ -1535,6 +1543,7 @@ public struct S1
}
";
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 @@ public struct S
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 @@ public struct S
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", @"
......
......@@ -508,9 +508,9 @@ void M1()
";
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 struct S
";
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 @@ void M1()
";
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 async Task M1()
";
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 @@ void M1()
";
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 @@ void M1()
";
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 @@ public struct S3
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 struct S1
";
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<EventArgs> 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<EventArgs> E { add {} remove {} }
}
......@@ -1891,22 +1914,22 @@ public struct S
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<EventArgs> E { add {} remove {} }
......@@ -1915,5 +1938,46 @@ public struct S
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));
}
}
}
......@@ -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()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册