Exemple #1
0
        internal static ConversionSymbol VarArgumentConversion(Arg arg, TypeSymbol type, BindOptions options)
        {
            if (arg == null || arg.Expr is EmptyExpr)
            {
                return(ConversionSymbol.Create(Constant.CreateDefault(type)));
            }
            var conv = Conversion(arg.Expr, type, options);

            return(conv);
        }
 internal static ConversionSymbol ResolveDynamicConversion(Expr expr, TypeSymbol type, BindOptions options)
 {
     if (expr.Datatype.NativeType == NativeType.Object)
     {
         var inner = Conversion(expr, Compilation.Get(NativeType.Usual), options);
         var outer = Conversion(TypeConversion.Bound(expr, Compilation.Get(NativeType.Usual), inner), type, options);
         if (outer.Exists)
         {
             return(ConversionSymbol.Create(outer, inner));
         }
     }
     return(null);
 }
 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);
 }
        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));
                    }
                }
            }
        }
Exemple #5
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);
        }
 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);
 }
Exemple #7
0
        internal static bool CheckUnaryOperator(Expr expr, MethodSymbol m, ref ConversionSymbol conv, BindOptions options, bool needSpecialName = true)
        {
            var method = m.Method;

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

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

            if (TypesMatch(type, expr.Datatype))
            {
                conv = ConversionSymbol.Create(ConversionKind.Identity);
                return(true);
            }
            var _conv = Conversion(expr, type, options);

            if (_conv.IsImplicit)
            {
                if (conv == null)
                {
                    conv = _conv;
                    return(true);
                }
                var cost  = conv?.Cost;
                var _cost = _conv.Cost;
                if (_cost < cost)
                {
                    conv = _conv;
                    return(true);
                }
            }
            return(false);
        }
 internal static ConversionSymbol ResolveEnumConversion(Expr expr, TypeSymbol type, BindOptions options)
 {
     if (expr.Datatype.IsEnum)
     {
         if (TypesMatch(expr.Datatype.EnumUnderlyingType, type))
         {
             return(ConversionSymbol.Create(ConversionKind.ImplicitEnumeration));
         }
         else
         {
             var inner = ConversionSymbol.Create(ConversionKind.ImplicitEnumeration);
             var outer = Conversion(TypeConversion.Bound(expr, expr.Datatype.EnumUnderlyingType, inner), type, options);
             if (outer.Exists)
             {
                 return(ConversionSymbol.Create(outer, inner));
             }
         }
     }
     if (type.IsEnum && options.HasFlag(BindOptions.Explicit))
     {
         if (TypesMatch(type.EnumUnderlyingType, expr.Datatype))
         {
             return(ConversionSymbol.Create(ConversionKind.ExplicitEnumeration));
         }
         else
         {
             var inner = Conversion(expr, type.EnumUnderlyingType, options);
             if (inner.Exists)
             {
                 var outer = ConversionSymbol.Create(ConversionKind.ExplicitEnumeration);
                 return(ConversionSymbol.Create(outer, inner));
             }
         }
     }
     return(null);
 }
Exemple #9
0
        internal static ConversionSymbol ArgumentConversion(Arg arg, ParameterInfo param, BindOptions options)
        {
            if (arg == null || arg.Expr is EmptyExpr)
            {
                var type = FindType(param.ParameterType);
                if (param.HasDefaultValue && type.NativeType != NativeType.Unknown)
                {
                    return(ConversionSymbol.Create(Constant.Create(param.DefaultValue, type.NativeType)));
                }
                else if (param.HasDefaultValue || param.IsOptional)
                {
                    return(ConversionSymbol.Create(Constant.CreateDefault(type)));
                }
                else
                {
                    var defValAttr = Compilation.Get(WellKnownTypes.DefaultParameterValueAttribute);
                    foreach (var attr in param.CustomAttributes)
                    {
                        if (attr.AttributeType == defValAttr.Type)
                        {
                            int desc = attr.ConstructorArguments[1].Value as int? ?? -1;

                            var val = attr.ConstructorArguments[0];
                            switch (desc)
                            {
                            case 0:
                                // normal .Net Object
                                // return value  or null
                                if (val.ArgumentType != null && val.Value != null)
                                {
                                    var valType = FindType(val.ArgumentType);
                                    if (valType.NativeType == NativeType.Unknown)
                                    {
                                        // Enum type? can be casted to Int32
                                        return(ConversionSymbol.Create(Constant.Create(val.Value, NativeType.Int32)));
                                    }
                                    else
                                    {
                                        return(ConversionSymbol.Create(Constant.Create(val.Value, valType.NativeType)));
                                    }
                                }
                                else
                                {
                                    return(ConversionSymbol.Create(Constant.Null));
                                }

                            case 1:
                                // NIL
                                return(ConversionSymbol.Create(Constant.Nil));

                            case 2:
                                // Date, value should be long of ticks. Return DateTime
                                DateTime dt = new DateTime((long)val.Value);
                                return(ConversionSymbol.Create(Constant.Create(dt)));

                            case 3:
                                // Symbol, value should be a string literal or null
                                if (val.Value == null)
                                {
                                    return(ConversionSymbol.Create(Constant.Null));
                                }
                                else
                                {
                                    return(ConversionSymbol.Create(Constant.Create((string)val.Value)));
                                }

                            case 4:
                                // Psz, value should be a string or null
                                if (val.Value == null)
                                {
                                    return(ConversionSymbol.Create(Constant.Null));
                                }
                                else
                                {
                                    return(ConversionSymbol.Create(Constant.Create((string)val.Value)));
                                }

                            case 5:
                                // IntPtr, return value as IntPtr
                                if (val.Value == null)
                                {
                                    return(ConversionSymbol.Create(Constant.Null));
                                }
                                else
                                {
                                    int    i = val.Value as int? ?? 0;
                                    IntPtr p = new IntPtr(i);
                                    return(ConversionSymbol.Create(Constant.Create(p)));
                                }

                            default:
                                return(ConversionSymbol.Create(Constant.Null));
                            }
                        }
                    }
                }
                return(ConversionSymbol.Create(ConversionKind.NoConversion));
            }
            var conv = Conversion(arg.Expr, FindType(param.ParameterType), options);

            return(conv);
        }
        internal static ConversionSymbol Conversion(Expr expr, TypeSymbol type, BindOptions options)
        {
            var noConversion = ConversionKind.NoConversion;

            var conversion = ConversionEasyOut.ClassifyConversion(expr.Datatype, type);

            if (expr.Symbol.IsConstant() || expr.IsConstant)
            {
                options |= BindOptions.Explicit;
            }

            if (conversion != ConversionKind.NoConversion)
            {
                var conv = ConversionSymbol.Create(conversion);
                if (!conv.IsCast && options.HasFlag(BindOptions.Explicit) || conv.IsImplicit)
                {
                    return(conv);
                }
                if (conv.IsCast && options.HasFlag(BindOptions.Cast))
                {
                    return(conv);
                }
                if (conv.IsExplicit && conv.Kind == ConversionKind.ExplicitNumeric && options.HasFlag(BindOptions.AllowImplicitNarrowingConversions))
                {
                    return(conv); // TODO nvk: this should raise a warning!
                }
                if (conv.Exists)
                {
                    noConversion = ConversionKind.NoImplicitConversion;
                }
            }

            if (TypesMatch(expr.Datatype, type))
            {
                return(ConversionSymbol.Create(ConversionKind.Identity));
            }

            if (type.Type.IsGenericType || expr.Datatype.Type.IsGenericType)
            {
                return(ConversionSymbol.Create(noConversion));
            }

            MethodSymbol converter = null;

            ResolveUserDefinedConversion(expr, type, expr.Datatype.Lookup(OperatorNames.Implicit), type.Lookup(OperatorNames.Implicit), ref converter, options | BindOptions.Special);
            if (converter != null)
            {
                return(ConversionSymbol.Create(ConversionKind.ImplicitUserDefined, converter));
            }

            if (options.HasFlag(BindOptions.Explicit))
            {
                ResolveUserDefinedConversion(expr, type, expr.Datatype.Lookup(OperatorNames.Explicit), type.Lookup(OperatorNames.Explicit), ref converter, options | BindOptions.Special);
                if (converter != null)
                {
                    return(ConversionSymbol.Create(ConversionKind.ExplicitUserDefined, converter));
                }
            }

            {
                var conv = ResolveUsualConversion(expr, type, options);
                if (conv != null)
                {
                    return(conv);
                }
            }

            if (type.IsByRef != expr.Datatype.IsByRef)
            {
                var conv = ResolveByRefConversion(expr, type, options);
                if (conv != null)
                {
                    return(conv);
                }
            }

            if (type.NativeType == NativeType.Object)
            {
                if (expr.Datatype.Type.IsValueType)
                {
                    return(ConversionSymbol.Create(ConversionKind.Boxing));
                }
                else
                {
                    return(ConversionSymbol.Create(ConversionKind.ImplicitReference));
                }
            }
            else if (expr.Datatype.NativeType == NativeType.Object)
            {
                if (!options.HasFlag(BindOptions.AllowDynamic))
                {
                    if (options.HasFlag(BindOptions.Explicit))
                    {
                        return(type.IsValueType ? ConversionSymbol.Create(ConversionKind.Unboxing) : ConversionSymbol.Create(ConversionKind.ExplicitReference));
                    }
                    else
                    {
                        noConversion = ConversionKind.NoImplicitConversion;
                    }
                }
            }
            else if (type.IsReferenceType && expr.Datatype.IsReferenceType)
            {
                if (expr.Datatype.IsSubclassOf(type))
                {
                    return(ConversionSymbol.Create(ConversionKind.ImplicitReference));
                }
                if (type.IsSubclassOf(expr.Datatype))
                {
                    if (options.HasFlag(BindOptions.Explicit))
                    {
                        return(ConversionSymbol.Create(ConversionKind.ExplicitReference));
                    }
                    else
                    {
                        noConversion = ConversionKind.NoImplicitConversion;
                    }
                }
            }

            {
                var conv = ResolveEnumConversion(expr, type, options);
                if (conv != null)
                {
                    return(conv);
                }
            }

            if (options.HasFlag(BindOptions.AllowDynamic))
            {
                var conv = ResolveDynamicConversion(expr, type, options);
                if (conv != null)
                {
                    return(conv);
                }
            }

            if (!options.HasFlag(BindOptions.Explicit) && noConversion == ConversionKind.NoConversion)
            {
                ResolveUserDefinedConversion(expr, type, expr.Datatype.Lookup(OperatorNames.Explicit), type.Lookup(OperatorNames.Explicit), ref converter, options | BindOptions.Special);
                if (converter != null)
                {
                    noConversion = ConversionKind.NoImplicitConversion;
                }
            }

            return(ConversionSymbol.Create(noConversion));
        }
        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));
                    }
                }
            }
        }
Exemple #12
0
 internal ConversionToTemp(TypeSymbol type) : base(ConversionKind.ImplicitUserDefined)
 {
     Conversion = ConversionSymbol.Create(ConversionKind.Identity); Type = type; Local = new LocalSymbol(Type);
 }