private static Dictionary CreateBuiltInExprConverter()

in System.Data.Entity/System/Data/Common/EntitySql/SemanticAnalyzer.cs [4371:5196]


        private static Dictionary<AST.BuiltInKind, BuiltInExprConverter> CreateBuiltInExprConverter()
        {
            Dictionary<AST.BuiltInKind, BuiltInExprConverter> builtInExprConverter = new Dictionary<AST.BuiltInKind, BuiltInExprConverter>(sizeof(AST.BuiltInKind));

            ////////////////////////////
            // Arithmetic Expressions
            ////////////////////////////

            //
            // e1 + e2
            //
            #region e1 + e2
            builtInExprConverter.Add(AST.BuiltInKind.Plus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertPlusOperands(bltInExpr, sr);

                if (TypeSemantics.IsNumericType(args.Left.ResultType))
                {
                    return args.Left.Plus(args.Right);
                }
                else
                {
                    //
                    // fold '+' operator into concat canonical function
                    //
                    MetadataFunctionGroup function;
                    if (!sr.TypeResolver.TryGetFunctionFromMetadata("Edm", "Concat", out function))
                    {
                        throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, Strings.ConcatBuiltinNotSupported);
                    }

                    List<TypeUsage> argTypes = new List<TypeUsage>(2);
                    argTypes.Add(args.Left.ResultType);
                    argTypes.Add(args.Right.ResultType);

                    bool isAmbiguous = false;
                    EdmFunction concatFunction = SemanticResolver.ResolveFunctionOverloads(
                        function.FunctionMetadata,
                        argTypes,
                        false /* isGroupAggregate */,
                        out isAmbiguous);

                    if (null == concatFunction || isAmbiguous)
                    {
                        throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, Strings.ConcatBuiltinNotSupported);
                    }

                    return concatFunction.Invoke(new[] { args.Left, args.Right });
                }

            });
            #endregion

            //
            // e1 - e2
            //
            #region e1 - e2
            builtInExprConverter.Add(AST.BuiltInKind.Minus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertArithmeticArgs(bltInExpr, sr);

                return args.Left.Minus(args.Right);
            });
            #endregion

            //
            // e1 * e2
            //
            #region e1 * e2
            builtInExprConverter.Add(AST.BuiltInKind.Multiply, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertArithmeticArgs(bltInExpr, sr);

                return args.Left.Multiply(args.Right);
            });
            #endregion

            //
            // e1 / e2
            //
            #region e1 / e2
            builtInExprConverter.Add(AST.BuiltInKind.Divide, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertArithmeticArgs(bltInExpr, sr);

                return args.Left.Divide(args.Right);
            });
            #endregion

            //
            // e1 % e2
            //
            #region e1 % e2
            builtInExprConverter.Add(AST.BuiltInKind.Modulus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertArithmeticArgs(bltInExpr, sr);

                return args.Left.Modulo(args.Right);
            });
            #endregion

            //
            // - e
            //
            #region - e
            builtInExprConverter.Add(AST.BuiltInKind.UnaryMinus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                DbExpression argument = ConvertArithmeticArgs(bltInExpr, sr).Left;
                if (TypeSemantics.IsUnsignedNumericType(argument.ResultType))
                {
                    TypeUsage closestPromotableType = null;
                    if (!TypeHelpers.TryGetClosestPromotableType(argument.ResultType, out closestPromotableType))
                    {
                        throw EntityUtil.EntitySqlError(Strings.InvalidUnsignedTypeForUnaryMinusOperation(argument.ResultType.EdmType.FullName));
                    }
                }

                DbExpression unaryExpr = argument.UnaryMinus();
                return unaryExpr;
            });
            #endregion

            //
            // + e
            //
            #region + e
            builtInExprConverter.Add(AST.BuiltInKind.UnaryPlus, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                return ConvertArithmeticArgs(bltInExpr, sr).Left;
            });
            #endregion

            ////////////////////////////
            // Logical Expressions
            ////////////////////////////

            //
            // e1 AND e2
            // e1 && e2
            //
            #region e1 AND e2
            builtInExprConverter.Add(AST.BuiltInKind.And, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = SemanticAnalyzer.ConvertLogicalArgs(bltInExpr, sr);

                return args.Left.And(args.Right);
            });
            #endregion

            //
            // e1 OR e2
            // e1 || e2
            //
            #region e1 OR e2
            builtInExprConverter.Add(AST.BuiltInKind.Or, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = SemanticAnalyzer.ConvertLogicalArgs(bltInExpr, sr);

                return args.Left.Or(args.Right);
            });
            #endregion

            //
            // NOT e
            // ! e
            //
            #region NOT e
            builtInExprConverter.Add(AST.BuiltInKind.Not, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                return ConvertLogicalArgs(bltInExpr, sr).Left.Not();
            });
            #endregion

            ////////////////////////////
            // Comparison Expressions
            ////////////////////////////

            //
            // e1 == e2 | e1 = e2
            //
            #region e1 == e2
            builtInExprConverter.Add(AST.BuiltInKind.Equal, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertEqualCompArgs(bltInExpr, sr);

                return args.Left.Equal(args.Right);
            });
            #endregion

            //
            // e1 != e2 | e1 <> e2
            //
            #region e1 != e2
            builtInExprConverter.Add(AST.BuiltInKind.NotEqual, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertEqualCompArgs(bltInExpr, sr);

                // 

                return args.Left.Equal(args.Right).Not();
            });
            #endregion

            //
            // e1 >= e2
            //
            #region e1 >= e2
            builtInExprConverter.Add(AST.BuiltInKind.GreaterEqual, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertOrderCompArgs(bltInExpr, sr);

                return args.Left.GreaterThanOrEqual(args.Right);
            });
            #endregion

            //
            // e1 > e2
            //
            #region e1 > e2
            builtInExprConverter.Add(AST.BuiltInKind.GreaterThan, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertOrderCompArgs(bltInExpr, sr);

                return args.Left.GreaterThan(args.Right);
            });
            #endregion

            //
            // e1 <= e2
            //
            #region e1 <= e2
            builtInExprConverter.Add(AST.BuiltInKind.LessEqual, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertOrderCompArgs(bltInExpr, sr);

                return args.Left.LessThanOrEqual(args.Right);
            });
            #endregion

            //
            // e1 < e2
            //
            #region e1 < e2
            builtInExprConverter.Add(AST.BuiltInKind.LessThan, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertOrderCompArgs(bltInExpr, sr);

                return args.Left.LessThan(args.Right);
            });
            #endregion


            ////////////////////////////
            //    SET EXPRESSIONS
            ////////////////////////////


            //
            // e1 UNION e2
            //
            #region e1 UNION e2
            builtInExprConverter.Add(AST.BuiltInKind.Union, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);

                return args.Left.UnionAll(args.Right).Distinct();
            });
            #endregion

            //
            // e1 UNION ALL e2
            //
            #region e1 UNION ALL e2
            builtInExprConverter.Add(AST.BuiltInKind.UnionAll, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);

                return args.Left.UnionAll(args.Right);
            });
            #endregion

            //
            // e1 INTERSECT e2
            //
            #region e1 INTERSECT e2
            builtInExprConverter.Add(AST.BuiltInKind.Intersect, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);

                return args.Left.Intersect(args.Right);
            });
            #endregion

            //
            // e1 OVERLAPS e2
            //
            #region e1 OVERLAPS e1
            builtInExprConverter.Add(AST.BuiltInKind.Overlaps, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);

                return args.Left.Intersect(args.Right).IsEmpty().Not();
            });
            #endregion

            //
            // ANYELEMENT( e )
            //
            #region ANYELEMENT( e )
            builtInExprConverter.Add(AST.BuiltInKind.AnyElement, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                return ConvertSetArgs(bltInExpr, sr).Left.Element();
            });
            #endregion

            //
            // ELEMENT( e )
            //
            #region ELEMENT( e ) - NOT SUPPORTED IN ORCAS TIMEFRAME
            builtInExprConverter.Add(AST.BuiltInKind.Element, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                throw EntityUtil.NotSupported(Strings.ElementOperatorIsNotSupported);
            });
            #endregion

            //
            // e1 EXCEPT e2
            //
            #region e1 EXCEPT e2
            builtInExprConverter.Add(AST.BuiltInKind.Except, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);

                return args.Left.Except(args.Right);
            });
            #endregion

            //
            // EXISTS( e )
            //
            #region EXISTS( e )
            builtInExprConverter.Add(AST.BuiltInKind.Exists, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                return ConvertSetArgs(bltInExpr, sr).Left.IsEmpty().Not();
            });
            #endregion

            //
            // FLATTEN( e )
            //
            #region FLATTEN( e )
            builtInExprConverter.Add(AST.BuiltInKind.Flatten, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                DbExpression elemExpr = ConvertValueExpression(bltInExpr.Arg1, sr);

                if (!TypeSemantics.IsCollectionType(elemExpr.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.InvalidFlattenArgument);
                }

                if (!TypeSemantics.IsCollectionType(TypeHelpers.GetElementTypeUsage(elemExpr.ResultType)))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.InvalidFlattenArgument);
                }

                DbExpressionBinding leftExpr = elemExpr.BindAs(sr.GenerateInternalName("l_flatten"));

                DbExpressionBinding rightExpr = leftExpr.Variable.BindAs(sr.GenerateInternalName("r_flatten"));

                DbExpressionBinding applyBinding = leftExpr.CrossApply(rightExpr).BindAs(sr.GenerateInternalName("flatten"));

                return applyBinding.Project(applyBinding.Variable.Property(rightExpr.VariableName));
            });
            #endregion

            //
            // e1 IN e2
            //
            #region e1 IN e2
            builtInExprConverter.Add(AST.BuiltInKind.In, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertInExprArgs(bltInExpr, sr);

                //
                // Convert "x in multiset(y1, y2, ..., yn)" into x = y1 or x = y2 or x = y3 ...
                //
                if (args.Right.ExpressionKind == DbExpressionKind.NewInstance)
                {
                    return ConvertSimpleInExpression(sr, args.Left, args.Right);
                }
                else
                {
                    DbExpressionBinding rSet = args.Right.BindAs(sr.GenerateInternalName("in-filter"));

                    DbExpression leftIn = args.Left;
                    DbExpression rightSet = rSet.Variable;

                    DbExpression exists = rSet.Filter(leftIn.Equal(rightSet)).IsEmpty().Not();

                    List<DbExpression> whenExpr = new List<DbExpression>(1);
                    whenExpr.Add(leftIn.IsNull());
                    List<DbExpression> thenExpr = new List<DbExpression>(1);
                    thenExpr.Add(DbExpressionBuilder.Null(sr.TypeResolver.BooleanType));

                    DbExpression left = DbExpressionBuilder.Case(whenExpr, thenExpr, DbExpressionBuilder.False);

                    DbExpression converted = left.Or(exists);

                    return converted;
                }
            });
            #endregion

            //
            // e1 NOT IN e1
            //
            #region e1 NOT IN e1
            builtInExprConverter.Add(AST.BuiltInKind.NotIn, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertInExprArgs(bltInExpr, sr);

                if (args.Right.ExpressionKind == DbExpressionKind.NewInstance)
                {
                    return ConvertSimpleInExpression(sr, args.Left, args.Right).Not();
                }
                else
                {
                    DbExpressionBinding rSet = args.Right.BindAs(sr.GenerateInternalName("in-filter"));

                    DbExpression leftIn = args.Left;
                    DbExpression rightSet = rSet.Variable;

                    DbExpression exists = rSet.Filter(leftIn.Equal(rightSet)).IsEmpty();

                    List<DbExpression> whenExpr = new List<DbExpression>(1);
                    whenExpr.Add(leftIn.IsNull());
                    List<DbExpression> thenExpr = new List<DbExpression>(1);
                    thenExpr.Add(DbExpressionBuilder.Null(sr.TypeResolver.BooleanType));

                    DbExpression left = DbExpressionBuilder.Case(whenExpr, thenExpr, DbExpressionBuilder.True);

                    DbExpression converted = left.And(exists);

                    return converted;
                }
            });
            #endregion

            //
            // SET( e ) - DISTINCT( e ) before
            //
            #region SET( e )
            builtInExprConverter.Add(AST.BuiltInKind.Distinct, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                Pair<DbExpression, DbExpression> args = ConvertSetArgs(bltInExpr, sr);

                return args.Left.Distinct();
            });
            #endregion


            ////////////////////////////
            // Nullabity Expressions
            ////////////////////////////

            //
            // e IS NULL
            //
            #region e IS NULL
            builtInExprConverter.Add(AST.BuiltInKind.IsNull, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                DbExpression isNullExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);

                //
                // Ensure expression type is valid for this operation.
                //
                if (isNullExpr != null && !TypeHelpers.IsValidIsNullOpType(isNullExpr.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.IsNullInvalidType);
                }

                return isNullExpr != null ? (DbExpression)isNullExpr.IsNull() : DbExpressionBuilder.True;
            });
            #endregion

            //
            // e IS NOT NULL
            //
            #region e IS NOT NULL
            builtInExprConverter.Add(AST.BuiltInKind.IsNotNull, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                DbExpression isNullExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);

                //
                // Ensure expression type is valid for this operation.
                //
                if (isNullExpr != null && !TypeHelpers.IsValidIsNullOpType(isNullExpr.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.IsNullInvalidType);
                }

                return isNullExpr != null ? (DbExpression)isNullExpr.IsNull().Not() : DbExpressionBuilder.False;
            });
            #endregion

            ////////////////////////////
            //    Type Expressions
            ////////////////////////////

            //
            // e IS OF ( [ONLY] T )
            //
            #region e IS OF ( [ONLY] T )
            builtInExprConverter.Add(AST.BuiltInKind.IsOf, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                var exprToFilter = ConvertValueExpression(bltInExpr.Arg1, sr);
                var typeToFilterTo = ConvertTypeName(bltInExpr.Arg2, sr);

                bool isOnly = (bool)((AST.Literal)bltInExpr.Arg3).Value;
                bool isNot = (bool)((AST.Literal)bltInExpr.Arg4).Value;
                bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode;

                if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(exprToFilter.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
                        Strings.ExpressionTypeMustBeEntityType(Strings.CtxIsOf,
                                                               exprToFilter.ResultType.EdmType.BuiltInTypeKind.ToString(),
                                                               exprToFilter.ResultType.EdmType.FullName));
                }
                else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(exprToFilter.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
                        Strings.ExpressionTypeMustBeNominalType(Strings.CtxIsOf,
                                                                exprToFilter.ResultType.EdmType.BuiltInTypeKind.ToString(),
                                                                exprToFilter.ResultType.EdmType.FullName));
                }

                if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(typeToFilterTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.TypeMustBeEntityType(Strings.CtxIsOf,
                                                                                                        typeToFilterTo.EdmType.BuiltInTypeKind.ToString(),
                                                                                                        typeToFilterTo.EdmType.FullName));
                }
                else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(typeToFilterTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.TypeMustBeNominalType(Strings.CtxIsOf,
                                                                                                         typeToFilterTo.EdmType.BuiltInTypeKind.ToString(),
                                                                                                         typeToFilterTo.EdmType.FullName));
                }

                if (!TypeSemantics.IsPolymorphicType(exprToFilter.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.TypeMustBeInheritableType);
                }

                if (!TypeSemantics.IsPolymorphicType(typeToFilterTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.TypeMustBeInheritableType);
                }

                if (!IsSubOrSuperType(exprToFilter.ResultType, typeToFilterTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.ErrCtx, Strings.NotASuperOrSubType(exprToFilter.ResultType.EdmType.FullName,
                                                                                                 typeToFilterTo.EdmType.FullName));
                }

                typeToFilterTo = TypeHelpers.GetReadOnlyType(typeToFilterTo);

                DbExpression retExpr = null;
                if (isOnly)
                {
                    retExpr = exprToFilter.IsOfOnly(typeToFilterTo);
                }
                else
                {
                    retExpr = exprToFilter.IsOf(typeToFilterTo);
                }

                if (isNot)
                {
                    retExpr = retExpr.Not();
                }

                return retExpr;
            });
            #endregion

            //
            // TREAT( e as T )
            //
            #region TREAT( e as T )
            builtInExprConverter.Add(AST.BuiltInKind.Treat, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                var exprToTreat = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
                var typeToTreatTo = ConvertTypeName(bltInExpr.Arg2, sr);

                bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode;

                if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(typeToTreatTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx,
                        Strings.TypeMustBeEntityType(Strings.CtxTreat,
                                                     typeToTreatTo.EdmType.BuiltInTypeKind.ToString(),
                                                     typeToTreatTo.EdmType.FullName));
                }
                else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(typeToTreatTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx,
                        Strings.TypeMustBeNominalType(Strings.CtxTreat,
                                                      typeToTreatTo.EdmType.BuiltInTypeKind.ToString(),
                                                      typeToTreatTo.EdmType.FullName));
                }

                if (exprToTreat == null)
                {
                    exprToTreat = DbExpressionBuilder.Null(typeToTreatTo);
                }
                else if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(exprToTreat.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
                        Strings.ExpressionTypeMustBeEntityType(Strings.CtxTreat,
                                                               exprToTreat.ResultType.EdmType.BuiltInTypeKind.ToString(),
                                                               exprToTreat.ResultType.EdmType.FullName));
                }
                else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(exprToTreat.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
                        Strings.ExpressionTypeMustBeNominalType(Strings.CtxTreat,
                                                                exprToTreat.ResultType.EdmType.BuiltInTypeKind.ToString(),
                                                                exprToTreat.ResultType.EdmType.FullName));
                }

                if (!TypeSemantics.IsPolymorphicType(exprToTreat.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.TypeMustBeInheritableType);
                }

                if (!TypeSemantics.IsPolymorphicType(typeToTreatTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.TypeMustBeInheritableType);
                }

                if (!IsSubOrSuperType(exprToTreat.ResultType, typeToTreatTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.NotASuperOrSubType(exprToTreat.ResultType.EdmType.FullName,
                                                                                                      typeToTreatTo.EdmType.FullName));
                }

                return exprToTreat.TreatAs(TypeHelpers.GetReadOnlyType(typeToTreatTo));
            });
            #endregion

            //
            // CAST( e AS T )
            //
            #region CAST( e AS T )
            builtInExprConverter.Add(AST.BuiltInKind.Cast, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                var exprToCast = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
                var typeToCastTo = ConvertTypeName(bltInExpr.Arg2, sr);

                //
                // Ensure CAST target type is scalar.
                //
                if (!TypeSemantics.IsScalarType(typeToCastTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.InvalidCastType);
                }

                if (exprToCast == null)
                {
                    return DbExpressionBuilder.Null(typeToCastTo);
                }

                //
                // Ensure CAST source type is scalar.
                //
                if (!TypeSemantics.IsScalarType(exprToCast.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.InvalidCastExpressionType);
                }

                if (!TypeSemantics.IsCastAllowed(exprToCast.ResultType, typeToCastTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.InvalidCast(exprToCast.ResultType.EdmType.FullName, typeToCastTo.EdmType.FullName));
                }

                return exprToCast.CastTo(TypeHelpers.GetReadOnlyType(typeToCastTo));
            });
            #endregion

            //
            // OFTYPE( [ONLY] e, T )
            //
            #region OFTYPE( [ONLY] e, T )
            builtInExprConverter.Add(AST.BuiltInKind.OfType, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                var exprToFilter = ConvertValueExpression(bltInExpr.Arg1, sr);
                var typeToFilterTo = ConvertTypeName(bltInExpr.Arg2, sr);

                bool isOnly = (bool)((AST.Literal)bltInExpr.Arg3).Value;

                bool isNominalTypeAllowed = sr.ParserOptions.ParserCompilationMode == ParserOptions.CompilationMode.RestrictedViewGenerationMode;

                if (!TypeSemantics.IsCollectionType(exprToFilter.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.ExpressionMustBeCollection);
                }

                TypeUsage elementType = TypeHelpers.GetElementTypeUsage(exprToFilter.ResultType);
                if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(elementType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
                        Strings.OfTypeExpressionElementTypeMustBeEntityType(elementType.EdmType.BuiltInTypeKind.ToString(), elementType));
                }
                else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(elementType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx,
                        Strings.OfTypeExpressionElementTypeMustBeNominalType(elementType.EdmType.BuiltInTypeKind.ToString(), elementType));
                }

                if (!isNominalTypeAllowed && !TypeSemantics.IsEntityType(typeToFilterTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx,
                        Strings.TypeMustBeEntityType(Strings.CtxOfType, typeToFilterTo.EdmType.BuiltInTypeKind.ToString(), typeToFilterTo.EdmType.FullName));
                }
                else if (isNominalTypeAllowed && !TypeSemantics.IsNominalType(typeToFilterTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx,
                        Strings.TypeMustBeNominalType(Strings.CtxOfType, typeToFilterTo.EdmType.BuiltInTypeKind.ToString(), typeToFilterTo.EdmType.FullName));
                }

                if (isOnly && typeToFilterTo.EdmType.Abstract)
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.OfTypeOnlyTypeArgumentCannotBeAbstract(typeToFilterTo.EdmType.FullName));
                }

                if (!IsSubOrSuperType(elementType, typeToFilterTo))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.NotASuperOrSubType(elementType.EdmType.FullName, typeToFilterTo.EdmType.FullName));
                }

                DbExpression ofTypeExpression = null;
                if (isOnly)
                {
                    ofTypeExpression = exprToFilter.OfTypeOnly(TypeHelpers.GetReadOnlyType(typeToFilterTo));
                }
                else
                {
                    ofTypeExpression = exprToFilter.OfType(TypeHelpers.GetReadOnlyType(typeToFilterTo));
                }

                return ofTypeExpression;
            });
            #endregion

            //
            // e LIKE pattern [ESCAPE escape]
            //
            #region e LIKE pattern [ESCAPE escape]
            builtInExprConverter.Add(AST.BuiltInKind.Like, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                DbExpression likeExpr = null;

                DbExpression matchExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg1, sr);
                if (matchExpr == null)
                {
                    matchExpr = DbExpressionBuilder.Null(sr.TypeResolver.StringType);
                }
                else if (!IsStringType(matchExpr.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg1.ErrCtx, Strings.LikeArgMustBeStringType);
                }

                DbExpression patternExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg2, sr);
                if (patternExpr == null)
                {
                    patternExpr = DbExpressionBuilder.Null(sr.TypeResolver.StringType);
                }
                else if (!IsStringType(patternExpr.ResultType))
                {
                    throw EntityUtil.EntitySqlError(bltInExpr.Arg2.ErrCtx, Strings.LikeArgMustBeStringType);
                }

                if (3 == bltInExpr.ArgCount)
                {
                    DbExpression escapeExpr = ConvertValueExpressionAllowUntypedNulls(bltInExpr.Arg3, sr);
                    if (escapeExpr == null)
                    {
                        escapeExpr = DbExpressionBuilder.Null(sr.TypeResolver.StringType);
                    }
                    else if (!IsStringType(escapeExpr.ResultType))
                    {
                        throw EntityUtil.EntitySqlError(bltInExpr.Arg3.ErrCtx, Strings.LikeArgMustBeStringType);
                    }

                    likeExpr = matchExpr.Like(patternExpr, escapeExpr);
                }
                else
                {
                    likeExpr = matchExpr.Like(patternExpr);
                }

                return likeExpr;
            });
            #endregion

            //
            // e BETWEEN e1 AND e2
            //
            #region e BETWEEN e1 AND e2
            builtInExprConverter.Add(AST.BuiltInKind.Between, ConvertBetweenExpr);
            #endregion

            //
            // e NOT BETWEEN e1 AND e2
            //
            #region e NOT BETWEEN e1 AND e2
            builtInExprConverter.Add(AST.BuiltInKind.NotBetween, delegate(AST.BuiltInExpr bltInExpr, SemanticResolver sr)
            {
                return ConvertBetweenExpr(bltInExpr, sr).Not();
            });
            #endregion

            return builtInExprConverter;
        }