// // Factory method: if there are pending implementation methods, we return a PendingImplementation // object, otherwise we return null. // // Register method implementations are either abstract methods // flagged as such on the base class or interface methods // static public PendingImplementation GetPendingImplementations(TypeDefinition container) { TypeSpec b = container.BaseType; var missing_interfaces = GetMissingInterfaces(container); // // If we are implementing an abstract class, and we are not // ourselves abstract, and there are abstract methods (C# allows // abstract classes that have no abstract methods), then allocate // one slot. // // We also pre-compute the methods. // bool implementing_abstract = ((b != null) && b.IsAbstract && (container.ModFlags & Modifiers.ABSTRACT) == 0); MethodSpec[] abstract_methods = null; if (implementing_abstract) { var am = MemberCache.GetNotImplementedAbstractMethods(b); if (am == null) { implementing_abstract = false; } else { abstract_methods = new MethodSpec[am.Count]; am.CopyTo(abstract_methods, 0); } } int total = missing_interfaces.Length + (implementing_abstract ? 1 : 0); if (total == 0) { return(null); } var pending = new PendingImplementation(container, missing_interfaces, abstract_methods, total); // // check for inherited conflicting methods // foreach (var p in pending.pending_implementations) { // // It can happen for generic interfaces only // if (!p.type.IsGeneric) { continue; } // // CLR does not distinguishes between ref and out // for (int i = 0; i < p.methods.Count; ++i) { MethodSpec compared_method = p.methods[i]; if (compared_method.Parameters.IsEmpty) { continue; } for (int ii = i + 1; ii < p.methods.Count; ++ii) { MethodSpec tested_method = p.methods[ii]; if (compared_method.Name != tested_method.Name) { continue; } if (p.type != tested_method.DeclaringType) { continue; } if (!TypeSpecComparer.Override.IsSame(compared_method.Parameters.Types, tested_method.Parameters.Types)) { continue; } bool exact_match = true; bool ref_only_difference = false; var cp = compared_method.Parameters.FixedParameters; var tp = tested_method.Parameters.FixedParameters; for (int pi = 0; pi < cp.Length; ++pi) { // // First check exact modifiers match // if ((cp[pi].ModFlags & Parameter.Modifier.RefOutMask) == (tp[pi].ModFlags & Parameter.Modifier.RefOutMask)) { continue; } if (((cp[pi].ModFlags | tp[pi].ModFlags) & Parameter.Modifier.RefOutMask) == Parameter.Modifier.RefOutMask) { ref_only_difference = true; continue; } exact_match = false; break; } if (!exact_match || !ref_only_difference) { continue; } pending.Report.SymbolRelatedToPreviousError(compared_method); pending.Report.SymbolRelatedToPreviousError(tested_method); pending.Report.Error(767, container.Location, "Cannot implement interface `{0}' with the specified type parameters because it causes method `{1}' to differ on parameter modifiers only", p.type.GetDefinition().GetSignatureForError(), compared_method.GetSignatureForError()); break; } } } return(pending); }
protected virtual bool DoDefineMembers () { Debug.Assert (!IsPartialPart); if (iface_exprs != null) { foreach (var iface_type in iface_exprs) { if (iface_type == null) continue; // Ensure the base is always setup var compiled_iface = iface_type.MemberDefinition as Interface; if (compiled_iface != null) compiled_iface.Define (); ObsoleteAttribute oa = iface_type.GetAttributeObsolete (); if (oa != null && !IsObsolete) AttributeTester.Report_ObsoleteMessage (oa, iface_type.GetSignatureForError (), Location, Report); if (iface_type.Arity > 0) { // TODO: passing `this' is wrong, should be base type iface instead VarianceDecl.CheckTypeVariance (iface_type, Variance.Covariant, this); if (((InflatedTypeSpec) iface_type).HasDynamicArgument () && !IsCompilerGenerated) { Report.Error (1966, Location, "`{0}': cannot implement a dynamic interface `{1}'", GetSignatureForError (), iface_type.GetSignatureForError ()); return false; } } if (iface_type.IsGenericOrParentIsGeneric) { foreach (var prev_iface in iface_exprs) { if (prev_iface == iface_type || prev_iface == null) break; if (!TypeSpecComparer.Unify.IsEqual (iface_type, prev_iface)) continue; Report.Error (695, Location, "`{0}' cannot implement both `{1}' and `{2}' because they may unify for some type parameter substitutions", GetSignatureForError (), prev_iface.GetSignatureForError (), iface_type.GetSignatureForError ()); } } } if (Kind == MemberKind.Interface) { foreach (var iface in spec.Interfaces) { MemberCache.AddInterface (iface); } } } if (base_type != null) { // // Run checks skipped during DefineType (e.g FullNamedExpression::ResolveAsType) // if (base_type_expr != null) { ObsoleteAttribute obsolete_attr = base_type.GetAttributeObsolete (); if (obsolete_attr != null && !IsObsolete) AttributeTester.Report_ObsoleteMessage (obsolete_attr, base_type.GetSignatureForError (), base_type_expr.Location, Report); if (IsGenericOrParentIsGeneric && base_type.IsAttribute) { Report.Error (698, base_type_expr.Location, "A generic type cannot derive from `{0}' because it is an attribute class", base_type.GetSignatureForError ()); } } var baseContainer = base_type.MemberDefinition as ClassOrStruct; if (baseContainer != null) { baseContainer.Define (); // // It can trigger define of this type (for generic types only) // if (HasMembersDefined) return true; } } if (Kind == MemberKind.Struct || Kind == MemberKind.Class) { pending = PendingImplementation.GetPendingImplementations (this); } var count = members.Count; for (int i = 0; i < count; ++i) { var mc = members[i] as InterfaceMemberBase; if (mc == null || !mc.IsExplicitImpl) continue; try { mc.Define (); } catch (Exception e) { throw new InternalErrorException (mc, e); } } for (int i = 0; i < count; ++i) { var mc = members[i] as InterfaceMemberBase; if (mc != null && mc.IsExplicitImpl) continue; if (members[i] is TypeContainer) continue; try { members[i].Define (); } catch (Exception e) { throw new InternalErrorException (members[i], e); } } if (HasOperators) { CheckPairedOperators (); } if (requires_delayed_unmanagedtype_check) { requires_delayed_unmanagedtype_check = false; foreach (var member in members) { var f = member as Field; if (f != null && f.MemberType != null && f.MemberType.IsPointer) TypeManager.VerifyUnmanaged (Module, f.MemberType, f.Location); } } ComputeIndexerName(); if (HasEquals && !HasGetHashCode) { Report.Warning (659, 3, Location, "`{0}' overrides Object.Equals(object) but does not override Object.GetHashCode()", GetSignatureForError ()); } if (Kind == MemberKind.Interface && iface_exprs != null) { MemberCache.RemoveHiddenMembers (spec); } return true; }
// // Factory method: if there are pending implementation methods, we return a PendingImplementation // object, otherwise we return null. // // Register method implementations are either abstract methods // flagged as such on the base class or interface methods // static public PendingImplementation GetPendingImplementations (TypeDefinition container) { TypeSpec b = container.BaseType; var missing_interfaces = GetMissingInterfaces (container); // // If we are implementing an abstract class, and we are not // ourselves abstract, and there are abstract methods (C# allows // abstract classes that have no abstract methods), then allocate // one slot. // // We also pre-compute the methods. // bool implementing_abstract = ((b != null) && b.IsAbstract && (container.ModFlags & Modifiers.ABSTRACT) == 0); MethodSpec[] abstract_methods = null; if (implementing_abstract){ var am = MemberCache.GetNotImplementedAbstractMethods (b); if (am == null) { implementing_abstract = false; } else { abstract_methods = new MethodSpec[am.Count]; am.CopyTo (abstract_methods, 0); } } int total = missing_interfaces.Length + (implementing_abstract ? 1 : 0); if (total == 0) return null; var pending = new PendingImplementation (container, missing_interfaces, abstract_methods, total); // // check for inherited conflicting methods // foreach (var p in pending.pending_implementations) { // // It can happen for generic interfaces only // if (!p.type.IsGeneric) continue; // // CLR does not distinguishes between ref and out // for (int i = 0; i < p.methods.Count; ++i) { MethodSpec compared_method = p.methods[i]; if (compared_method.Parameters.IsEmpty) continue; for (int ii = i + 1; ii < p.methods.Count; ++ii) { MethodSpec tested_method = p.methods[ii]; if (compared_method.Name != tested_method.Name) continue; if (p.type != tested_method.DeclaringType) continue; if (!TypeSpecComparer.Override.IsSame (compared_method.Parameters.Types, tested_method.Parameters.Types)) continue; bool exact_match = true; bool ref_only_difference = false; var cp = compared_method.Parameters.FixedParameters; var tp = tested_method.Parameters.FixedParameters; for (int pi = 0; pi < cp.Length; ++pi) { // // First check exact modifiers match // if ((cp[pi].ModFlags & Parameter.Modifier.RefOutMask) == (tp[pi].ModFlags & Parameter.Modifier.RefOutMask)) continue; if (((cp[pi].ModFlags | tp[pi].ModFlags) & Parameter.Modifier.RefOutMask) == Parameter.Modifier.RefOutMask) { ref_only_difference = true; continue; } exact_match = false; break; } if (!exact_match || !ref_only_difference) continue; pending.Report.SymbolRelatedToPreviousError (compared_method); pending.Report.SymbolRelatedToPreviousError (tested_method); pending.Report.Error (767, container.Location, "Cannot implement interface `{0}' with the specified type parameters because it causes method `{1}' to differ on parameter modifiers only", p.type.GetDefinition().GetSignatureForError (), compared_method.GetSignatureForError ()); break; } } } return pending; }