From 1782b291f89dd8f8b95cd3caeca5264672457cb8 Mon Sep 17 00:00:00 2001 From: Marek Safar Date: Mon, 29 May 2017 23:55:47 +0200 Subject: [PATCH] [mcs] New property/indexer cannot have accessors implementing an interface in base type. Fixes #56627 --- mcs/errors/cs0535-7.cs | 40 +++++++++++++++++++++++++++ mcs/errors/cs0535-8.cs | 40 +++++++++++++++++++++++++++ mcs/mcs/import.cs | 9 +------ mcs/mcs/pending.cs | 61 +++++++++++++++++++++++++++++++++--------- mcs/mcs/property.cs | 12 +++++++++ 5 files changed, 141 insertions(+), 21 deletions(-) create mode 100644 mcs/errors/cs0535-7.cs create mode 100644 mcs/errors/cs0535-8.cs diff --git a/mcs/errors/cs0535-7.cs b/mcs/errors/cs0535-7.cs new file mode 100644 index 00000000000..11a7670bc1b --- /dev/null +++ b/mcs/errors/cs0535-7.cs @@ -0,0 +1,40 @@ +// CS0535: `CC' does not implement interface member `IA.Coordinate.set' +// Line: 33 + +using System; + +public interface IA +{ + object Coordinate { + get; + set; + } +} + +public abstract class CA : IA +{ + public abstract object Coordinate { + get; + set; + } +} + +public partial class CB : CA +{ + public override object Coordinate { + get { + throw new NotImplementedException (); + } + set { + } + } +} + +public class CC : CB, IA +{ + public new object Coordinate { + get { + throw new NotImplementedException (); + } + } +} diff --git a/mcs/errors/cs0535-8.cs b/mcs/errors/cs0535-8.cs new file mode 100644 index 00000000000..853794ee31d --- /dev/null +++ b/mcs/errors/cs0535-8.cs @@ -0,0 +1,40 @@ +// CS0535: `CC' does not implement interface member `IA.this[int].set' +// Line: 33 + +using System; + +public interface IA +{ + object this[int arg] { + get; + set; + } +} + +public abstract class CA : IA +{ + public abstract object this[int arg] { + get; + set; + } +} + +public partial class CB : CA +{ + public override object this[int arg] { + get { + throw new NotImplementedException (); + } + set { + } + } +} + +public class CC : CB, IA +{ + public new object this[int arg] { + get { + throw new NotImplementedException (); + } + } +} diff --git a/mcs/mcs/import.cs b/mcs/mcs/import.cs index 359a738a555..dbec2c0469f 100644 --- a/mcs/mcs/import.cs +++ b/mcs/mcs/import.cs @@ -645,14 +645,7 @@ namespace Mono.CSharp if (set_param_count == 0) { set_based_param = ParametersCompiled.EmptyReadOnlyParameters; } else { - // - // Create indexer parameters based on setter method parameters (the last parameter has to be removed) - // - var data = new IParameterData[set_param_count]; - var types = new TypeSpec[set_param_count]; - Array.Copy (set.Parameters.FixedParameters, data, set_param_count); - Array.Copy (set.Parameters.Types, types, set_param_count); - set_based_param = new ParametersImported (data, types, set.Parameters.HasParams); + set_based_param = IndexerSpec.CreateParametersFromSetter (set, set_param_count); } mod = set.Modifiers; diff --git a/mcs/mcs/pending.cs b/mcs/mcs/pending.cs index 661142822f8..507b937e2c9 100644 --- a/mcs/mcs/pending.cs +++ b/mcs/mcs/pending.cs @@ -147,7 +147,6 @@ namespace Mono.CSharp { int i = 0; if (abstract_methods != null) { int count = abstract_methods.Length; - pending_implementations [i].methods = new MethodSpec [count]; pending_implementations [i].need_proxy = new MethodSpec [count]; pending_implementations [i].methods = abstract_methods; @@ -527,7 +526,47 @@ namespace Mono.CSharp { bool BaseImplements (TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method) { base_method = null; - var base_type = container.BaseType; + bool base_can_implement = true; + TypeSpec lookup_type; + + // + // Special handling for properties/indexers which cannot have accessors + // implementing an interface found in different types (e.g. current and base) + // + if (mi.IsAccessor && container.Interfaces != null) { + + bool new_implementation = false; + foreach (var iface in container.Interfaces) { + if (TypeSpecComparer.IsEqual (iface, iface_type)) { + new_implementation = true; + break; + } + } + + if (new_implementation) { + MemberFilter filter; + if (mi.Parameters.Count > 1) { + var indexer_params = mi.Name [0] == 'g' ? mi.Parameters : IndexerSpec.CreateParametersFromSetter (mi, mi.Parameters.Count - 1); + filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, MemberKind.Indexer, indexer_params, null); + } else { + var pname = mi.Name.Substring (4); + filter = MemberFilter.Property (pname, null); + } + + var prop = MemberCache.FindMember (container.CurrentType, filter, BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly); + if (prop != null && (prop.Modifiers & Modifiers.NEW) != 0) + base_can_implement = false; + } + } + + if (base_can_implement) { + lookup_type = container.BaseType; + + if (lookup_type.ImplementsInterface (iface_type, false)) + return true; + } else { + lookup_type = container.CurrentType; + } // // Setup filter with no return type to give better error message @@ -537,7 +576,7 @@ namespace Mono.CSharp { MethodSpec close_match = null; while (true) { - var candidates = MemberCache.FindMembers (base_type, mi.Name, false); + var candidates = MemberCache.FindMembers (lookup_type, mi.Name, !base_can_implement); if (candidates == null) { base_method = close_match; return false; @@ -630,8 +669,11 @@ namespace Mono.CSharp { break; } - base_type = candidates[0].DeclaringType.BaseType; - if (base_type == null) { + if (!base_can_implement) + return false; + + lookup_type = candidates[0].DeclaringType.BaseType; + if (lookup_type == null) { base_method = close_match; return false; } @@ -668,10 +710,6 @@ namespace Mono.CSharp { for (i = 0; i < top; i++){ TypeSpec type = pending_implementations [i].type; - bool base_implements_type = type.IsInterface && - container.BaseType != null && - container.BaseType.ImplementsInterface (type, false); - for (int j = 0; j < pending_implementations [i].methods.Count; ++j) { var mi = pending_implementations[i].methods[j]; if (mi == null) @@ -686,11 +724,8 @@ namespace Mono.CSharp { continue; } - if (pending_implementations [i].optional) - continue; - MethodSpec candidate; - if (base_implements_type || BaseImplements (type, mi, out candidate)) + if (BaseImplements (type, mi, out candidate)) continue; if (candidate == null) { diff --git a/mcs/mcs/property.cs b/mcs/mcs/property.cs index 5d831e940b5..0d4efedbd1e 100644 --- a/mcs/mcs/property.cs +++ b/mcs/mcs/property.cs @@ -1793,6 +1793,18 @@ namespace Mono.CSharp } #endregion + public static ParametersImported CreateParametersFromSetter (MethodSpec setter, int set_param_count) + { + // + // Creates indexer parameters based on setter method parameters (the last parameter has to be removed) + // + var data = new IParameterData [set_param_count]; + var types = new TypeSpec [set_param_count]; + Array.Copy (setter.Parameters.FixedParameters, data, set_param_count); + Array.Copy (setter.Parameters.Types, types, set_param_count); + return new ParametersImported (data, types, setter.Parameters.HasParams); + } + public override string GetSignatureForDocumentation () { return base.GetSignatureForDocumentation () + parameters.GetSignatureForDocumentation (); -- 2.25.1