예제 #1
0
        static ConversionSymbol()
        {
            var conversions = (ConversionKind[])Enum.GetValues(typeof(ConversionKind));

            simpleConv = new ConversionSymbol[conversions.Length];

            foreach (var c in conversions)
            {
                simpleConv[(int)c] = new ConversionSymbol(c);
            }

            convCost = new int[conversions.Length];

#if DEBUG
            foreach (var c in conversions)
            {
                convCost[(int)c] = -1;
            }
#endif

            convCost[(int)ConversionKind.NoConversion]         = 0;
            convCost[(int)ConversionKind.NoImplicitConversion] = 0;

            convCost[(int)ConversionKind.Identity]            = Implicit | 0;
            convCost[(int)ConversionKind.ImplicitEnumeration] = Implicit | 1;
            convCost[(int)ConversionKind.ImplicitNumeric]     = Implicit | 1;
            convCost[(int)ConversionKind.ImplicitNullable]    = Implicit | 2;
            //convCost[(int)ConversionKind.NullLiteral] = Implicit | 0;
            convCost[(int)ConversionKind.ImplicitReference]   = Implicit | 0;
            convCost[(int)ConversionKind.Boxing]              = Implicit | 3;
            convCost[(int)ConversionKind.ImplicitUsual]       = Implicit | 4;
            convCost[(int)ConversionKind.ImplicitUserDefined] = Implicit | 4;
            convCost[(int)ConversionKind.Refer]             = Implicit | 0;
            convCost[(int)ConversionKind.Deref]             = Implicit | 0;
            convCost[(int)ConversionKind.ConstantReduction] = Implicit | 0;

            convCost[(int)ConversionKind.ExplicitEnumeration] = Explicit | 1;
            convCost[(int)ConversionKind.ExplicitNumeric]     = Explicit | 1;
            convCost[(int)ConversionKind.ExplicitNullable]    = Explicit | 2;
            convCost[(int)ConversionKind.ExplicitReference]   = Explicit | 0;
            convCost[(int)ConversionKind.Unboxing]            = Explicit | Cast | 3;
            convCost[(int)ConversionKind.ExplicitUsual]       = Explicit | 4;
            convCost[(int)ConversionKind.ExplicitUserDefined] = Explicit | 4;

#if DEBUG
            foreach (var cost in convCost)
            {
                Debug.Assert(cost >= 0);
            }
#endif
        }
예제 #2
0
 internal static ConversionSymbol ResolveUsualConversion(Expr expr, TypeSymbol type, BindOptions options)
 {
     if (expr.Datatype.NativeType == NativeType.Usual)
     {
         if (type.NativeType == NativeType.Object)
         {
             if (options.HasFlag(BindOptions.BoxUsual))
             {
                 return(ConversionSymbol.Create(ConversionKind.Boxing));
             }
             else
             {
                 MethodSymbol converter = null;
                 ResolveConversionMethod(expr, type, Compilation.Get(NativeType.Usual).Lookup(XSharpFunctionNames.ToObject), ref converter, options);
                 if (converter != null)
                 {
                     return(ConversionSymbol.Create(ConversionKind.ImplicitUserDefined, converter));
                 }
             }
         }
         else
         {
             MethodSymbol converter = null;
             ResolveConversionMethod(expr, Compilation.Get(NativeType.Object), Compilation.Get(NativeType.Usual).Lookup(XSharpFunctionNames.ToObject), ref converter, options);
             if (converter != null)
             {
                 var inner = ConversionSymbol.Create(ConversionKind.ImplicitUserDefined, converter);
                 var outer = type.IsReferenceType ? ConversionSymbol.Create(ConversionKind.ExplicitReference)
                     : type.IsValueType ? ConversionSymbol.Create(ConversionKind.Unboxing)
                     : ConversionSymbol.Create(ConversionKind.NoConversion);
                 if (outer.Exists)
                 {
                     return(ConversionSymbol.Create(outer, inner));
                 }
             }
         }
     }
     else if (type.NativeType == NativeType.Usual && expr.Datatype.IsReferenceType)
     {
         var inner = Conversion(expr, Compilation.Get(NativeType.Object), options | BindOptions.Explicit);
         if (inner.Exists)
         {
             var outer = Conversion(TypeConversion.Bound(expr, Compilation.Get(NativeType.Object), inner), type, options);
             if (outer.Exists)
             {
                 return(ConversionSymbol.Create(outer, inner));
             }
         }
     }
     return(null);
 }
예제 #3
0
        Arg ApplyUsualConversions(ArgList args, out Expr writeBack)
        {
            writeBack = null;
            bool hasRefArgs = false;

            for (int i = 0; i < args.Args.Count; i++)
            {
                var e = args.Args[i].Expr;
                Convert(ref e, Compilation.Get(NativeType.Usual));
                if (args.Args[i].RefKind != RefKind.None)
                {
                    hasRefArgs = true;
                }
            }
            var arguments = new Arg(LiteralArray.Bound(args.Args));

            if (hasRefArgs)
            {
                var conv = ConversionSymbol.Create(ConversionSymbol.Create(ConversionKind.Identity), new ConversionToTemp(arguments.Expr.Datatype));
                Convert(ref arguments.Expr, arguments.Expr.Datatype, conv);
                for (int i = 0; i < args.Args.Count; i++)
                {
                    if (args.Args[i].RefKind != RefKind.None)
                    {
                        HandleVarArgWriteBack(conv, args.Args[i].Expr, i, ref writeBack);
                    }
                }
            }
            return(arguments);

            void HandleVarArgWriteBack(ConversionSymbol conv, Expr e, int i, ref Expr wb)
            {
                if (e.Symbol?.HasSetAccess == true || e is AutoVarExpr || e is AliasExpr)
                {
                    // Handle writeBack
                    Expr t = IdExpr.Bound(conv.IndirectRefConversionTempLocal());
                    t = ArrayAccessExpr.Bound(t, ArgList.Bound(LiteralExpr.Bound(Constant.Create(i + 1))), this);
                    var wc = Conversion(t, e.Datatype, BindOptions.Default);
                    if (wc.Exists)
                    {
                        Convert(ref t, e.Datatype, wc);
                        SymbolExtensions.AddExpr(ref wb, AssignExpr.Bound(e, t, BindOptions.Default));
                    }
                }
            }
        }
예제 #4
0
        internal static bool CheckBinaryOperator(Expr left, Expr right, MethodSymbol m,
                                                 ref ConversionSymbol lconv, ref ConversionSymbol rconv, BindOptions options)
        {
            var method = m.Method;

            if (!m.Method.IsStatic || (options.HasFlag(BindOptions.Special) && !m.Method.IsSpecialName))
            {
                return(false);
            }
            var parameters = method.GetParameters();

            if (parameters.Length != 2)
            {
                return(false);
            }
            var ltype = FindType(parameters[0].ParameterType);
            var rtype = FindType(parameters[1].ParameterType);

            if (TypesMatch(ltype, left.Datatype) && TypesMatch(rtype, right.Datatype))
            {
                lconv = ConversionSymbol.Create(ConversionKind.Identity);
                rconv = ConversionSymbol.Create(ConversionKind.Identity);
                return(true);
            }
            var _lconv = Conversion(left, ltype, options);
            var _rconv = Conversion(right, rtype, options);

            if (_lconv.IsImplicit && _rconv.IsImplicit)
            {
                if (lconv == null && rconv == null)
                {
                    lconv = _lconv;
                    rconv = _rconv;
                    return(true);
                }
                var cost  = lconv?.Cost + rconv?.Cost;
                var _cost = _lconv.Cost + _rconv.Cost;
                if (_cost < cost)
                {
                    lconv = _lconv;
                    rconv = _rconv;
                    return(true);
                }
            }
            return(false);
        }
예제 #5
0
 internal static ConversionSymbol ResolveByRefConversion(Expr expr, TypeSymbol type, BindOptions options)
 {
     if (type.IsByRef && TypesMatch(expr.Datatype, type.ElementType))
     {
         return(ConversionSymbol.CreateByRef());
     }
     else
     {
         var inner = ConversionSymbol.Create(ConversionKind.Deref);
         var outer = Conversion(TypeConversion.Bound(expr, expr.Datatype.ElementType, inner), type, options);
         if (outer.Exists)
         {
             return(ConversionSymbol.Create(outer, inner));
         }
     }
     return(null);
 }
예제 #6
0
 internal ConversionToTemp(ConversionSymbol conv, TypeSymbol type) : base(conv.Kind)
 {
     Conversion = conv; Type = type;
 }
예제 #7
0
 internal ConversionChain(ConversionSymbol conv, ConversionSymbol prev) : base(conv.Kind)
 {
     Conversion = conv; Previous = prev;
 }
예제 #8
0
        void ApplyConversions(ArgList args, OverloadResult ovRes, out Expr writeBack)
        {
            writeBack = null;
            var parameters = ovRes.Parameters.Parameters;

            for (int i = 0; i < ovRes.FixedArgs; i++)
            {
                var conv = ovRes.Conversions[i];
                var e    = args.Args[i].Expr;
                if (conv.Kind != ConversionKind.Identity)
                {
                    Convert(ref args.Args[i].Expr, FindType(parameters[i].ParameterType), conv);
                }
                if (conv is ConversionSymbolToConstant)
                {
                    Convert(ref args.Args[i].Expr, FindType(parameters[i].ParameterType), BindOptions.Default);
                }
                HandleArgWriteBack(conv, e, ref writeBack);
            }
            if (ovRes.MissingArgs > 0)
            {
                for (int i = ovRes.FixedArgs; i < ovRes.FixedArgs + ovRes.MissingArgs; i++)
                {
                    var conv = ovRes.Conversions[i];
                    var a    = new Arg(LiteralExpr.Bound(((ConversionSymbolToConstant)conv).Constant));
                    Convert(ref a.Expr, FindType(parameters[i].ParameterType), BindOptions.Default);
                    args.Args.Add(a);
                }
            }
            else if (ovRes.Parameters.HasParamArray)
            {
                var  varArgs    = new List <Expr>(ovRes.VarArgs);
                var  varArgType = FindType(parameters[ovRes.FixedArgs].ParameterType.GetElementType());
                bool hasRefArgs = false;
                for (int i = ovRes.FixedArgs; i < ovRes.FixedArgs + ovRes.VarArgs; i++)
                {
                    var conv = ovRes.Conversions[i];
                    var e    = args.Args[i].Expr;
                    Convert(ref e, varArgType, conv);
                    varArgs.Add(e);
                    if (args.Args[i].RefKind != RefKind.None)
                    {
                        hasRefArgs = true;
                    }
                }
                var varArg = new Arg(LiteralArray.Bound(varArgs, varArgType));
                if (hasRefArgs)
                {
                    var conv = ConversionSymbol.Create(ConversionSymbol.Create(ConversionKind.Identity), new ConversionToTemp(varArg.Expr.Datatype));
                    Convert(ref varArg.Expr, varArg.Expr.Datatype, conv);
                    for (int i = ovRes.FixedArgs; i < ovRes.FixedArgs + ovRes.VarArgs; i++)
                    {
                        if (args.Args[i].RefKind != RefKind.None)
                        {
                            HandleVarArgWriteBack(conv, args.Args[i].Expr, i - ovRes.FixedArgs, ref writeBack);
                        }
                    }
                }
                while (args.Args.Count > ovRes.FixedArgs)
                {
                    args.Args.RemoveAt(args.Args.Count - 1);
                }
                args.Args.Add(varArg);
            }

            void HandleArgWriteBack(ConversionSymbol conv, Expr e, ref Expr wb)
            {
                if (conv.IsIndirectRefConversion())
                {
                    if (e.Symbol?.HasSetAccess == true || e is AutoVarExpr || e is AliasExpr)
                    {
                        // Handle writeBack
                        Expr t  = IdExpr.Bound(conv.IndirectRefConversionTempLocal());
                        var  wc = Conversion(t, e.Datatype, BindOptions.Default);
                        if (wc.Exists)
                        {
                            Convert(ref t, e.Datatype, wc);
                            SymbolExtensions.AddExpr(ref wb, AssignExpr.Bound(e, t, BindOptions.Default));
                        }
                    }
                }
            }

            void HandleVarArgWriteBack(ConversionSymbol conv, Expr e, int i, ref Expr wb)
            {
                if (e.Symbol?.HasSetAccess == true || e is AutoVarExpr || e is AliasExpr)
                {
                    // Handle writeBack
                    Expr t = IdExpr.Bound(conv.IndirectRefConversionTempLocal());
                    t = ArrayAccessExpr.Bound(t, ArgList.Bound(LiteralExpr.Bound(Constant.Create(i + 1))), this);
                    var wc = Conversion(t, e.Datatype, BindOptions.Default);
                    if (wc.Exists)
                    {
                        Convert(ref t, e.Datatype, wc);
                        SymbolExtensions.AddExpr(ref wb, AssignExpr.Bound(e, t, BindOptions.Default));
                    }
                }
            }
        }
예제 #9
0
        internal static BinaryOperatorSymbol UserDefinedBinaryOperator(BinaryOperatorKind kind, ref Expr left, ref Expr right, BindOptions options)
        {
            MethodSymbol     mop   = null;
            ConversionSymbol lconv = null;
            ConversionSymbol rconv = null;

            bool hasUsual = left.Datatype.NativeType == NativeType.Usual || right.Datatype.NativeType == NativeType.Usual;

            if (options.HasFlag(BindOptions.AllowInexactComparisons))
            {
                bool hasString   = left.Datatype.NativeType == NativeType.String || right.Datatype.NativeType == NativeType.String;
                bool bothStrings = left.Datatype.NativeType == NativeType.String && right.Datatype.NativeType == NativeType.String;

                switch (kind)
                {
                case BinaryOperatorKind.Equal:
                    if (bothStrings)
                    {
                        ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringEquals), ref mop, ref lconv, ref rconv, options);
                    }
                    else if (hasString)
                    {
                        ResolveBinaryOperator(left, right, Compilation.Get(NativeType.Usual).Lookup(OperatorNames.__UsualInExactEquals), ref mop, ref lconv, ref rconv, options);
                    }
                    break;

                case BinaryOperatorKind.NotEqual:
                    if (bothStrings)
                    {
                        ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringNotEquals), ref mop, ref lconv, ref rconv, options);
                    }
                    else if (hasString)
                    {
                        ResolveBinaryOperator(left, right, Compilation.Get(NativeType.Usual).Lookup(OperatorNames.__UsualInExactNotEquals), ref mop, ref lconv, ref rconv, options);
                    }
                    break;

                case BinaryOperatorKind.GreaterThan:
                case BinaryOperatorKind.LessThan:
                case BinaryOperatorKind.GreaterThanOrEqual:
                case BinaryOperatorKind.LessThanOrEqual:
                    if (bothStrings)
                    {
                        ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringCompare), ref mop, ref lconv, ref rconv, options);
                    }
                    break;
                }
            }
            else
            {
                switch (kind)
                {
                case BinaryOperatorKind.Equal:
                case BinaryOperatorKind.NotEqual:
                case BinaryOperatorKind.GreaterThan:
                case BinaryOperatorKind.LessThan:
                case BinaryOperatorKind.GreaterThanOrEqual:
                case BinaryOperatorKind.LessThanOrEqual:
                    if (left.Datatype.NativeType == NativeType.String && right.Datatype.NativeType == NativeType.String)
                    {
                        ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.System_String_CompareOrdinal), ref mop, ref lconv, ref rconv, options);
                    }
                    break;
                }
            }

            if (mop == null)
            {
                var name = BinaryOperatorSymbol.OperatorName(kind);
                if (name != null)
                {
                    ResolveBinaryOperator(left, right, left.Datatype.Lookup(name), ref mop, ref lconv, ref rconv, options | BindOptions.Special);
                    ResolveBinaryOperator(left, right, right.Datatype.Lookup(name), ref mop, ref lconv, ref rconv, options | BindOptions.Special);
                }
            }

            if (mop == null && kind == BinaryOperatorKind.Exponent)
            {
                ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions_POW), ref mop, ref lconv, ref rconv, options);
                if (hasUsual)
                {
                    ResolveBinaryOperator(left, right, left.Datatype.Lookup(OperatorNames.__UsualExponent), ref mop, ref lconv, ref rconv, options);
                    ResolveBinaryOperator(left, right, right.Datatype.Lookup(OperatorNames.__UsualExponent), ref mop, ref lconv, ref rconv, options);
                }
            }

            if (mop != null)
            {
                var op = BinaryOperatorSymbol.Create(kind, mop, lconv, rconv);
                ApplyBinaryOperator(ref left, ref right, op);
                return(op);
            }

            return(null);
        }
예제 #10
0
 internal ConversionToTemp(TypeSymbol type) : base(ConversionKind.ImplicitUserDefined)
 {
     Conversion = ConversionSymbol.Create(ConversionKind.Identity); Type = type; Local = new LocalSymbol(Type);
 }
예제 #11
0
 internal ConversionToTemp(ConversionSymbol conv, TypeSymbol type) : base(conv.Kind == ConversionKind.Identity ? ConversionKind.ImplicitUserDefined : conv.Kind)
 {
     Conversion = conv; Type = type; Local = new LocalSymbol(Type);
 }
예제 #12
0
 internal ConversionChain(ConversionSymbol conv, ConversionSymbol prev) : base(conv.Kind == ConversionKind.Identity ? ConversionKind.ImplicitUserDefined : conv.Kind)
 {
     Conversion = conv; Previous = prev;
 }
예제 #13
0
 internal static UnaryOperatorSymbolWithMethod Create(UnaryOperatorKind kind, MethodSymbol method, ConversionSymbol conv)
 {
     return(new UnaryOperatorSymbolWithMethod(kind, method, conv));
 }
예제 #14
0
 internal UnaryOperatorSymbolWithMethod(UnaryOperatorKind kind, MethodSymbol method,
                                        ConversionSymbol conv) : base(kind, OperandType.Error)
 {
     Method = method;
     Conv   = conv;
 }