コード例 #1
0
        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;
                }
            }
        }
コード例 #2
0
        void PopulateClass(AstClass astClass, DataType result)
        {
            var parameterizedType = Parameterize(result);
            var fieldInitializers = new List <AstExpression>();
            var deferredActions   = new List <Action>();

            parameterizedType.AssignBaseType();
            parameterizedType.Base?.PopulateMembers();

            foreach (var it in result.Interfaces)
            {
                it.PopulateMembers();
            }

            // Create dummies for members
            foreach (var item in astClass.Members)
            {
                if (item is AstClassMember)
                {
                    var m = (AstClassMember)item;
                    if (!_compiler.Environment.Test(((item as AstNamedMember)?.Name ?? astClass.Name).Source, m.OptionalCondition))
                    {
                        continue;
                    }
                }

                switch (item.MemberType)
                {
                case AstMemberType.Method:
                {
                    var md = item as AstMethod;

                    ClassType gt = null;
                    if (md.OptionalGenericSignature != null)
                    {
                        gt = new ClassType(md.Name.Source, parameterizedType, md.DocComment, Modifiers.Private | Modifiers.Static | Modifiers.Generated, md.Name.Symbol);
                        CreateGenericSignature(gt, md.OptionalGenericSignature, md.Modifiers.HasFlag(Modifiers.Override) || md.OptionalInterfaceType != null);
                    }

                    var pl = _compiler.CompileParameterList(gt ?? parameterizedType, md.Parameters, deferredActions);
                    var rt = _resolver.GetType(gt ?? parameterizedType, md.ReturnType);
                    var me = new Method(md.Name.Source, result, md.DocComment, GetMemberModifiers(md.Name.Source, parameterizedType, md.Modifiers), md.Name.Symbol, gt, rt, pl);
                    result.Methods.Add(me);

                    if (md.Attributes.Count > 0)
                    {
                        EnqueueAttributes(me, x => me.SetAttributes(_compiler.CompileAttributes(parameterizedType, md.Attributes)));
                    }

                    gt?.Methods.Add(me);

                    EnqueueCompiler(new FunctionCompiler(_compiler, me, parameterizedType, md.OptionalBody));

                    if (md.OptionalInterfaceType != null)
                    {
                        var it = _resolver.GetType(parameterizedType, md.OptionalInterfaceType);

                        if (!it.IsInvalid)
                        {
                            var im = TryImplementMethod(it, me);

                            if (im == null)
                            {
                                Log.Error(md.OptionalInterfaceType.Source, ErrorCode.E0000, "Method " + (me.UnoName + me.Parameters.BuildString()).Quote() + " does not exist in interface " + it.Quote());
                            }
                            else
                            {
                                me.SetImplementedMethod(im);
                            }
                        }
                    }
                    break;
                }

                case AstMemberType.Constructor:
                {
                    var md   = item as AstConstructor;
                    var pl   = _compiler.CompileParameterList(parameterizedType, md.Parameters, deferredActions);
                    var ctor = new Constructor(md.Source, result, md.DocComment, md.Modifiers, pl);

                    if (md.Attributes.Count > 0)
                    {
                        EnqueueAttributes(ctor, x => ctor.SetAttributes(_compiler.CompileAttributes(parameterizedType, md.Attributes)));
                    }

                    var fc = new FunctionCompiler(_compiler, ctor, parameterizedType, md.OptionalBody);
                    EnqueueCompiler(fc);

                    if (ctor.IsStatic)
                    {
                        if (result.Initializer != null)
                        {
                            Log.Error(ctor.Source, ErrorCode.E3002, parameterizedType.Quote() + " already has a static constructor");
                        }

                        result.Initializer = ctor;
                    }
                    else
                    {
                        ctor.Modifiers = GetMemberModifiers(md.Source, parameterizedType, md.Modifiers);
                        result.Constructors.Add(ctor);
                    }

                    if (md.OptionalBody != null)
                    {
                        ctor.SetBody(new Scope(ctor.Source));
                    }

                    if (md.CallType == AstConstructorCallType.This && parameterizedType.IsStruct && md.CallArguments.Count == 0)
                    {
                        ctor.Body.Statements.Add(new StoreThis(ctor.Source, new Default(ctor.Source, parameterizedType)));
                    }
                    else if (md.CallType != AstConstructorCallType.None)
                    {
                        if (ctor.Body == null)
                        {
                            Log.Error(md.Source, ErrorCode.E0000, ctor.Quote() + " cannot call constructor without method body");
                        }
                        else if (md.CallType != AstConstructorCallType.Base || parameterizedType.Base != DataType.Invalid)
                        {
                            _enqueuedActions.Add(() =>
                                {
                                    var bt = md.CallType == AstConstructorCallType.Base ? parameterizedType.Base : parameterizedType;
                                    bt.PopulateMembers();

                                    Constructor callCtor;
                                    Expression[] callArgs;
                                    if (!fc.TryResolveConstructorOverload(md.Source, bt.Constructors, md.CallArguments, out callCtor, out callArgs))
                                    {
                                        Log.Error(md.Source, ErrorCode.E3003, bt.Quote() + " does not have a constructor that matches this argument list");
                                    }
                                    else
                                    {
                                        ctor.Body.Statements.Add(new CallConstructor(md.Source, callCtor, callArgs));
                                    }
                                });
                        }
                    }
                    else if (!ctor.IsStatic &&
                             parameterizedType.Base != null &&
                             parameterizedType.TypeType != TypeType.Struct &&
                             ctor.Body != null)
                    {
                        _enqueuedActions.Add(() =>
                            {
                                Constructor callCtor;
                                Expression[] callArgs;
                                if (!fc.TryResolveConstructorOverload(md.Source, parameterizedType.Base.Constructors, AstArgument.Empty, out callCtor, out callArgs))
                                {
                                    Log.Error(md.Source, ErrorCode.E3004, "Base class " + parameterizedType.Base.Quote() + " does not have a default constructor");
                                }
                                else
                                {
                                    ctor.Body.Statements.Add(new CallConstructor(md.Source, callCtor, callArgs));
                                }
                            });
                    }
                    break;
                }

                case AstMemberType.Finalizer:
                {
                    var fd        = item as AstFinalizer;
                    var pl        = _compiler.CompileParameterList(parameterizedType, fd.Parameters, deferredActions);
                    var finalizer = new Finalizer(fd.Source, result, fd.DocComment, fd.Modifiers, pl);

                    if (fd.Attributes.Count > 0)
                    {
                        EnqueueAttributes(finalizer, x => finalizer.SetAttributes(_compiler.CompileAttributes(parameterizedType, fd.Attributes)));
                    }

                    if (result.Finalizer != null)
                    {
                        Log.Error(fd.Source, ErrorCode.E3002, parameterizedType.Quote() + " already has a finalizer");
                    }

                    result.Finalizer = finalizer;
                    EnqueueCompiler(new FunctionCompiler(_compiler, finalizer, parameterizedType, fd.OptionalBody));
                    break;
                }

                case AstMemberType.Property:
                {
                    var pd   = item as AstProperty;
                    var dt   = _resolver.GetType(parameterizedType, pd.ReturnType);
                    var prop = new Property(pd.Name.Source, pd.DocComment, GetMemberModifiers(pd.Name.Source, parameterizedType, pd.Modifiers), pd.Name.Symbol, result, dt);
                    result.Properties.Add(prop);

                    bool hasImplicitImplementation = false;

                    // Implicit implementation
                    if (!prop.IsAbstract)
                    {
                        if (pd.Get != null && pd.Get.OptionalBody == null ||
                            pd.Set != null && pd.Set.OptionalBody == null)
                        {
                            if (pd.Set != null && pd.Set.OptionalBody == null && (pd.Get == null || pd.Get?.OptionalBody != null))
                            {
                                if (!prop.IsExtern)
                                {
                                    Log.Error(pd.Set.Source, ErrorCode.E3042, prop.Quote(".set") + " must declare a body because it is not marked abstract or extern. Automatically implemented properties must define both get and set accessors");
                                }
                            }
                            else if (pd.Get != null && pd.Get.OptionalBody == null && (pd.Set == null || pd.Set?.OptionalBody != null))
                            {
                                if (!prop.IsExtern)
                                {
                                    Log.Error(pd.Get.Source, ErrorCode.E3041, prop.Quote(".get") + " must declare a body because it is not marked abstract or extern. Automatically implemented properties must define both get and set accessors");
                                }
                            }
                            else
                            {
                                prop.CreateImplicitField(prop.Source);

                                var getScope = new Scope(pd.Get.Source);
                                prop.CreateGetMethod(pd.Get.Source, GetAccessorModifiers(pd.Get.Source, prop, pd.Get.Modifiers) | Modifiers.Generated, getScope);

                                var setScope  = new Scope(pd.Set.Source);
                                var setMethod = prop.CreateSetMethod(pd.Set.Source, GetAccessorModifiers(pd.Set.Source, prop, pd.Set.Modifiers) | Modifiers.Generated, setScope);
                                var propIndex = result.Properties.Count - 1;

                                _enqueuedActions.Add(() =>
                                    {
                                        parameterizedType.PopulateMembers();

                                        var obj   = prop.Modifiers.HasFlag(Modifiers.Static) ? null : new This(prop.Source, parameterizedType).Address;
                                        var field = parameterizedType.Properties[propIndex].ImplicitField;

                                        getScope.Statements.Add(
                                            new Return(pd.Get.Source, new LoadField(pd.Get.Source, obj, field)));
                                        setScope.Statements.Add(
                                            new StoreField(pd.Set.Source, obj, field, new LoadArgument(pd.Set.Source, setMethod, 0)));
                                    });

                                hasImplicitImplementation = true;
                            }
                        }
                    }

                    if (pd.Attributes.Count > 0)
                    {
                        EnqueueAttributes(prop,
                                          x =>
                            {
                                prop.SetAttributes(_compiler.CompileAttributes(parameterizedType, pd.Attributes));
                                prop.GetMethod?.SetAttributes(prop.Attributes);
                                prop.SetMethod?.SetAttributes(prop.Attributes);
                                prop.ImplicitField?.SetAttributes(prop.Attributes);
                            });
                    }

                    if (!hasImplicitImplementation)
                    {
                        if (pd.Get != null)
                        {
                            EnqueueCompiler(new FunctionCompiler(_compiler, prop.CreateGetMethod(pd.Get.Source, GetAccessorModifiers(pd.Get.Source, prop, pd.Get.Modifiers)), parameterizedType, pd.Get.OptionalBody));
                        }
                        if (pd.Set != null)
                        {
                            EnqueueCompiler(new FunctionCompiler(_compiler, prop.CreateSetMethod(pd.Set.Source, GetAccessorModifiers(pd.Set.Source, prop, pd.Set.Modifiers)), parameterizedType, pd.Set.OptionalBody));
                        }
                    }

                    if (pd.OptionalInterfaceType != null)
                    {
                        var it = _compiler.NameResolver.GetType(parameterizedType, pd.OptionalInterfaceType);

                        if (!it.IsInvalid)
                        {
                            var im = TryImplementProperty(it, prop);

                            if (im == null)
                            {
                                Log.Error(pd.OptionalInterfaceType.Source, ErrorCode.E0000, "Property " + prop.UnoName.Quote() + " does not exist in interface " + it.Quote());
                            }
                            else
                            {
                                prop.SetImplementedProperty(im);
                            }
                        }
                    }
                    break;
                }

                case AstMemberType.Field:
                {
                    var f  = item as AstField;
                    var dt = _compiler.NameResolver.GetType(parameterizedType, f.ReturnType);

                    if (f.FieldModifiers.HasFlag(FieldModifiers.Const))
                    {
                        var m = new Literal(f.Name.Source, result, f.Name.Symbol, f.DocComment, GetMemberModifiers(f.Name.Source, parameterizedType, f.Modifiers), dt, f.InitValue);
                        result.Literals.Add(m);

                        if (f.Attributes.Count > 0)
                        {
                            EnqueueAttributes(m, x => m.SetAttributes(_compiler.CompileAttributes(parameterizedType, f.Attributes)));
                        }

                        if (f.InitValue == null)
                        {
                            Log.Error(f.Name.Source, ErrorCode.E3007, "'const' fields must provide a constant value");
                        }
                        else
                        {
                            deferredActions.Add(() => m.Value = _compiler.CompileConstant(f.InitValue, parameterizedType, dt).Value);
                        }
                    }
                    else
                    {
                        var m = new Field(f.Name.Source, result, f.Name.Symbol, f.DocComment, GetMemberModifiers(f.Name.Source, parameterizedType, f.Modifiers), f.FieldModifiers, dt);
                        fieldInitializers.Add(f.InitValue);
                        result.Fields.Add(m);

                        if (f.Attributes.Count > 0)
                        {
                            EnqueueAttributes(m, x => m.SetAttributes(_compiler.CompileAttributes(parameterizedType, f.Attributes)));
                        }
                    }
                    break;
                }

                case AstMemberType.Operator:
                {
                    var od = item as AstOperator;
                    var rt = _resolver.GetType(parameterizedType, od.ReturnType);
                    var pl = _compiler.CompileParameterList(parameterizedType, od.Parameters, deferredActions);
                    var op = new Operator(od.Source, result, od.Operator, od.DocComment, GetMemberModifiers(od.Source, parameterizedType, od.Modifiers), rt, pl);
                    result.Operators.Add(op);

                    if (od.Attributes.Count > 0)
                    {
                        EnqueueAttributes(op, x => op.SetAttributes(_compiler.CompileAttributes(parameterizedType, od.Attributes)));
                    }

                    EnqueueCompiler(new FunctionCompiler(_compiler, op, parameterizedType, od.OptionalBody));
                    break;
                }

                case AstMemberType.Converter:
                {
                    var cd   = item as AstConverter;
                    var rt   = _resolver.GetType(parameterizedType, cd.TargetType);
                    var pl   = _compiler.CompileParameterList(parameterizedType, cd.Parameters, deferredActions);
                    var type = cd.Modifiers.HasFlag(Modifiers.Implicit) ? CastModifier.Implicit : CastModifier.Explicit;
                    var cast = new Cast(cd.TargetType.Source, result, type, cd.DocComment, GetMemberModifiers(cd.TargetType.Source, parameterizedType, cd.Modifiers), rt, pl);
                    result.Casts.Add(cast);

                    if (cd.Attributes.Count > 0)
                    {
                        EnqueueAttributes(cast, x => cast.SetAttributes(_compiler.CompileAttributes(parameterizedType, cd.Attributes)));
                    }

                    EnqueueCompiler(new FunctionCompiler(_compiler, cast, parameterizedType, cd.OptionalBody));
                    break;
                }

                case AstMemberType.Indexer:
                {
                    var id      = item as AstIndexer;
                    var rt      = _resolver.GetType(parameterizedType, id.ReturnType);
                    var pl      = _compiler.CompileParameterList(parameterizedType, id.Parameters, deferredActions);
                    var indexer = new Property(id.Source, id.DocComment, GetMemberModifiers(id.Source, parameterizedType, id.Modifiers), "Item", result, rt, pl);
                    result.Properties.Add(indexer);

                    if (id.Attributes.Count > 0)
                    {
                        EnqueueAttributes(indexer,
                                          x =>
                            {
                                indexer.SetAttributes(_compiler.CompileAttributes(parameterizedType, id.Attributes));
                                indexer.GetMethod?.SetAttributes(indexer.Attributes);
                                indexer.SetMethod?.SetAttributes(indexer.Attributes);
                            });
                    }

                    if (id.Get != null)
                    {
                        EnqueueCompiler(new FunctionCompiler(_compiler, indexer.CreateGetMethod(id.Get.Source, GetAccessorModifiers(id.Get.Source, indexer, id.Get.Modifiers)), parameterizedType, id.Get.OptionalBody));
                    }
                    if (id.Set != null)
                    {
                        EnqueueCompiler(new FunctionCompiler(_compiler, indexer.CreateSetMethod(id.Set.Source, GetAccessorModifiers(id.Set.Source, indexer, id.Set.Modifiers)), parameterizedType, id.Set.OptionalBody));
                    }

                    if (id.OptionalInterfaceType != null)
                    {
                        var it = _resolver.GetType(parameterizedType, id.OptionalInterfaceType);

                        if (!it.IsInvalid)
                        {
                            var im = TryImplementProperty(it, indexer);

                            if (im == null)
                            {
                                Log.Error(id.OptionalInterfaceType.Source, ErrorCode.E0000, "Indexer 'this" + indexer.Parameters.BuildString("[", "]") + "' does not exist in interface " + it.Quote());
                            }
                            else
                            {
                                indexer.SetImplementedProperty(im);
                            }
                        }
                    }
                    break;
                }

                case AstMemberType.Event:
                {
                    var ed = item as AstEvent;
                    var dt = _resolver.GetType(parameterizedType, ed.DelegateType);

                    if (dt.IsInvalid)
                    {
                        break;
                    }

                    if (!dt.IsDelegate)
                    {
                        Log.Error(ed.Name.Source, ErrorCode.E3012, "Events must have delegate type. " + dt + " is a " + dt.TypeType);
                    }

                    var ev = new Event(ed.Name.Source, ed.DocComment, GetMemberModifiers(ed.Name.Source, parameterizedType, ed.Modifiers), result, dt, ed.Name.Symbol);
                    result.Events.Add(ev);

                    if (ed.Attributes.Count > 0)
                    {
                        EnqueueAttributes(ev,
                                          x =>
                            {
                                ev.SetAttributes(_compiler.CompileAttributes(parameterizedType, ed.Attributes));
                                ev.AddMethod?.SetAttributes(ev.Attributes);
                                ev.RemoveMethod?.SetAttributes(ev.Attributes);
                                ev.ImplicitField?.SetAttributes(ev.Attributes);
                            });
                    }

                    // Implicit implementation
                    if (ed.Add == null && ed.Remove == null)
                    {
                        if (!ev.IsAbstract)
                        {
                            ev.CreateImplicitField(ed.Name.Source);

                            var addScope     = new Scope(ed.Name.Source);
                            var addMethod    = ev.CreateAddMethod(ev.Source, ev.Modifiers | Modifiers.Generated, addScope);
                            var removeScope  = new Scope(ed.Name.Source);
                            var removeMethod = ev.CreateRemoveMethod(ev.Source, ev.Modifiers | Modifiers.Generated, removeScope);
                            var eventIndex   = result.Events.Count - 1;

                            _enqueuedActions.Add(() =>
                                {
                                    parameterizedType.PopulateMembers();

                                    var obj   = ev.IsStatic ? null : new This(ev.Source, parameterizedType).Address;
                                    var field = parameterizedType.Events[eventIndex].ImplicitField;

                                    addScope.Statements.Add(
                                        new StoreField(ev.Source, obj, field,
                                                       new CastOp(ev.Source, ev.ReturnType,
                                                                  _ilf.CallMethod(ev.Source, _ilf.Essentials.Delegate, "Combine",
                                                                                  new CastOp(ev.Source, _ilf.Essentials.Delegate, new LoadField(ev.Source, obj, field)),
                                                                                  new LoadArgument(ev.Source, addMethod, 0)))));
                                    removeScope.Statements.Add(
                                        new StoreField(ev.Source, obj, field,
                                                       new CastOp(ev.Source, ev.ReturnType,
                                                                  _ilf.CallMethod(ev.Source, _ilf.Essentials.Delegate, "Remove",
                                                                                  new CastOp(ev.Source, _ilf.Essentials.Delegate, new LoadField(ev.Source, obj, field)),
                                                                                  new LoadArgument(ev.Source, removeMethod, 0)))));
                                });
                        }
                        else
                        {
                            ev.CreateAddMethod(ev.Source, ev.Modifiers);
                            ev.CreateRemoveMethod(ev.Source, ev.Modifiers);
                        }

                        break;
                    }

                    if (ed.Add != null && ed.Add.Modifiers != 0 || ed.Remove != null && ed.Remove.Modifiers != 0)
                    {
                        Log.Error(ed.Name.Source, ErrorCode.E3040, "Modifiers can not be placed on event accessor declarations");
                    }

                    if (ed.Add != null)
                    {
                        EnqueueCompiler(new FunctionCompiler(_compiler, ev.CreateAddMethod(ed.Add.Source, ev.Modifiers), parameterizedType, ed.Add.OptionalBody));
                    }
                    if (ed.Remove != null)
                    {
                        EnqueueCompiler(new FunctionCompiler(_compiler, ev.CreateRemoveMethod(ed.Remove.Source, ev.Modifiers), parameterizedType, ed.Remove.OptionalBody));
                    }

                    if (ed.OptionalInterfaceType != null)
                    {
                        var it = _resolver.GetType(parameterizedType, ed.OptionalInterfaceType);

                        if (!it.IsInvalid)
                        {
                            var im = TryImplementEvent(it, ev);

                            if (im == null)
                            {
                                Log.Error(ed.OptionalInterfaceType.Source, ErrorCode.E0000, "Event " + ev.UnoName.Quote() + " does not exist in interface " + it.Quote());
                            }
                            else
                            {
                                ev.SetImplementedEvent(im);
                            }
                        }
                    }
                    break;
                }
                }

                switch (item.MemberType)
                {
                case AstMemberType.Method:
                case AstMemberType.Property:
                case AstMemberType.Indexer:
                case AstMemberType.Event:
                    switch (parameterizedType.TypeType)
                    {
                    case TypeType.Class:
                    case TypeType.Interface:
                    case TypeType.Struct:
                        continue;
                    }
                    break;

                case AstMemberType.Field:
                case AstMemberType.Constructor:
                case AstMemberType.Operator:
                case AstMemberType.Converter:
                case AstMemberType.Class:
                case AstMemberType.Enum:
                case AstMemberType.Delegate:
                    switch (parameterizedType.TypeType)
                    {
                    case TypeType.Class:
                    case TypeType.Struct:
                        continue;
                    }
                    break;

                case AstMemberType.Finalizer:
                case AstMemberType.MetaMethod:
                case AstMemberType.MetaProperty:
                case AstMemberType.NodeBlock:
                case AstMemberType.Block:
                case AstMemberType.ApplyStatement:
                    switch (parameterizedType.TypeType)
                    {
                    case TypeType.Class:
                        continue;
                    }
                    break;
                }

                Log.Error(((item as AstNamedMember)?.Name ?? astClass.Name).Source, ErrorCode.E3013, "<" + item.MemberType + "> is not allowed in this scope");
            }

            // Compile swizzle types
            if (astClass.Swizzlers != null)
            {
                foreach (var e in astClass.Swizzlers)
                {
                    result.Swizzlers.Add(_resolver.GetType(parameterizedType, e));
                }
            }

            // Compile field initializers
            if (fieldInitializers.Count > 0)
            {
                _enqueuedActions.Add(() => CompileFieldInitializers(result, parameterizedType, fieldInitializers));
            }

            // Create default constructor in non-static classes
            if (result.IsClass && !result.IsStatic && result.Constructors.Count == 0)
            {
                var ctor = new Constructor(parameterizedType.Source, parameterizedType, null,
                                           (parameterizedType.IsAbstract ? Modifiers.Protected : Modifiers.Public) | Modifiers.Generated,
                                           ParameterList.Empty, new Scope(parameterizedType.Source));
                result.Constructors.Add(ctor);
                _enqueuedActions.Add(() =>
                {
                    parameterizedType.AssignBaseType();
                    parameterizedType.Base.PopulateMembers();

                    Constructor callCtor  = null;
                    Expression[] callArgs = null;
                    if (parameterizedType.Base != DataType.Invalid && !new FunctionCompiler(_compiler, parameterizedType).TryResolveConstructorOverload(parameterizedType.Source, parameterizedType.Base.Constructors, AstArgument.Empty, out callCtor, out callArgs))
                    {
                        Log.Error(parameterizedType.Source, ErrorCode.E3001, parameterizedType.Base.Quote() + " does not have a default constructor");
                    }
                    else
                    {
                        ctor.Body.Statements.Add(new CallConstructor(ctor.Source, callCtor, callArgs));
                    }
                });
            }

            // Resolve overridden members
            foreach (var m in result.Methods)
            {
                m.SetOverriddenMethod(TryOverrideMethod(m));

                if (m.IsGenericDefinition)
                {
                    if (m.ImplementedMethod != null || m.OverriddenMethod != null)
                    {
                        // Inherit base generic constraints
                        var baseParams = (m.OverriddenMethod ?? m.ImplementedMethod).GenericDefinition.GenericParameters;

                        for (int i = 0; i < m.GenericParameters.Length; i++)
                        {
                            var baseParam = baseParams[i];
                            var thisParam = m.GenericParameters[i];

                            baseParam.AssignBaseType();
                            thisParam.AssignBaseType();
                            thisParam.SetBase(baseParam.Base);
                            thisParam.SetConstraintType(baseParam.ConstraintType);
                            thisParam.SetInterfaces(baseParam.Interfaces);

                            if (baseParam.Constructors.Count > 0)
                            {
                                thisParam.Constructors.Add(new Constructor(baseParam.Constructors[0].Source, thisParam, null,
                                                                           Modifiers.Public | Modifiers.Generated | Modifiers.Extern, ParameterList.Empty));
                            }
                        }
                    }

                    Parameterize(m.Source, m, m.GenericParameters);
                }
            }

            foreach (var m in result.Properties)
            {
                m.SetOverriddenProperty(TryOverrideProperty(m));
            }
            foreach (var m in result.Events)
            {
                m.SetOverriddenEvent(TryOverrideEvent(m));
            }

            if (!result.IsInterface && result.Interfaces.Length > 0)
            {
                ImplementInterfaces(result);
            }

            _compiler.BlockBuilder.PopulateBlock(astClass, result.Block);

            foreach (var action in deferredActions)
            {
                action();
            }
        }