Exemple #1
0
		protected void AddPartial (TypeDefinition next_part, TypeDefinition existing)
		{
			next_part.ModFlags |= Modifiers.PARTIAL;

			if (existing == null) {
				AddTypeContainer (next_part);
				return;
			}

			if ((existing.ModFlags & Modifiers.PARTIAL) == 0) {
				if (existing.Kind != next_part.Kind) {
					AddTypeContainer (next_part);
				} else {
					Report.SymbolRelatedToPreviousError (next_part);
					Error_MissingPartialModifier (existing);
				}

				return;
			}

			if (existing.Kind != next_part.Kind) {
				Report.SymbolRelatedToPreviousError (existing);
				Report.Error (261, next_part.Location,
					"Partial declarations of `{0}' must be all classes, all structs or all interfaces",
					next_part.GetSignatureForError ());
			}

			if ((existing.ModFlags & Modifiers.AccessibilityMask) != (next_part.ModFlags & Modifiers.AccessibilityMask) &&
				((existing.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) == 0 &&
				 (next_part.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) == 0)) {
					 Report.SymbolRelatedToPreviousError (existing);
				Report.Error (262, next_part.Location,
					"Partial declarations of `{0}' have conflicting accessibility modifiers",
					next_part.GetSignatureForError ());
			}

			var tc_names = existing.CurrentTypeParameters;
			if (tc_names != null) {
				for (int i = 0; i < tc_names.Count; ++i) {
					var tp = next_part.MemberName.TypeParameters[i];
					if (tc_names[i].MemberName.Name != tp.MemberName.Name) {
						Report.SymbolRelatedToPreviousError (existing.Location, "");
						Report.Error (264, next_part.Location, "Partial declarations of `{0}' must have the same type parameter names in the same order",
							next_part.GetSignatureForError ());
						break;
					}

					if (tc_names[i].Variance != tp.Variance) {
						Report.SymbolRelatedToPreviousError (existing.Location, "");
						Report.Error (1067, next_part.Location, "Partial declarations of `{0}' must have the same type parameter variance modifiers",
							next_part.GetSignatureForError ());
						break;
					}
				}
			}

			if ((next_part.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) != 0) {
				existing.ModFlags |= next_part.ModFlags & ~(Modifiers.DEFAULT_ACCESS_MODIFER | Modifiers.AccessibilityMask);
			} else if ((existing.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) != 0) {
				existing.ModFlags &= ~(Modifiers.DEFAULT_ACCESS_MODIFER | Modifiers.AccessibilityMask);
				existing.ModFlags |= next_part.ModFlags;
			} else {
				existing.ModFlags |= next_part.ModFlags;
			}

			existing.Definition.Modifiers = existing.ModFlags;

			if (next_part.attributes != null) {
				if (existing.attributes == null)
					existing.attributes = next_part.attributes;
				else
					existing.attributes.AddAttributes (next_part.attributes.Attrs);
			}

			next_part.PartialContainer = existing;

			if (containers == null)
				containers = new List<TypeContainer> ();

			containers.Add (next_part);
		}
Exemple #2
0
		public bool Define (TypeDefinition container, string method_full_name)
		{
			PendingImplementation pending = container.PendingImplementations;
			MethodSpec ambig_iface_method;
			bool optional = false;

			if (pending != null) {
				implementing = pending.IsInterfaceMethod (method.MethodName, member.InterfaceType, this, out ambig_iface_method, ref optional);

				if (member.InterfaceType != null) {
					if (implementing == null) {
						if (member is PropertyBase) {
							container.Compiler.Report.Error (550, method.Location,
								"`{0}' is an accessor not found in interface member `{1}{2}'",
									  method.GetSignatureForError (), member.InterfaceType.GetSignatureForError (),
									  member.GetSignatureForError ().Substring (member.GetSignatureForError ().LastIndexOf ('.')));

						} else {
							container.Compiler.Report.Error (539, method.Location,
									  "`{0}.{1}' in explicit interface declaration is not a member of interface",
									  member.InterfaceType.GetSignatureForError (), member.ShortName);
						}
						return false;
					}
					if (implementing.IsAccessor && !method.IsAccessor) {
						container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
						container.Compiler.Report.Error (683, method.Location,
							"`{0}' explicit method implementation cannot implement `{1}' because it is an accessor",
							member.GetSignatureForError (), implementing.GetSignatureForError ());
						return false;
					}
				} else {
					if (implementing != null) {
						if (!method.IsAccessor) {
							if (implementing.IsAccessor) {
								container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
								container.Compiler.Report.Error (470, method.Location,
									"Method `{0}' cannot implement interface accessor `{1}'",
									method.GetSignatureForError (), TypeManager.CSharpSignature (implementing));
							}
						} else if (implementing.DeclaringType.IsInterface) {
							if (!implementing.IsAccessor) {
								container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
								container.Compiler.Report.Error (686, method.Location,
									"Accessor `{0}' cannot implement interface member `{1}' for type `{2}'. Use an explicit interface implementation",
									method.GetSignatureForError (), TypeManager.CSharpSignature (implementing), container.GetSignatureForError ());
							} else {
								PropertyBase.PropertyMethod pm = method as PropertyBase.PropertyMethod;
								if (pm != null && pm.HasCustomAccessModifier && (pm.ModFlags & Modifiers.PUBLIC) == 0) {
									container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
									container.Compiler.Report.Error (277, method.Location,
										"Accessor `{0}' must be declared public to implement interface member `{1}'",
										method.GetSignatureForError (), implementing.GetSignatureForError ());
								}
							}
						}
					}
				}
			} else {
				ambig_iface_method = null;
			}

			//
			// For implicit implementations, make sure we are public, for
			// explicit implementations, make sure we are private.
			//
			if (implementing != null){
				if (member.IsExplicitImpl) {
					if (method.ParameterInfo.HasParams && !implementing.Parameters.HasParams) {
						container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
						container.Compiler.Report.Error (466, method.Location,
							"`{0}': the explicit interface implementation cannot introduce the params modifier",
							method.GetSignatureForError ());
					}

					if (ambig_iface_method != null) {
						container.Compiler.Report.SymbolRelatedToPreviousError (ambig_iface_method);
						container.Compiler.Report.SymbolRelatedToPreviousError (implementing);
						container.Compiler.Report.Warning (473, 2, method.Location,
							"Explicit interface implementation `{0}' matches more than one interface member. Consider using a non-explicit implementation instead",
							method.GetSignatureForError ());
					}
				} else {
					//
					// Setting implementin to null inside this block will trigger a more
					// verbose error reporting for missing interface implementations
					//
					if (implementing.DeclaringType.IsInterface) {
						//
						// If this is an interface method implementation,
						// check for public accessibility
						//
						if ((flags & MethodAttributes.MemberAccessMask) != MethodAttributes.Public) {
							implementing = null;
						} else if (optional && (container.Interfaces == null || !container.Definition.Interfaces.Contains (implementing.DeclaringType))) {
							//
							// We are not implementing interface when base class already implemented it
							//
							implementing = null;
						}
					} else if ((flags & MethodAttributes.MemberAccessMask) == MethodAttributes.Private) {
						// We may never be private.
						implementing = null;

					} else if ((modifiers & Modifiers.OVERRIDE) == 0) {
						//
						// We may be protected if we're overriding something.
						//
						implementing = null;
					}
				}
					
				//
				// Static is not allowed
				//
				if ((modifiers & Modifiers.STATIC) != 0){
					implementing = null;
				}
			}
			
			//
			// If implementing is still valid, set flags
			//
			if (implementing != null){
				//
				// When implementing interface methods, set NewSlot
				// unless, we are overwriting a method.
				//
				if ((modifiers & Modifiers.OVERRIDE) == 0 && implementing.DeclaringType.IsInterface) {
					flags |= MethodAttributes.NewSlot;
				}

				flags |= MethodAttributes.Virtual | MethodAttributes.HideBySig;

				// Set Final unless we're virtual, abstract or already overriding a method.
				if ((modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE)) == 0)
					flags |= MethodAttributes.Final;

				//
				// clear the pending implementation flag (requires explicit methods to be defined first)
				//
				pending.ImplementMethod (method.MethodName,
					member.InterfaceType, this, member.IsExplicitImpl, out ambig_iface_method, ref optional);

				//
				// Update indexer accessor name to match implementing abstract accessor
				//
				if (!implementing.DeclaringType.IsInterface && !member.IsExplicitImpl && implementing.IsAccessor)
					method_full_name = implementing.MemberDefinition.Name;
			}

			full_name = method_full_name;
			declaring_type = container.Definition;

			return true;
		}
Exemple #3
0
        /// <summary>
        ///   This function tells whether one of our base classes implements
        ///   the given method (which turns out, it is valid to have an interface
        ///   implementation in a base
        /// </summary>
        bool BaseImplements(TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method)
        {
            base_method = null;
            var base_type = container.BaseType;

            //
            // Setup filter with no return type to give better error message
            // about mismatch at return type when the check bellow rejects them
            //
            var        parameters  = mi.Parameters;
            MethodSpec close_match = null;

            while (true)
            {
                var candidates = MemberCache.FindMembers(base_type, mi.Name, false);
                if (candidates == null)
                {
                    base_method = close_match;
                    return(false);
                }

                MethodSpec similar_candidate = null;
                foreach (var candidate in candidates)
                {
                    if (candidate.Kind != MemberKind.Method)
                    {
                        continue;
                    }

                    if (candidate.Arity != mi.Arity)
                    {
                        continue;
                    }

                    var candidate_param = ((MethodSpec)candidate).Parameters;
                    if (!TypeSpecComparer.Override.IsEqual(parameters.Types, candidate_param.Types))
                    {
                        continue;
                    }

                    bool modifiers_match = true;
                    for (int i = 0; i < parameters.Count; ++i)
                    {
                        //
                        // First check exact ref/out match
                        //
                        if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                        {
                            continue;
                        }

                        modifiers_match = false;

                        //
                        // Different in ref/out only
                        //
                        if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                        {
                            if (similar_candidate == null)
                            {
                                if (!candidate.IsPublic)
                                {
                                    break;
                                }

                                if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, ((MethodSpec)candidate).ReturnType))
                                {
                                    break;
                                }

                                // It's used for ref/out ambiguity overload check
                                similar_candidate = (MethodSpec)candidate;
                            }

                            continue;
                        }

                        similar_candidate = null;
                        break;
                    }

                    if (!modifiers_match)
                    {
                        continue;
                    }

                    //
                    // From this point the candidate is used for detailed error reporting
                    // because it's very close match to what we are looking for
                    //
                    var m = (MethodSpec)candidate;

                    if (!m.IsPublic)
                    {
                        if (close_match == null)
                        {
                            close_match = m;
                        }

                        continue;
                    }

                    if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, m.ReturnType))
                    {
                        if (close_match == null)
                        {
                            close_match = m;
                        }

                        continue;
                    }

                    base_method = m;

                    if (mi.IsGeneric && !Method.CheckImplementingMethodConstraints(container, m, mi))
                    {
                        return(true);
                    }
                }

                if (base_method != null)
                {
                    if (similar_candidate != null)
                    {
                        Report.SymbolRelatedToPreviousError(similar_candidate);
                        Report.SymbolRelatedToPreviousError(mi);
                        Report.SymbolRelatedToPreviousError(container);
                        Report.Warning(1956, 1, ((MemberCore)base_method.MemberDefinition).Location,
                                       "The interface method `{0}' implementation is ambiguous between following methods: `{1}' and `{2}' in type `{3}'",
                                       mi.GetSignatureForError(), base_method.GetSignatureForError(), similar_candidate.GetSignatureForError(), container.GetSignatureForError());
                    }

                    break;
                }

                base_type = candidates[0].DeclaringType.BaseType;
                if (base_type == null)
                {
                    base_method = close_match;
                    return(false);
                }
            }

            if (!base_method.IsVirtual)
            {
#if STATIC
                var base_builder = base_method.GetMetaInfo() as MethodBuilder;
                if (base_builder != null)
                {
                    //
                    // We can avoid creating a proxy if base_method can be marked 'final virtual'. This can
                    // be done for all methods from compiled assembly
                    //
                    base_builder.__SetAttributes(base_builder.Attributes | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot);
                    return(true);
                }
#endif
                DefineProxy(iface_type, base_method, mi);
            }

            return(true);
        }
Exemple #4
0
        /// <summary>
        ///   This function tells whether one of our base classes implements
        ///   the given method (which turns out, it is valid to have an interface
        ///   implementation in a base
        /// </summary>
        bool BaseImplements(TypeSpec iface_type, MethodSpec mi, out MethodSpec base_method)
        {
            base_method = null;
            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
            // about mismatch at return type when the check bellow rejects them
            //
            var        parameters  = mi.Parameters;
            MethodSpec close_match = null;

            while (true)
            {
                var candidates = MemberCache.FindMembers(lookup_type, mi.Name, !base_can_implement);
                if (candidates == null)
                {
                    base_method = close_match;
                    return(false);
                }

                MethodSpec similar_candidate = null;
                foreach (var candidate in candidates)
                {
                    if (candidate.Kind != MemberKind.Method)
                    {
                        continue;
                    }

                    if (candidate.Arity != mi.Arity)
                    {
                        continue;
                    }

                    var candidate_param = ((MethodSpec)candidate).Parameters;
                    if (!TypeSpecComparer.Override.IsEqual(parameters.Types, candidate_param.Types))
                    {
                        continue;
                    }

                    bool modifiers_match = true;
                    for (int i = 0; i < parameters.Count; ++i)
                    {
                        //
                        // First check exact ref/out match
                        //
                        if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) == (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                        {
                            continue;
                        }

                        modifiers_match = false;

                        //
                        // Different in ref/out only
                        //
                        if ((parameters.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask) != (candidate_param.FixedParameters[i].ModFlags & Parameter.Modifier.RefOutMask))
                        {
                            if (similar_candidate == null)
                            {
                                if (!candidate.IsPublic)
                                {
                                    break;
                                }

                                if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, ((MethodSpec)candidate).ReturnType))
                                {
                                    break;
                                }

                                // It's used for ref/out ambiguity overload check
                                similar_candidate = (MethodSpec)candidate;
                            }

                            continue;
                        }

                        similar_candidate = null;
                        break;
                    }

                    if (!modifiers_match)
                    {
                        continue;
                    }

                    //
                    // From this point the candidate is used for detailed error reporting
                    // because it's very close match to what we are looking for
                    //
                    var m = (MethodSpec)candidate;

                    if (!m.IsPublic)
                    {
                        if (close_match == null)
                        {
                            close_match = m;
                        }

                        continue;
                    }

                    if (!TypeSpecComparer.Override.IsEqual(mi.ReturnType, m.ReturnType))
                    {
                        if (close_match == null)
                        {
                            close_match = m;
                        }

                        continue;
                    }

                    base_method = m;

                    if (mi.IsGeneric && !Method.CheckImplementingMethodConstraints(container, m, mi))
                    {
                        return(true);
                    }
                }

                if (base_method != null)
                {
                    if (similar_candidate != null)
                    {
                        Report.SymbolRelatedToPreviousError(similar_candidate);
                        Report.SymbolRelatedToPreviousError(mi);
                        Report.SymbolRelatedToPreviousError(container);
                        Report.Warning(1956, 1, ((MemberCore)base_method.MemberDefinition).Location,
                                       "The interface method `{0}' implementation is ambiguous between following methods: `{1}' and `{2}' in type `{3}'",
                                       mi.GetSignatureForError(), base_method.GetSignatureForError(), similar_candidate.GetSignatureForError(), container.GetSignatureForError());
                    }

                    break;
                }

                if (!base_can_implement)
                {
                    return(false);
                }

                lookup_type = candidates[0].DeclaringType.BaseType;
                if (lookup_type == null)
                {
                    base_method = close_match;
                    return(false);
                }
            }

            if (!base_method.IsVirtual)
            {
#if STATIC
                var base_builder = base_method.GetMetaInfo() as MethodBuilder;
                if (base_builder != null)
                {
                    //
                    // We can avoid creating a proxy if base_method can be marked 'final virtual'. This can
                    // be done for all methods from compiled assembly
                    //
                    base_builder.__SetAttributes(base_builder.Attributes | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot);
                    return(true);
                }
#endif
                DefineProxy(iface_type, base_method, mi);
            }

            return(true);
        }