예제 #1
0
        private static bool IsVarianceUnsafe <T>(
            TypeSymbol type,
            bool requireOutputSafety,
            bool requireInputSafety,
            Symbol context,
            LocationProvider <T> locationProvider,
            T locationArg,
            BindingDiagnosticBag diagnostics)
            where T : Symbol
        {
            Debug.Assert(requireOutputSafety || requireInputSafety);

            // A type T is "output-unsafe" ["input-unsafe"] if one of the following holds:
            switch (type.Kind)
            {
            case SymbolKind.TypeParameter:
                // 1) T is a contravariant [covariant] type parameter
                TypeParameterSymbol typeParam = (TypeParameterSymbol)type;
                if (requireInputSafety && requireOutputSafety && typeParam.Variance != VarianceKind.None)
                {
                    // This sub-case isn't mentioned in the spec, because it's not required for
                    // the definition.  It just allows us to give a better error message for
                    // type parameters that are both output-unsafe and input-unsafe.
                    diagnostics.AddVarianceError(typeParam, context, locationProvider, locationArg, MessageID.IDS_Invariantly);
                    return(true);
                }
                else if (requireOutputSafety && typeParam.Variance == VarianceKind.In)
                {
                    // The is output-unsafe case (1) from the spec.
                    diagnostics.AddVarianceError(typeParam, context, locationProvider, locationArg, MessageID.IDS_Covariantly);
                    return(true);
                }
                else if (requireInputSafety && typeParam.Variance == VarianceKind.Out)
                {
                    // The is input-unsafe case (1) from the spec.
                    diagnostics.AddVarianceError(typeParam, context, locationProvider, locationArg, MessageID.IDS_Contravariantly);
                    return(true);
                }
                else
                {
                    return(false);
                }

            case SymbolKind.ArrayType:
                // 2) T is an array type with an output-unsafe [input-unsafe] element type
                return(IsVarianceUnsafe(((ArrayTypeSymbol)type).ElementType, requireOutputSafety, requireInputSafety, context, locationProvider, locationArg, diagnostics));

            case SymbolKind.ErrorType:
            case SymbolKind.NamedType:
                var namedType = (NamedTypeSymbol)type;
                // 3) (see IsVarianceUnsafe(NamedTypeSymbol))
                return(IsVarianceUnsafe(namedType, requireOutputSafety, requireInputSafety, context, locationProvider, locationArg, diagnostics));

            default:
                return(false);
            }
        }