Esempio n. 1
0
        /// <summary>
        /// Returns the better type amongst the two, with some possible modifications (dynamic/object or tuple names).
        /// </summary>
        private static TypeSymbol Better(
            TypeSymbol type1,
            TypeSymbol type2,
            ConversionsBase conversions,
            ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            // Anything is better than an error sym.
            if (type1.IsErrorType())
            {
                return(type2);
            }

            if ((object)type2 == null || type2.IsErrorType())
            {
                return(type1);
            }

            var conversionsWithoutNullability = conversions.WithNullability(false);
            var t1tot2 = conversionsWithoutNullability.ClassifyImplicitConversionFromType(type1, type2, ref useSiteDiagnostics).Exists;
            var t2tot1 = conversionsWithoutNullability.ClassifyImplicitConversionFromType(type2, type1, ref useSiteDiagnostics).Exists;

            if (t1tot2 && t2tot1)
            {
                if (type1.IsDynamic())
                {
                    return(type1);
                }

                if (type2.IsDynamic())
                {
                    return(type2);
                }

                if (type1.Equals(type2, TypeCompareKind.IgnoreDynamicAndTupleNames | TypeCompareKind.IgnoreNullableModifiersForReferenceTypes))
                {
                    return(MethodTypeInferrer.Merge(
                               TypeWithAnnotations.Create(type1),
                               TypeWithAnnotations.Create(type2),
                               VarianceKind.Out,
                               conversions).Type);
                }

                return(null);
            }

            if (t1tot2)
            {
                return(type2);
            }

            if (t2tot1)
            {
                return(type1);
            }

            return(null);
        }
Esempio n. 2
0
        /// <remarks>
        /// This method implements best type inference for the conditional operator ?:.
        /// NOTE: If either expression is an error type, we return error type as the inference result.
        /// </remarks>
        public static TypeSymbol InferBestTypeForConditionalOperator(
            BoundExpression expr1,
            BoundExpression expr2,
            ConversionsBase conversions,
            out bool hadMultipleCandidates,
            ref HashSet <DiagnosticInfo> useSiteDiagnostics)
        {
            // SPEC:    The second and third operands, x and y, of the ?: operator control the type of the conditional expression.
            // SPEC:    •	If x has type X and y has type Y then
            // SPEC:        o	If an implicit conversion (§6.1) exists from X to Y, but not from Y to X, then Y is the type of the conditional expression.
            // SPEC:        o	If an implicit conversion (§6.1) exists from Y to X, but not from X to Y, then X is the type of the conditional expression.
            // SPEC:        o	Otherwise, no expression type can be determined, and a compile-time error occurs.
            // SPEC:    •	If only one of x and y has a type, and both x and y, are implicitly convertible to that type, then that is the type of the conditional expression.
            // SPEC:    •	Otherwise, no expression type can be determined, and a compile-time error occurs.

            // A type is a candidate if all expressions are convertible to that type.
            ArrayBuilder <TypeSymbol> candidateTypes = ArrayBuilder <TypeSymbol> .GetInstance();

            try
            {
                var        conversionsWithoutNullability = conversions.WithNullability(false);
                TypeSymbol type1 = expr1.Type;

                if ((object)type1 != null)
                {
                    if (type1.IsErrorType())
                    {
                        hadMultipleCandidates = false;
                        return(type1);
                    }

                    if (conversionsWithoutNullability.ClassifyImplicitConversionFromExpression(expr2, type1, ref useSiteDiagnostics).Exists)
                    {
                        candidateTypes.Add(type1);
                    }
                }

                TypeSymbol type2 = expr2.Type;

                if ((object)type2 != null)
                {
                    if (type2.IsErrorType())
                    {
                        hadMultipleCandidates = false;
                        return(type2);
                    }

                    if (conversionsWithoutNullability.ClassifyImplicitConversionFromExpression(expr1, type2, ref useSiteDiagnostics).Exists)
                    {
                        candidateTypes.Add(type2);
                    }
                }

                hadMultipleCandidates = candidateTypes.Count > 1;

                return(GetBestType(candidateTypes, conversions, ref useSiteDiagnostics));
            }
            finally
            {
                candidateTypes.Free();
            }
        }