void ParameterizeBaseType(DataType current, Dictionary <DataType, DataType> map, DataType result)
        {
            current.AssignBaseType();
            result.SetBase(ParameterizeType(map, current.Base));

            if (result is DelegateType)
            {
                var currentDelegate = (DelegateType)current;
                var resultDelegate  = (DelegateType)result;
                resultDelegate.SetReturnType(ParameterizeType(map, currentDelegate.ReturnType));
                resultDelegate.SetParameters(ParameterizeParameters(map, currentDelegate.Parameters));
            }
            else if (current.Interfaces.Length > 0)
            {
                var interfaceTypes = new InterfaceType[current.Interfaces.Length];

                for (int i = 0, l = interfaceTypes.Length; i < l; i++)
                {
                    interfaceTypes[i] = (InterfaceType)ParameterizeType(map, current.Interfaces[i]);
                }

                result.SetInterfaces(interfaceTypes);
            }
        }
        Expression TryCompileCast(Source src, DataType targetType, Expression operand)
        {
            if (targetType.IsInvalid || operand.IsInvalid)
            {
                return(Expression.Invalid);
            }

            // Equal types == NOP
            if (targetType.Equals(operand.ReturnType))
            {
                return(operand);
            }

            var cast = TryResolveCastOverload(src, NameResolver.GetTypeCasts(targetType, operand.ReturnType), ref operand);

            if (cast != null)
            {
                return(new CallCast(src, cast, operand));
            }

            // Box
            // Generic -> object
            // Method -> delegate
            // etc
            var impl = TryCompileImplicitCast(src, targetType, operand);

            if (impl != null)
            {
                return(impl);
            }

            // Down cast
            if (targetType.IsReferenceType && operand.ReturnType.IsReferenceType ||
                targetType.IsInterface || operand.ReturnType.IsInterface)
            {
                return(operand.ReturnType.IsInterface ||
                       operand.ReturnType.IsSubclassOf(targetType) ||
                       operand.ReturnType.IsImplementingInterface(targetType) ||
                       targetType.IsInterface ||
                       targetType.IsSubclassOf(operand.ReturnType) ||
                       targetType.IsImplementingInterface(operand.ReturnType)
                    ? new CastOp(src, targetType, operand)
                    : Error(src, ErrorCode.E2028, targetType.Quote() + " and " + operand.ReturnType.Quote() + " are not compatible types"));
            }

            // Unbox
            // Ref -> generic
            if (targetType.IsValueType && operand.ReturnType.Equals(Essentials.Object) ||
                targetType.IsGenericParameter && operand.ReturnType.IsReferenceType)
            {
                return(new CastOp(src, targetType, operand));
            }

            if (operand.ReturnType.IsEnum)
            {
                operand.ReturnType.AssignBaseType();
                return(TryCompileCast(src, targetType, new CastOp(src, operand.ReturnType.Base ?? Essentials.Int, operand)));
            }

            if (targetType.IsEnum)
            {
                targetType.AssignBaseType();
                var intValue = TryCompileCast(src, targetType.Base ?? Essentials.Int, operand);
                if (intValue != null)
                {
                    return(new CastOp(src, targetType, intValue));
                }
            }

            return(null);
        }
        Expression TryCompileImplicitCast(Source src, DataType expectedType, Expression value, bool reportErrorIfNotFound)
        {
            if (ImplicitCastStack.Contains(expectedType))
            {
                ImplicitCastStack.Add(expectedType);
            }
            else
            {
                ImplicitCastStack.Add(expectedType);

                if (Equals(expectedType, value.ReturnType))
                {
                    return(value);
                }

                if (value.ReturnType is InvalidType || expectedType is InvalidType)
                {
                    return(Expression.Invalid);
                }

                // (EnumType)0
                if (expectedType is EnumType && value is Constant && value.ConstantValue is int && (int)value.ConstantValue == 0)
                {
                    return(new Constant(value.Source, (EnumType)expectedType, (int)value.ConstantValue));
                }

                // Null type (must be done before delegate)
                if (value.ReturnType.IsNull)
                {
                    return(expectedType.IsReferenceType
                            ? new Constant(src, expectedType, null) :
                           !reportErrorIfNotFound
                            ? null
                            : Error(src, ErrorCode.E2043, "'<null>' has no implicit cast to " + expectedType.Quote() + " because that is not a reference type"));
                }

                // Delegate
                if (expectedType is DelegateType && value is MethodGroup)
                {
                    var dt = expectedType as DelegateType;
                    dt.AssignBaseType();

                    var mg                = value as MethodGroup;
                    var candidates        = mg.Candidates;
                    var compatibleMethods = new List <Method>();

                    foreach (var m in candidates)
                    {
                        if (!m.IsGenericDefinition &&
                            m.ReturnType.Equals(dt.ReturnType) &&
                            dt.CompareParameters(m))
                        {
                            compatibleMethods.Add(m);
                        }
                    }

                    if (compatibleMethods.Count == 0)
                    {
                        foreach (var c in candidates)
                        {
                            if (c.IsGenericDefinition)
                            {
                                var dummyArgs = new Expression[dt.Parameters.Length];

                                for (int i = 0; i < dummyArgs.Length; i++)
                                {
                                    var p = dt.Parameters[i];
                                    dummyArgs[i] = new Default(p.Source, p.Type);

                                    switch (p.Modifier)
                                    {
                                    case ParameterModifier.Const:
                                        dummyArgs[i] = new AddressOf(dummyArgs[i], AddressType.Const);
                                        break;

                                    case ParameterModifier.Ref:
                                        dummyArgs[i] = new AddressOf(dummyArgs[i], AddressType.Ref);
                                        break;

                                    case ParameterModifier.Out:
                                        dummyArgs[i] = new AddressOf(dummyArgs[i], AddressType.Out);
                                        break;
                                    }
                                }

                                candidates = CopyAndParameterizeGenericMethods(src, candidates, dummyArgs);

                                foreach (var m in candidates)
                                {
                                    if (!m.IsGenericDefinition &&
                                        m.ReturnType.Equals(dt.ReturnType) &&
                                        dt.CompareParameters(m))
                                    {
                                        compatibleMethods.Add(m);
                                    }
                                }
                                break;
                            }
                        }

                        if (compatibleMethods.Count == 0)
                        {
                            foreach (var m in candidates)
                            {
                                if (!m.IsGenericDefinition &&
                                    (m.ReturnType.Equals(dt.ReturnType) || m.ReturnType.IsReferenceType && m.ReturnType.IsSubclassOfOrEqual(dt.ReturnType)) &&
                                    dt.CompareParametersEqualOrSubclassOf(m))
                                {
                                    compatibleMethods.Add(m);
                                }
                            }
                        }
                    }

                    if (compatibleMethods.Count == 1)
                    {
                        var m = compatibleMethods[0];

                        if (m.IsStatic)
                        {
                            return(new NewDelegate(src, dt, null, m));
                        }

                        if (mg.Object != null && !mg.Object.ReturnType.IsReferenceType)
                        {
                            mg.Object = new CastOp(src, Essentials.Object, mg.Object.ActualValue);
                        }

                        return(new NewDelegate(src, dt, mg.Object, m));
                    }

                    return(!reportErrorIfNotFound
                        ? null
                        : compatibleMethods.Count == 0
                            ? Error(src, ErrorCode.E2045, "No methods matches the parameter list and return type of delegate type " + dt.Quote())
                            : ReportAmbiguousMatchError(src, compatibleMethods));
                }

                // Lambda
                if (expectedType is DelegateType && value is UncompiledLambda)
                {
                    expectedType.AssignBaseType();
                    return(TryCompileImplicitLambdaCast((UncompiledLambda)value, (DelegateType)expectedType));
                }

                // Constant
                if (value is Constant && expectedType.IsIntrinsic)
                {
                    var constant = value as Constant;

                    if (constant.Value is int)
                    {
                        int intValue = (int)constant.Value;

                        switch (expectedType.BuiltinType)
                        {
                        case BuiltinType.SByte:
                            if (intValue >= -0x80 && intValue <= 0x7f)
                            {
                                return(new Constant(constant.Source, expectedType, (sbyte)intValue));
                            }
                            break;

                        case BuiltinType.Byte:
                            if (intValue >= 0 && intValue <= 0xff)
                            {
                                return(new Constant(constant.Source, expectedType, (byte)intValue));
                            }
                            break;

                        case BuiltinType.Short:
                            if (intValue >= -0x8000 && intValue <= 0x7fff)
                            {
                                return(new Constant(constant.Source, expectedType, (short)intValue));
                            }
                            break;

                        case BuiltinType.UShort:
                            if (intValue >= 0 && intValue <= 0xffff)
                            {
                                return(new Constant(constant.Source, expectedType, (ushort)intValue));
                            }
                            break;

                        case BuiltinType.UInt:
                            if (intValue >= 0)
                            {
                                return(new Constant(constant.Source, expectedType, (uint)intValue));
                            }
                            break;

                        case BuiltinType.ULong:
                            if (intValue >= 0)
                            {
                                return(new Constant(constant.Source, expectedType, (ulong)intValue));
                            }
                            break;
                        }
                    }

                    if (constant.Value is long)
                    {
                        long longValue = (long)constant.Value;

                        switch (expectedType.BuiltinType)
                        {
                        case BuiltinType.ULong:
                            if (longValue >= 0)
                            {
                                return(new Constant(constant.Source, expectedType, (ulong)longValue));
                            }
                            break;
                        }
                    }
                }

                // Implict cast
                bool ambiguous;
                var  cast = TryResolveCastOverload(src, NameResolver.GetTypeCasts(expectedType, value.ReturnType),
                                                   ref value, reportErrorIfNotFound, out ambiguous);

                if (ambiguous)
                {
                    goto ERROR;
                }

                if (cast != null && cast.IsImplicitCast)
                {
                    return(new CallCast(src, cast, value));
                }

                // Up cast
                if (expectedType == Essentials.Object ||
                    value.ReturnType.IsSubclassOf(expectedType) ||
                    expectedType.IsInterface && value.ReturnType.IsImplementingInterface(expectedType))
                {
                    return(new CastOp(src, expectedType, value));
                }

                // Fixed Array
                if (expectedType.IsFixedArray && value.ReturnType.IsFixedArray)
                {
                    var t1 = expectedType as FixedArrayType;
                    var t2 = value.ReturnType as FixedArrayType;

                    if (t1.ElementType.Equals(t2.ElementType) && (
                            t1.OptionalSize == null || t2.OptionalSize == null ||
                            t1.OptionalSize is Constant && t2.OptionalSize is Constant && Equals(t1.OptionalSize.ConstantValue, t2.OptionalSize.ConstantValue)
                            ))
                    {
                        return(value);
                    }
                }

                // T[] -> IEnumerable<T>
                if (value.ReturnType.IsRefArray && expectedType.MasterDefinition == Essentials.IEnumerable_T)
                {
                    ImplicitCastStack.RemoveLast();
                    var arrayEnumerable = TypeBuilder.Parameterize(src, Essentials.ArrayEnumerable_T, value.ReturnType.ElementType);
                    return(TryCompileImplicitCast(src, expectedType,
                                                  ILFactory.NewObject(src, arrayEnumerable, value), reportErrorIfNotFound));
                }
            }

ERROR:
            return(!reportErrorIfNotFound
                ? null
                : Error(src, ErrorCode.E2047, "No implicit cast from " + value.ReturnType.Quote() + " to " + expectedType.Quote()));
        }
        void ParameterizeMembers(DataType definition, DataType current, Dictionary <DataType, DataType> map, DataType result)
        {
            current.AssignAttributes();
            result.SetAttributes(current.Attributes);
            current.PopulateMembers();

            foreach (var s in current.Swizzlers)
            {
                result.Swizzlers.Add(ParameterizeType(map, s));
            }

            if (current.Initializer != null)
            {
                var m = current.Initializer;
                var c = new Constructor(m.Source, result, m.DocComment,
                                        m.Modifiers, ParameterizeParameters(map, m.Parameters), m.Body);
                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Initializer = c;
            }

            if (current.Finalizer != null)
            {
                var m = current.Finalizer;
                var c = new Finalizer(m.Source, result, m.DocComment,
                                      m.Modifiers, ParameterizeParameters(map, m.Parameters), m.Body);
                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Finalizer = c;
            }

            foreach (var m in current.Constructors)
            {
                var c = new Constructor(m.Source, result, m.DocComment,
                                        m.Modifiers, ParameterizeParameters(map, m.Parameters), m.Body);
                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Constructors.Add(c);
            }

            foreach (var m in current.Methods)
            {
                DataType  owner = result;
                ClassType genericMethodParametersOwner = null;

                if (m.IsGenericDefinition)
                {
                    if (m.GenericType != definition)
                    {
                        genericMethodParametersOwner = new ClassType(m.Source, result, m.DocComment, Modifiers.Private | Modifiers.Static | Modifiers.Generated, m.UnoName);
                        genericMethodParametersOwner.MakeGenericDefinition(m.GenericParameters);

                        foreach (var p in m.GenericParameters)
                        {
                            map.Add(p, p);
                        }
                    }
                    else
                    {
                        owner = (DataType)result.Parent;
                        genericMethodParametersOwner = (ClassType)result;
                    }
                }

                var c = new Method(m.Source, owner, m.DocComment,
                                   m.Modifiers, m.UnoName, genericMethodParametersOwner, ParameterizeType(map, m.ReturnType), ParameterizeParameters(map, m.Parameters), m.Body);

                if (genericMethodParametersOwner != null && genericMethodParametersOwner != result)
                {
                    genericMethodParametersOwner.Methods.Add(c);
                }

                if (m.OverriddenMethod != null)
                {
                    c.SetOverriddenMethod(ParameterizeMethod(map, m.OverriddenMethod));
                }
                if (m.ImplementedMethod != null)
                {
                    c.SetImplementedMethod(ParameterizeMethod(map, m.ImplementedMethod));
                }

                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Methods.Add(c);
            }

            foreach (var m in current.Properties)
            {
                var c = new Property(m.Source, m.DocComment, m.Modifiers, m.UnoName, result,
                                     ParameterizeType(map, m.ReturnType), ParameterizeParameters(map, m.Parameters));

                if (m.GetMethod != null)
                {
                    c.CreateGetMethod(m.GetMethod.Source, m.GetMethod.Modifiers, m.GetMethod.Body);
                }
                if (m.SetMethod != null)
                {
                    c.CreateSetMethod(m.SetMethod.Source, m.SetMethod.Modifiers, m.SetMethod.Body);
                }
                if (m.ImplicitField != null)
                {
                    c.CreateImplicitField(m.ImplicitField.Source);
                }

                if (m.OverriddenProperty != null)
                {
                    c.SetOverriddenProperty(ParameterizeProperty(map, m.OverriddenProperty));
                }
                if (m.ImplementedProperty != null)
                {
                    c.SetImplementedProperty(ParameterizeProperty(map, m.ImplementedProperty));
                }

                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Properties.Add(c);
            }

            foreach (var m in current.Events)
            {
                var c = new Event(m.Source, m.DocComment, m.Modifiers, result,
                                  ParameterizeType(map, m.ReturnType), m.UnoName);

                if (m.AddMethod != null)
                {
                    c.CreateAddMethod(m.AddMethod.Source, m.AddMethod.Modifiers, m.AddMethod.Body);
                }
                if (m.RemoveMethod != null)
                {
                    c.CreateRemoveMethod(m.RemoveMethod.Source, m.RemoveMethod.Modifiers, m.RemoveMethod.Body);
                }
                if (m.ImplicitField != null)
                {
                    c.CreateImplicitField(m.ImplicitField.Source);
                }

                if (m.OverriddenEvent != null)
                {
                    c.SetOverriddenEvent(ParameterizeEvent(map, m.OverriddenEvent));
                }
                if (m.ImplementedEvent != null)
                {
                    c.SetImplementedEvent(ParameterizeEvent(map, m.ImplementedEvent));
                }

                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Events.Add(c);
            }

            foreach (var m in current.Casts)
            {
                var c = new Cast(m.Source, result, m.Type, m.DocComment, m.Modifiers,
                                 ParameterizeType(map, m.ReturnType), ParameterizeParameters(map, m.Parameters), m.Body);
                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Casts.Add(c);
            }

            foreach (var m in current.Operators)
            {
                var c = new Operator(m.Source, result, m.Type, m.DocComment, m.Modifiers,
                                     ParameterizeType(map, m.ReturnType), ParameterizeParameters(map, m.Parameters), m.Body);
                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Operators.Add(c);
            }

            foreach (var m in current.Fields)
            {
                var c = new Field(m.Source, result, m.UnoName, m.DocComment, m.Modifiers, m.FieldModifiers,
                                  ParameterizeType(map, m.ReturnType));
                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Fields.Add(c);
            }

            foreach (var m in current.Literals)
            {
                var c = new Literal(m.Source, result, m.UnoName, m.DocComment, m.Modifiers,
                                    ParameterizeType(map, m.ReturnType), m.Value);
                m.AssignAttributes();
                c.SetAttributes(m.Attributes);
                c.SetMasterDefinition(m.MasterDefinition);
                result.Literals.Add(c);
            }

            result.AssignBaseType();

            if (!result.IsParameterizedDefinition &&
                !result.IsInterface && result.Interfaces.Length > 0)
            {
                foreach (var e in current.InterfaceMethods)
                {
                    var impl = FindParameterizedMethod(ParameterizeType(map, e.Key.DeclaringType), e.Key);
                    var decl = FindParameterizedMethod(result, e.Value);
                    result.InterfaceMethods[impl] = decl;
                }
            }
        }