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); }
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); }
/// <summary> /// Checks if the given type implements (or extends, in the case of an interface), /// System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T>, /// 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); }
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); }
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); }
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; }
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; }
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; }
/// <summary> /// Checks if the given type implements (or extends, in the case of an interface), /// System.Collections.IEnumerable or System.Collections.Generic.IEnumerable<T>, /// 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; }