提交 667f95b8 编写于 作者: M Marek Safar

Reject varianly implemented interface members.

上级 549e7b41
// CS738: `CB' does not implement interface member `IG<IA>.Method()' and the best implementing candidate `CA<IB>.Method()' return type `IB' does not match interface member return type `IA'
// Line: 29
public interface IA
{
}
public interface IB : IA
{
}
public interface IG<out U>
{
U Method ();
}
public interface IDerived : IG<IA>
{
}
public abstract class CA<T> : IG<T>
{
public T Method ()
{
return default (T);
}
}
public class CB : CA<IB>, IG<IA>
{
}
......@@ -129,7 +129,7 @@ namespace Mono.CSharp {
// From T to any interface implemented by C
//
var base_type = expr_type.GetEffectiveBase ();
if (base_type == target_type || TypeSpec.IsBaseClass (base_type, target_type, false) || base_type.ImplementsInterface (target_type)) {
if (base_type == target_type || TypeSpec.IsBaseClass (base_type, target_type, false) || base_type.ImplementsInterface (target_type, true)) {
if (expr_type.IsReferenceType)
return new ClassCast (expr, target_type);
......@@ -239,7 +239,7 @@ namespace Mono.CSharp {
// from any class-type S to any interface-type T.
if (target_type.IsInterface) {
if (expr_type.ImplementsInterface (target_type)){
if (expr_type.ImplementsInterface (target_type, true)){
return !TypeManager.IsValueType (expr_type);
}
}
......@@ -321,7 +321,7 @@ namespace Mono.CSharp {
// from any interface type S to interface-type T.
if (expr_type.IsInterface && target_type.IsInterface) {
return expr_type.ImplementsInterface (target_type);
return expr_type.ImplementsInterface (target_type, true);
}
// from any delegate type to System.Delegate
......@@ -403,7 +403,7 @@ namespace Mono.CSharp {
// from any class-type S to any interface-type T.
if (target_type.IsInterface) {
if (expr_type.ImplementsInterface (target_type) &&
if (expr_type.ImplementsInterface (target_type, true) &&
(TypeManager.IsGenericParameter (expr_type) || TypeManager.IsValueType (expr_type))) {
return expr == null ? EmptyExpression.Null : new BoxedCast (expr, target_type);
}
......@@ -765,7 +765,7 @@ namespace Mono.CSharp {
// If `expr_type' implements `target_type' (which is an iface)
// see TryImplicitIntConversion
//
if (target_type.IsInterface && expr_type.ImplementsInterface (target_type))
if (target_type.IsInterface && expr_type.ImplementsInterface (target_type, true))
return true;
if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
......@@ -1679,7 +1679,7 @@ namespace Mono.CSharp {
// sealed, or provided T implements S.
//
if (source_type.IsInterface) {
if (!target_type.IsSealed || target_type.ImplementsInterface (source_type)) {
if (!target_type.IsSealed || target_type.ImplementsInterface (source_type, true)) {
if (target_type.IsClass)
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
......@@ -1750,7 +1750,7 @@ namespace Mono.CSharp {
// From any class type S to any interface T, provides S is not sealed
// and provided S does not implement T.
//
if (target_type.IsInterface && !source_type.IsSealed && !source_type.ImplementsInterface (target_type)) {
if (target_type.IsInterface && !source_type.IsSealed && !source_type.ImplementsInterface (target_type, true)) {
return source == null ? EmptyExpression.Null : new ClassCast (source, target_type);
}
......
......@@ -8974,7 +8974,7 @@ namespace Mono.CSharp {
initializer.Resolve (ec);
throw new InternalErrorException ("This line should never be reached");
} else {
if (!ec.CurrentInitializerVariable.Type.ImplementsInterface (TypeManager.ienumerable_type)) {
if (!ec.CurrentInitializerVariable.Type.ImplementsInterface (TypeManager.ienumerable_type, false)) {
ec.Report.Error (1922, loc, "A field or property `{0}' cannot be initialized with a collection " +
"object initializer because type `{1}' does not implement `{2}' interface",
ec.CurrentInitializerVariable.GetSignatureForError (),
......
......@@ -325,7 +325,7 @@ namespace Mono.CSharp {
continue;
}
if (member.DeclaringType.ImplementsInterface (entry.DeclaringType)) {
if (member.DeclaringType.ImplementsInterface (entry.DeclaringType, false)) {
if (existing is MemberSpec[]) {
existing = new MemberSpec[] { member };
return true;
......@@ -336,7 +336,7 @@ namespace Mono.CSharp {
}
if ((entry.DeclaringType == member.DeclaringType && entry.IsAccessor == member.IsAccessor) ||
entry.DeclaringType.ImplementsInterface (member.DeclaringType))
entry.DeclaringType.ImplementsInterface (member.DeclaringType, false))
return false;
}
......
......@@ -360,7 +360,14 @@ namespace Mono.CSharp {
bool BaseImplements (TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method)
{
var base_type = container.BaseType;
base_method = (MethodSpec) MemberCache.FindMember (base_type, new MemberFilter (mi), BindingRestriction.None);
//
// Setup filter with no return type to give better error message
// about mismatch at return type when the check bellow rejects them
//
var filter = new MemberFilter (mi.Name, mi.Arity, MemberKind.Method, mi.Parameters, null);
base_method = (MethodSpec) MemberCache.FindMember (base_type, filter, BindingRestriction.None);
if (base_method == null || (base_method.Modifiers & Modifiers.PUBLIC) == 0)
return false;
......@@ -368,10 +375,8 @@ namespace Mono.CSharp {
if (base_method.DeclaringType.IsInterface)
return false;
// Why was it here ????
//if (TypeManager.ImplementsInterface (base_type, iface_type)) {
// return true;
//}
if (!TypeSpecComparer.Override.IsEqual (mi.ReturnType, base_method.ReturnType))
return false;
if (!base_method.IsAbstract && !base_method.IsVirtual)
// FIXME: We can avoid creating a proxy if base_method can be marked 'final virtual' instead.
......@@ -396,7 +401,7 @@ namespace Mono.CSharp {
bool base_implements_type = type.IsInterface &&
container.BaseType != null &&
container.BaseType.ImplementsInterface (type);
container.BaseType.ImplementsInterface (type, false);
for (int j = 0; j < pending_implementations [i].methods.Count; ++j) {
var mi = pending_implementations[i].methods[j];
......
......@@ -4849,7 +4849,7 @@ namespace Mono.CSharp {
if (expr == null)
return false;
if (expr.Type != TypeManager.idisposable_type && !expr.Type.ImplementsInterface (TypeManager.idisposable_type)) {
if (expr.Type != TypeManager.idisposable_type && !expr.Type.ImplementsInterface (TypeManager.idisposable_type, false)) {
if (TypeManager.IsNullableType (expr.Type)) {
// it's handled it a custom code bellow
} else if (expr.Type == InternalType.Dynamic) {
......@@ -4967,7 +4967,7 @@ namespace Mono.CSharp {
}
if (li == Variable) {
if (li.Type != TypeManager.idisposable_type && !li.Type.ImplementsInterface (TypeManager.idisposable_type)) {
if (li.Type != TypeManager.idisposable_type && !li.Type.ImplementsInterface (TypeManager.idisposable_type, false)) {
Using.Error_IsNotConvertibleToIDisposable (bc, li.Type, type_expr.Location);
return null;
}
......@@ -5534,7 +5534,7 @@ namespace Mono.CSharp {
//
// Add Dispose method call when enumerator can be IDisposable
//
if (!enum_type.ImplementsInterface (TypeManager.idisposable_type)) {
if (!enum_type.ImplementsInterface (TypeManager.idisposable_type, false)) {
if (!enum_type.IsSealed && !TypeManager.IsValueType (enum_type)) {
//
// Runtime Dispose check
......
......@@ -289,13 +289,16 @@ namespace Mono.CSharp
return "<" + TypeManager.CSharpName (MemberDefinition.TypeParameters) + ">";
}
public bool ImplementsInterface (TypeSpec iface)
public bool ImplementsInterface (TypeSpec iface, bool variantly)
{
var t = this;
do {
if (t.Interfaces != null) { // TODO: Try t.iface
foreach (TypeSpec i in t.Interfaces) {
if (i == iface || TypeSpecComparer.Variant.IsEqual (i, iface) || TypeSpecComparer.IsEqual (i, iface))
if (i == iface || TypeSpecComparer.IsEqual (i, iface))
return true;
if (variantly && TypeSpecComparer.Variant.IsEqual (i, iface))
return true;
}
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册