public XamlIlNodeEmitResult Emit(IXamlIlAstNode value, IXamlIlCodeGen codeGen, IXamlIlType expectedType)
        {
            var res          = EmitCore(value, codeGen);
            var returnedType = res.ReturnType;

            if (returnedType != null || expectedType != null)
            {
                if (returnedType != null && expectedType == null)
                {
                    throw new XamlIlLoadException(
                              $"Emit of node {value} resulted in {returnedType.GetFqn()} while caller expected void", value);
                }

                if (expectedType != null && returnedType == null)
                {
                    throw new XamlIlLoadException(
                              $"Emit of node {value} resulted in void while caller expected {expectedType.GetFqn()}", value);
                }

                if (!expectedType.IsAssignableFrom(returnedType))
                {
                    throw new XamlIlLoadException(
                              $"Emit of node {value} resulted in  {returnedType.GetFqn()} which is not convertible to expected {expectedType.GetFqn()}",
                              value);
                }

                if (returnedType.IsValueType && !expectedType.IsValueType)
                {
                    codeGen.Generator.Emit(OpCodes.Box, returnedType);
                }
            }

            return(res);
        }
Пример #2
0
 public static bool IsDirectlyAssignableFrom(this IXamlIlType type, IXamlIlType other)
 {
     if (type.IsValueType || other.IsValueType)
     {
         return(type.Equals(other));
     }
     return(type.IsAssignableFrom(other));
 }
Пример #3
0
        public static bool TryGetCorrectlyTypedValue(XamlIlAstTransformationContext context,
                                                     IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode rv)
        {
            if (type.IsAssignableFrom(node.Type.GetClrType()))
            {
                rv = node;
                return(true);
            }

            return(TryConvertValue(context, node, type, null, out rv));
        }
Пример #4
0
 public static void EmitConvert(XamlIlEmitContext context, IXamlIlLineInfo node, IXamlIlType what,
                                IXamlIlType to, Func <bool, IXamlIlEmitter> ld)
 {
     if (what.Equals(to))
     {
         ld(false);
     }
     else if (what == XamlIlPseudoType.Null)
     {
         if (to.IsValueType)
         {
             if (to.GenericTypeDefinition?.Equals(context.Configuration.WellKnownTypes.NullableT) == true)
             {
                 using (var loc = context.GetLocal(to))
                     ld(false)
                     .Pop()
                     .Ldloca(loc.Local)
                     .Emit(OpCodes.Initobj, to)
                     .Ldloc(loc.Local);
             }
             else
             {
                 throw new XamlIlLoadException("Unable to convert {x:Null} to " + to.GetFqn(), node);
             }
         }
         else
         {
             ld(false);
         }
     }
     else if (what.IsValueType && to.IsValueType)
     {
         if (to.IsNullableOf(what))
         {
             ld(false).Emit(OpCodes.Newobj,
                            to.Constructors.First(c =>
                                                  c.Parameters.Count == 1 && c.Parameters[0].Equals(what)));
         }
         else if (what.IsNullableOf(what))
         {
             ld(true)
             .EmitCall(what.FindMethod(m => m.Name == "get_Value"));
         }
         else
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert value type {what.GetFullName()} to value type {to.GetFullName()}",
                       node);
         }
     }
     else if (!to.IsValueType && what.IsValueType)
     {
         if (!to.IsAssignableFrom(what))
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert value type {what.GetFullName()} to reference type {to.GetFullName()}",
                       node);
         }
         ld(false).Box(what);
     }
     else if (to.IsValueType && !what.IsValueType)
     {
         if (!(what.Namespace == "System" && what.Name == "Object"))
         {
             throw new XamlIlLoadException(
                       $"Don't know how to convert reference type {what.GetFullName()} to value type {to.GetFullName()}",
                       node);
         }
         ld(false).Unbox_Any(to);
     }
     else
     {
         if (to.IsAssignableFrom(what))
         {
             // Downcast, always safe
             ld(false);
         }
         else if (what.IsInterface || what.IsAssignableFrom(to))
         {
             // Upcast or cast from interface, might throw InvalidCastException
             ld(false).Emit(OpCodes.Castclass, to);
         }
         else
         {
             // Types are completely unrelated, e. g. string to List<int> conversion attempt
             throw new XamlIlLoadException(
                       $"Don't know how to convert reference type {what.GetFullName()} to reference type {to.GetFullName()}",
                       node);
         }
     }
 }
Пример #5
0
        public static bool TryGetCorrectlyTypedValue(XamlIlAstTransformationContext context,
                                                     IXamlIlAstValueNode node, IXamlIlType type, out IXamlIlAstValueNode rv)
        {
            var cfg = context.Configuration;

            rv = null;
            if (type.IsAssignableFrom(node.Type.GetClrType()))
            {
                rv = node;
                return(true);
            }


            // Since we are doing a conversion anyway, it makes sense to check for the underlying nullable type
            if (type.GenericTypeDefinition?.Equals(cfg.WellKnownTypes.NullableT) == true)
            {
                type = type.GenericArguments[0];
            }


            if (cfg.CustomValueConverter?.Invoke(context, node, type, out rv) == true)
            {
                return(true);
            }

            var nodeType = node.Type.GetClrType();

            // Implicit type converters
            if (!nodeType.Equals(cfg.WellKnownTypes.String))
            {
                return(false);
            }


            if (node is XamlIlAstTextNode tn)
            {
                if (type.IsEnum)
                {
                    var enumValue = type.Fields.FirstOrDefault(f => f.Name == tn.Text);
                    if (enumValue != null)
                    {
                        rv = TypeSystemHelpers.GetLiteralFieldConstantNode(enumValue, node);
                        return(true);
                    }
                }

                // Well known types
                if (TypeSystemHelpers.ParseConstantIfTypeAllows(tn.Text, type, tn, out var constantNode))
                {
                    rv = constantNode;
                    return(true);
                }

                if (type.FullName == "System.Type")
                {
                    var resolvedType = XamlIlTypeReferenceResolver.ResolveType(context, tn.Text, tn, true);
                    rv = new XamlIlTypeExtensionNode(tn, new XamlIlAstClrTypeReference(tn, resolvedType), type);
                    return(true);
                }

                if (cfg.WellKnownTypes.Delegate.IsAssignableFrom(type))
                {
                    var invoke   = type.FindMethod(m => m.Name == "Invoke");
                    var rootType = context.RootObject.Type.GetClrType();
                    var handler  =
                        rootType.FindMethod(tn.Text, invoke.ReturnType, false, invoke.Parameters.ToArray());
                    if (handler != null)
                    {
                        rv = new XamlIlLoadMethodDelegateNode(tn, context.RootObject, type, handler);
                        return(true);
                    }
                }
            }

            IXamlIlAstValueNode CreateInvariantCulture() =>
            new XamlIlStaticOrTargetedReturnMethodCallNode(node,
                                                           cfg.WellKnownTypes.CultureInfo.Methods.First(x =>
                                                                                                        x.IsPublic && x.IsStatic && x.Name == "get_InvariantCulture"), null);

            var candidates = type.Methods.Where(m => m.Name == "Parse" &&
                                                m.ReturnType.Equals(type) &&
                                                m.Parameters.Count > 0 &&
                                                m.Parameters[0].Equals(cfg.WellKnownTypes.String)).ToList();

            // Types with parse method
            var parser = candidates.FirstOrDefault(m =>
                                                   m.Parameters.Count == 2 &&
                                                   (
                                                       m.Parameters[1].Equals(cfg.WellKnownTypes.CultureInfo) ||
                                                       m.Parameters[1].Equals(cfg.WellKnownTypes.IFormatProvider)
                                                   )
                                                   )
                         ?? candidates.FirstOrDefault(m => m.Parameters.Count == 1);

            if (parser != null)
            {
                var args = new List <IXamlIlAstValueNode> {
                    node
                };
                if (parser.Parameters.Count == 2)
                {
                    args.Add(CreateInvariantCulture());
                }

                rv = new XamlIlStaticOrTargetedReturnMethodCallNode(node, parser, args);
                return(true);
            }

            if (cfg.TypeMappings.TypeDescriptorContext != null)
            {
                var typeConverterAttribute =
                    cfg.GetCustomAttribute(type, cfg.TypeMappings.TypeConverterAttributes).FirstOrDefault();
                if (typeConverterAttribute != null)
                {
                    var arg           = typeConverterAttribute.Parameters.FirstOrDefault();
                    var converterType = (arg as IXamlIlType) ??
                                        (arg is String sarg ? cfg.TypeSystem.FindType(sarg) : null);
                    if (converterType != null)
                    {
                        var converterMethod = converterType.FindMethod("ConvertFrom", cfg.WellKnownTypes.Object, false,
                                                                       cfg.TypeMappings.TypeDescriptorContext, cfg.WellKnownTypes.CultureInfo,
                                                                       cfg.WellKnownTypes.Object);
                        rv = new XamlIlAstNeedsParentStackValueNode(node,
                                                                    new XamlIlAstRuntimeCastNode(node,
                                                                                                 new XamlIlStaticOrTargetedReturnMethodCallNode(node, converterMethod,
                                                                                                                                                new[]
                        {
                            new XamlIlAstNewClrObjectNode(node,
                                                          converterType, null,
                                                          new List <IXamlIlAstValueNode>()),
                            new XamlIlAstContextLocalNode(node, cfg.TypeMappings.TypeDescriptorContext),
                            CreateInvariantCulture(),
                            node
                        }), new XamlIlAstClrTypeReference(node, type)));
                        return(true);
                    }
                }
            }

            return(false);
        }