コード例 #1
0
ファイル: Binder_QueryErrors.cs プロジェクト: belav/roslyn
        private static bool HasUniqueInterface(
            TypeSymbol instanceType,
            NamedTypeSymbol interfaceType,
            ref bool nonUnique,
            ref CompoundUseSiteInfo <AssemblySymbol> useSiteInfo
            )
        {
            TypeSymbol candidate = null;

            foreach (
                var i in instanceType.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteInfo)
                )
            {
                if (
                    TypeSymbol.Equals(
                        i.OriginalDefinition,
                        interfaceType,
                        TypeCompareKind.ConsiderEverything2
                        )
                    )
                {
                    if ((object)candidate == null)
                    {
                        candidate = i;
                    }
                    else if (!TypeSymbol.Equals(candidate, i, TypeCompareKind.ConsiderEverything2))
                    {
                        nonUnique = true;
                        return(false); // not unique
                    }
                }
            }

            return((object)candidate != null);
        }
コード例 #2
0
 public static bool ImplementsInterface(this TypeSymbol subType, TypeSymbol superInterface, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
 {
     foreach (NamedTypeSymbol @interface in subType.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
     {
         if (@interface.IsInterface && @interface == superInterface)
         {
             return(true);
         }
     }
     return(false);
 }
コード例 #3
0
        /// <summary>
        /// Checks if the given type implements (or extends, in the case of an interface),
        /// System.Collections.IEnumerable or System.Collections.Generic.IEnumerable&lt;T&gt;,
        /// for at least one T.
        /// </summary>
        /// <param name="builder">builder to fill in CollectionType.</param>
        /// <param name="type">Type to check.</param>
        /// <param name="diagnostics" />
        /// <param name="foundMultiple">True if multiple T's are found.</param>
        /// <returns>True if some IEnumerable is found (may still be ambiguous).</returns>
        private bool AllInterfacesContainsIEnumerable(
            ref ForEachEnumeratorInfo.Builder builder,
            TypeSymbol type,
            DiagnosticBag diagnostics,
            out bool foundMultiple)
        {
            Debug.Assert(!IsIEnumerable(type));

            NamedTypeSymbol implementedIEnumerable = null;

            foundMultiple = false;
            HashSet <DiagnosticInfo> useSiteDiagnostics = null;

            if (type.TypeKind == TypeKind.TypeParameter)
            {
                var typeParameter = (TypeParameterSymbol)type;
                GetIEnumerableOfT(typeParameter.EffectiveBaseClass(ref useSiteDiagnostics).AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), ref @implementedIEnumerable, ref foundMultiple);
                GetIEnumerableOfT(typeParameter.AllEffectiveInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), ref @implementedIEnumerable, ref foundMultiple);
            }
            else
            {
                GetIEnumerableOfT(type.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), ref @implementedIEnumerable, ref foundMultiple);
            }

            // Prefer generic to non-generic, unless it is inaccessible.
            if (((object)implementedIEnumerable == null) || !this.IsAccessible(implementedIEnumerable, ref useSiteDiagnostics))
            {
                implementedIEnumerable = null;

                var implementedNonGeneric = this.Compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable);
                if ((object)implementedNonGeneric != null)
                {
                    var conversion = this.Conversions.ClassifyImplicitConversion(type, implementedNonGeneric, ref useSiteDiagnostics);
                    if (conversion.IsImplicit)
                    {
                        implementedIEnumerable = implementedNonGeneric;
                    }
                }
            }

            diagnostics.Add(syntax.Expression, useSiteDiagnostics);

            builder.CollectionType = implementedIEnumerable;
            return((object)implementedIEnumerable != null);
        }
コード例 #4
0
        private static bool HasUniqueInterface(TypeSymbol instanceType, NamedTypeSymbol interfaceType, ref bool nonUnique, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            TypeSymbol candidate = null;

            foreach (var i in instanceType.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
            {
                if (i.OriginalDefinition == interfaceType)
                {
                    if ((object)candidate == null)
                    {
                        candidate = i;
                    }
                    else if (candidate != i)
                    {
                        nonUnique = true;
                        return(false); // not unique
                    }
                }
            }

            return((object)candidate != null);
        }
コード例 #5
0
        private bool GetUserDefinedOperators(UnaryOperatorKind kind, BoundExpression operand, ArrayBuilder <UnaryOperatorAnalysisResult> results, ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert(operand != null);

            if ((object)operand.Type == null)
            {
                // If the operand has no type -- because it is a null reference or a lambda or a method group --
                // there is no way we can determine what type to search for user-defined operators.
                return(false);
            }

            // Spec 7.3.5 Candidate user-defined operators
            // SPEC: Given a type T and an operation op(A) ... the set of candidate user-defined
            // SPEC: operators provided by T for op(A) is determined as follows:

            // SPEC: If T is a nullable type then T0 is its underlying type; otherwise T0 is T.
            // SPEC: For all operator declarations in T0 and all lifted forms of such operators, if
            // SPEC: at least one operator is applicable with respect to A then the set of candidate
            // SPEC: operators consists of all such applicable operators. Otherwise, if T0 is object
            // SPEC: then the set of candidate operators is empty. Otherwise, the set of candidate
            // SPEC: operators is the set provided by the direct base class of T0, or the effective
            // SPEC: base class of T0 if T0 is a type parameter.

            // https://github.com/dotnet/roslyn/issues/34451: The spec quote should be adjusted to cover operators from interfaces as well.
            // From https://github.com/dotnet/csharplang/blob/master/meetings/2017/LDM-2017-06-27.md:
            // - We only even look for operator implementations in interfaces if one of the operands has a type that is an interface or
            // a type parameter with a non-empty effective base interface list.
            // - The applicable operators from classes / structs shadow those in interfaces.This matters for constrained type parameters:
            // the effective base class can shadow operators from effective base interfaces.
            // - If we find an applicable candidate in an interface, that candidate shadows all applicable operators in base interfaces:
            // we stop looking.

            TypeSymbol type0 = operand.Type.StrippedType();

            // Searching for user-defined operators is expensive; let's take an early out if we can.
            if (OperatorFacts.DefinitelyHasNoUserDefinedOperators(type0))
            {
                return(false);
            }

            string name      = OperatorFacts.UnaryOperatorNameFromOperatorKind(kind);
            var    operators = ArrayBuilder <UnaryOperatorSignature> .GetInstance();

            bool hadApplicableCandidates = false;

            NamedTypeSymbol current = type0 as NamedTypeSymbol;

            if ((object)current == null)
            {
                current = type0.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
            }

            if ((object)current == null && type0.IsTypeParameter())
            {
                current = ((TypeParameterSymbol)type0).EffectiveBaseClass(ref useSiteDiagnostics);
            }

            for (; (object)current != null; current = current.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
            {
                operators.Clear();
                GetUserDefinedUnaryOperatorsFromType(current, kind, name, operators);
                results.Clear();
                if (CandidateOperators(operators, operand, results, ref useSiteDiagnostics))
                {
                    hadApplicableCandidates = true;
                    break;
                }
            }

            // Look in base interfaces, or effective interfaces for type parameters
            if (!hadApplicableCandidates)
            {
                ImmutableArray <NamedTypeSymbol> interfaces = default;
                if (type0.IsInterfaceType())
                {
                    interfaces = type0.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
                }
                else if (type0.IsTypeParameter())
                {
                    interfaces = ((TypeParameterSymbol)type0).AllEffectiveInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
                }

                if (!interfaces.IsDefaultOrEmpty)
                {
                    var shadowedInterfaces = PooledHashSet <NamedTypeSymbol> .GetInstance();

                    var resultsFromInterface = ArrayBuilder <UnaryOperatorAnalysisResult> .GetInstance();

                    results.Clear();

                    foreach (NamedTypeSymbol @interface in interfaces)
                    {
                        if ([email protected])
                        {
                            // this code could be reachable in error situations
                            continue;
                        }

                        if (shadowedInterfaces.Contains(@interface))
                        {
                            // this interface is "shadowed" by a derived interface
                            continue;
                        }

                        operators.Clear();
                        resultsFromInterface.Clear();
                        GetUserDefinedUnaryOperatorsFromType(@interface, kind, name, operators);
                        if (CandidateOperators(operators, operand, resultsFromInterface, ref useSiteDiagnostics))
                        {
                            hadApplicableCandidates = true;
                            results.AddRange(resultsFromInterface);

                            // this interface "shadows" all its base interfaces
                            shadowedInterfaces.AddAll(@interface.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics));
                        }
                    }

                    shadowedInterfaces.Free();
                    resultsFromInterface.Free();
                }
            }

            operators.Free();

            return(hadApplicableCandidates);
        }
コード例 #6
0
        private bool UpperBoundInterfaceInference(NamedTypeSymbol source, TypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert((object)source != null);
            Debug.Assert((object)target != null);

            if (!source.IsInterface)
            {
                return false;
            }

            // SPEC: * Otherwise, if U [source] is an interface type C<U1...Uk> and V [target] is a class type
            // SPEC:   or struct type and there is a unique set V1...Vk such that V directly 
            // SPEC:   or indirectly implements C<V1...Vk> then an exact ...
            // SPEC: * ... and U is an interface type ...

            switch (target.TypeKind)
            {
                case TypeKind.Struct:
                case TypeKind.Class:
                case TypeKind.Interface:
                    break;

                default:
                    return false;
            }

            NamedTypeSymbol bestInterface = GetInterfaceInferenceBound(target.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), source);
            if ((object)bestInterface == null)
            {
                return false;
            }

            UpperBoundTypeArgumentInference(source, bestInterface, ref useSiteDiagnostics);
            return true;
        }
コード例 #7
0
        private bool LowerBoundInterfaceInference(TypeSymbol source, NamedTypeSymbol target, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            Debug.Assert((object)source != null);
            Debug.Assert((object)target != null);

            if (!target.IsInterface)
            {
                return false;
            }

            // Spec 7.5.2.9 Lower-bound interfaces
            // SPEC: * Otherwise, if V [target] is an interface type C<V1...Vk> and U [source] is a class type
            // SPEC:   or struct type and there is a unique set U1...Uk such that U directly 
            // SPEC:   or indirectly implements C<U1...Uk> then an
            // SPEC:   exact, upper-bound, or lower-bound inference ...
            // SPEC: * ... and U is an interface type ...
            // SPEC: * ... and U is a type parameter ...

            ImmutableArray<NamedTypeSymbol> allInterfaces;
            switch (source.TypeKind)
            {
                case TypeKind.Struct:
                case TypeKind.Class:
                case TypeKind.Interface:
                    allInterfaces = source.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics);
                    break;

                case TypeKind.TypeParameter:
                    var typeParameter = (TypeParameterSymbol)source;
                    allInterfaces = typeParameter.EffectiveBaseClass(ref useSiteDiagnostics).
                                        AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics).
                                        Concat(typeParameter.AllEffectiveInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics));
                    break;

                default:
                    return false;
            }

            NamedTypeSymbol matchingInterface = GetInterfaceInferenceBound(allInterfaces, target);
            if ((object)matchingInterface == null)
            {
                return false;
            }
            LowerBoundTypeArgumentInference(matchingInterface, target, ref useSiteDiagnostics);
            return true;
        }
コード例 #8
0
        private static bool HasUniqueInterface(TypeSymbol instanceType, NamedTypeSymbol interfaceType, ref bool nonUnique, ref HashSet<DiagnosticInfo> useSiteDiagnostics)
        {
            TypeSymbol candidate = null;
            foreach (var i in instanceType.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics))
            {
                if (i.OriginalDefinition == interfaceType)
                {
                    if ((object)candidate == null)
                    {
                        candidate = i;
                    }
                    else if (candidate != i)
                    {
                        nonUnique = true;
                        return false; // not unique
                    }
                }
            }

            return (object)candidate != null;
        }
コード例 #9
0
ファイル: ForEachLoopBinder.cs プロジェクト: RoryVL/roslyn
        /// <summary>
        /// Checks if the given type implements (or extends, in the case of an interface),
        /// System.Collections.IEnumerable or System.Collections.Generic.IEnumerable&lt;T&gt;,
        /// for at least one T.
        /// </summary>
        /// <param name="builder">builder to fill in CollectionType.</param>
        /// <param name="type">Type to check.</param>
        /// <param name="diagnostics" />
        /// <param name="foundMultiple">True if multiple T's are found.</param>
        /// <returns>True if some IEnumerable is found (may still be ambiguous).</returns>
        private bool AllInterfacesContainsIEnumerable(
            ref ForEachEnumeratorInfo.Builder builder,
            TypeSymbol type,
            DiagnosticBag diagnostics,
            out bool foundMultiple)
        {
            Debug.Assert(!IsIEnumerable(type));

            NamedTypeSymbol implementedIEnumerable = null;
            foundMultiple = false;
            HashSet<DiagnosticInfo> useSiteDiagnostics = null;

            if (type.TypeKind == TypeKind.TypeParameter)
            {
                var typeParameter = (TypeParameterSymbol)type;
                GetIEnumerableOfT(typeParameter.EffectiveBaseClass(ref useSiteDiagnostics).AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), ref @implementedIEnumerable, ref foundMultiple);
                GetIEnumerableOfT(typeParameter.AllEffectiveInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), ref @implementedIEnumerable, ref foundMultiple);
            }
            else
            {
                GetIEnumerableOfT(type.AllInterfacesWithDefinitionUseSiteDiagnostics(ref useSiteDiagnostics), ref @implementedIEnumerable, ref foundMultiple);
            }

            // Prefer generic to non-generic, unless it is inaccessible.
            if (((object)implementedIEnumerable == null) || !this.IsAccessible(implementedIEnumerable, ref useSiteDiagnostics))
            {
                implementedIEnumerable = null;

                var implementedNonGeneric = this.Compilation.GetSpecialType(SpecialType.System_Collections_IEnumerable);
                if ((object)implementedNonGeneric != null)
                {
                    var conversion = this.Conversions.ClassifyImplicitConversion(type, implementedNonGeneric, ref useSiteDiagnostics);
                    if (conversion.IsImplicit)
                    {
                        implementedIEnumerable = implementedNonGeneric;
                    }
                }
            }

            diagnostics.Add(_syntax.Expression, useSiteDiagnostics);

            builder.CollectionType = implementedIEnumerable;
            return (object)implementedIEnumerable != null;
        }