Example #1
0
        /// <summary>
        /// Returns true if the two partial methods have the same constraints.
        /// </summary>
        private static bool HaveSameConstraints(SourceMemberMethodSymbol part1, SourceMemberMethodSymbol part2)
        {
            Debug.Assert(!ReferenceEquals(part1, part2));
            Debug.Assert(part1.Arity == part2.Arity);

            var typeParameters1 = part1.TypeParameters;

            int arity = typeParameters1.Length;

            if (arity == 0)
            {
                return(true);
            }

            var typeParameters2       = part2.TypeParameters;
            var indexedTypeParameters = IndexedTypeParameterSymbol.Take(arity);
            var typeMap1 = new TypeMap(typeParameters1, indexedTypeParameters, allowAlpha: true);
            var typeMap2 = new TypeMap(typeParameters2, indexedTypeParameters, allowAlpha: true);

            return(MemberSignatureComparer.HaveSameConstraints(typeParameters1, typeMap1, typeParameters2, typeMap2));
        }
Example #2
0
        internal static void FindExplicitlyImplementedMemberVerification(
            this Symbol implementingMember,
            Symbol implementedMember,
            BindingDiagnosticBag diagnostics
            )
        {
            if ((object)implementedMember == null)
            {
                return;
            }

            if (
                implementingMember.ContainsTupleNames() &&
                MemberSignatureComparer.ConsideringTupleNamesCreatesDifference(
                    implementingMember,
                    implementedMember
                    )
                )
            {
                // it is ok to explicitly implement with no tuple names, for compatibility with C# 6, but otherwise names should match
                var memberLocation = implementingMember.Locations[0];
                diagnostics.Add(
                    ErrorCode.ERR_ImplBadTupleNames,
                    memberLocation,
                    implementingMember,
                    implementedMember
                    );
            }

            // In constructed types, it is possible that two method signatures could differ by only ref/out
            // after substitution.  We look for this as part of explicit implementation because, if someone
            // tried to implement the ambiguous interface implicitly, we would separately raise an error about
            // the implicit implementation methods differing by only ref/out.
            FindExplicitImplementationCollisions(
                implementingMember,
                implementedMember,
                diagnostics
                );
        }
        private static Symbol FindExplicitlyImplementedMember(
            Symbol implementingMember,
            TypeSymbol explicitInterfaceType,
            string interfaceMemberName,
            ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifierSyntax,
            DiagnosticBag diagnostics)
        {
            if ((object)explicitInterfaceType == null)
            {
                return(null);
            }

            var memberLocation     = implementingMember.Locations[0];
            var containingType     = implementingMember.ContainingType;
            var containingTypeKind = containingType.TypeKind;

            if (containingTypeKind != TypeKind.Class && containingTypeKind != TypeKind.Struct)
            {
                diagnostics.Add(ErrorCode.ERR_ExplicitInterfaceImplementationInNonClassOrStruct, memberLocation, implementingMember);
                return(null);
            }

            if (!explicitInterfaceType.IsInterfaceType())
            {
                //we'd like to highlight just the type part of the name
                var explicitInterfaceSyntax = explicitInterfaceSpecifierSyntax.Name;
                var location = new SourceLocation(explicitInterfaceSyntax);

                diagnostics.Add(ErrorCode.ERR_ExplicitInterfaceImplementationNotInterface, location, explicitInterfaceType);
                return(null);
            }

            var explicitInterfaceNamedType = (NamedTypeSymbol)explicitInterfaceType;

            // 13.4.1: "For an explicit interface member implementation to be valid, the class or struct must name an
            // interface in its base class list that contains a member ..."
            if (!containingType.InterfacesAndTheirBaseInterfacesNoUseSiteDiagnostics.Contains(explicitInterfaceNamedType))
            {
                //we'd like to highlight just the type part of the name
                var explicitInterfaceSyntax = explicitInterfaceSpecifierSyntax.Name;
                var location = new SourceLocation(explicitInterfaceSyntax);

                diagnostics.Add(ErrorCode.ERR_ClassDoesntImplementInterface, location, implementingMember, explicitInterfaceNamedType);
                //do a lookup anyway
            }

            var hasParamsParam = implementingMember.HasParamsParameter();

            // Setting this flag to true does not imply that an interface member has been successfully implemented.
            // It just indicates that a corresponding interface member has been found (there may still be errors).
            var foundMatchingMember = false;

            Symbol implementedMember = null;

            foreach (Symbol interfaceMember in explicitInterfaceNamedType.GetMembers(interfaceMemberName))
            {
                // At this point, we know that explicitInterfaceNamedType is an interface, so candidate must be public
                // and, therefore, accessible.  So we don't need to check that.
                // However, metadata interface members can be static - we ignore them, as does Dev10.
                if (interfaceMember.Kind != implementingMember.Kind || interfaceMember.IsStatic)
                {
                    continue;
                }

                if (MemberSignatureComparer.ExplicitImplementationComparer.Equals(implementingMember, interfaceMember))
                {
                    foundMatchingMember = true;
                    // Cannot implement accessor directly unless
                    // the accessor is from an indexed property.
                    if (interfaceMember.IsAccessor() && !((MethodSymbol)interfaceMember).IsIndexedPropertyAccessor())
                    {
                        diagnostics.Add(ErrorCode.ERR_ExplicitMethodImplAccessor, memberLocation, implementingMember, interfaceMember);
                    }
                    else
                    {
                        if (interfaceMember.MustCallMethodsDirectly())
                        {
                            diagnostics.Add(ErrorCode.ERR_BogusExplicitImpl, memberLocation, implementingMember, interfaceMember);
                        }
                        else if (hasParamsParam && !interfaceMember.HasParamsParameter())
                        {
                            // Note: no error for !hasParamsParam && interfaceMethod.HasParamsParameter()
                            // Still counts as an implementation.
                            diagnostics.Add(ErrorCode.ERR_ExplicitImplParams, memberLocation, implementingMember, interfaceMember);
                        }

                        implementedMember = interfaceMember;
                        break;
                    }
                }
            }

            if (!foundMatchingMember)
            {
                // CONSIDER: we may wish to suppress this error in the event that another error
                // has been reported about the signature.
                diagnostics.Add(ErrorCode.ERR_InterfaceMemberNotFound, memberLocation, implementingMember);
            }

            if (implementingMember.ContainsTupleNames() && MemberSignatureComparer.ConsideringTupleNamesCreatesDifference(implementingMember, implementedMember))
            {
                // it is ok to explicitly implement with no tuple names, for compatibility with C# 6, but otherwise names should match
                diagnostics.Add(ErrorCode.ERR_ImplBadTupleNames, memberLocation, implementingMember, implementedMember);
            }

            // In constructed types, it is possible that two method signatures could differ by only ref/out
            // after substitution.  We look for this as part of explicit implementation because, if someone
            // tried to implement the ambiguous interface implicitly, we would separately raise an error about
            // the implicit implementation methods differing by only ref/out.
            FindExplicitImplementationCollisions(implementingMember, implementedMember, diagnostics);

            return(implementedMember);
        }