diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs index 7d354f2b81..4ee2be9ee0 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/AvaloniaXamlIlRuntimeCompiler.cs @@ -117,7 +117,7 @@ namespace Avalonia.Markup.Xaml.XamlIl var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + uri); var clrPropertyBuilder = tb.DefineNestedType("ClrProperties_" + Guid.NewGuid().ToString("N")); - var indexerClosureType = tb.DefineNestedType("IndexerClosure_" + Guid.NewGuid().ToString("N")); + var indexerClosureType = _sreBuilder.DefineType("IndexerClosure_" + Guid.NewGuid().ToString("N")); var compiler = new AvaloniaXamlIlCompiler(new AvaloniaXamlIlCompilerConfiguration(_sreTypeSystem, asm, _sreMappings, _sreXmlns, AvaloniaXamlIlLanguage.CustomValueConverter, diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs index 04bb3fe96f..413c84b3c5 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs @@ -30,13 +30,19 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers { if (directive.Namespace == XamlNamespaces.Xaml2006 && directive.Name == "DataContextType" - && directive.Values.Count == 1 - && directive.Values[0] is XamlIlAstTextNode text) + && directive.Values.Count == 1) { - on.Children.Remove(child); + on.Children.RemoveAt(i); i--; - directiveDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on, - XamlIlTypeReferenceResolver.ResolveType(context, text.Text, isMarkupExtension: false, text, strict: true).Type); + if (directive.Values[0] is XamlIlAstTextNode text) + { + directiveDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on, + XamlIlTypeReferenceResolver.ResolveType(context, text.Text, isMarkupExtension: false, text, strict: true).Type); + } + else + { + throw new XamlIlParseException("x:DataContextType should be set to a type name.", directive.Values[0]); + } } } else if (child is XamlIlAstXamlPropertyValueNode pv diff --git a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlPropertyInfoAccessorFactoryEmitter.cs b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlPropertyInfoAccessorFactoryEmitter.cs index 257a11914e..970c52a2f0 100644 --- a/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlPropertyInfoAccessorFactoryEmitter.cs +++ b/src/Markup/Avalonia.Markup.Xaml/XamlIl/CompilerExtensions/XamlIlPropertyInfoAccessorFactoryEmitter.cs @@ -11,11 +11,12 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions { class XamlIlPropertyInfoAccessorFactoryEmitter { - private bool _indexerClosureTypeInitialized = false; - private readonly IXamlIlTypeBuilder _indexerClosureType; + private const string IndexerClosureFactoryMethodName = "CreateAccessor"; + private readonly IXamlIlTypeBuilder _indexerClosureTypeBuilder; + private IXamlIlType _indexerClosureType; public XamlIlPropertyInfoAccessorFactoryEmitter(IXamlIlTypeBuilder indexerClosureType) { - _indexerClosureType = indexerClosureType; + _indexerClosureTypeBuilder = indexerClosureType; } public IXamlIlType EmitLoadInpcPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen) @@ -32,60 +33,70 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return EmitCreateAccessorFactoryDelegate(context, codeGen); } - private void EmitLoadPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlType type, string accessorFactoryName) + private void EmitLoadPropertyAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlType type, string accessorFactoryName, bool isStatic = true) { var types = context.GetAvaloniaTypes(); var weakReferenceType = context.Configuration.TypeSystem.GetType("System.WeakReference"); FindMethodMethodSignature accessorFactorySignature = new FindMethodMethodSignature(accessorFactoryName, types.IPropertyAccessor, weakReferenceType, types.IPropertyInfo) { - IsStatic = true + IsStatic = isStatic }; codeGen.Ldftn(type.GetMethod(accessorFactorySignature)); } public IXamlIlType EmitLoadIndexerAccessorFactory(XamlIlEmitContext context, IXamlIlEmitter codeGen, IXamlIlAstValueNode value) { - const string indexerClosureFactoryMethodName = "CreateAccessor"; - var types = context.GetAvaloniaTypes(); var intType = context.Configuration.TypeSystem.GetType("System.Int32"); - var weakReferenceType = context.Configuration.TypeSystem.GetType("System.WeakReference"); - if (!_indexerClosureTypeInitialized) + if (_indexerClosureType is null) { - var indexAccessorFactoryMethod = context.GetAvaloniaTypes().PropertyInfoAccessorFactory.GetMethod( - new FindMethodMethodSignature( - "CreateIndexerPropertyAccessor", - types.IPropertyAccessor, - weakReferenceType, - types.IPropertyInfo, - intType) - { - IsStatic = true - }); - var indexField = _indexerClosureType.DefineField(intType, "_index", false, false); - var ctor = _indexerClosureType.DefineConstructor(false, intType); - ctor.Generator - .Ldarg_0() - .Stfld(indexField); - _indexerClosureType.DefineMethod( - types.IPropertyAccessor, - new[] { weakReferenceType, types.IPropertyInfo }, - indexerClosureFactoryMethodName, - isPublic: false, - isStatic: false, - isInterfaceImpl: false) - .Generator - .Ldarg_0() - .Ldarg(1) - .Ldfld(indexField) - .EmitCall(indexAccessorFactoryMethod); + _indexerClosureType = InitializeClosureType(context); } context.Emit(value, codeGen, intType); codeGen.Newobj(_indexerClosureType.FindConstructor(new List { intType })); - EmitLoadPropertyAccessorFactory(context, codeGen, _indexerClosureType, indexerClosureFactoryMethodName); + EmitLoadPropertyAccessorFactory(context, codeGen, _indexerClosureType, IndexerClosureFactoryMethodName, isStatic: false); return EmitCreateAccessorFactoryDelegate(context, codeGen); } + private IXamlIlType InitializeClosureType(XamlIlEmitContext context) + { + var types = context.GetAvaloniaTypes(); + var intType = context.Configuration.TypeSystem.GetType("System.Int32"); + var weakReferenceType = context.Configuration.TypeSystem.GetType("System.WeakReference"); + var indexAccessorFactoryMethod = context.GetAvaloniaTypes().PropertyInfoAccessorFactory.GetMethod( + new FindMethodMethodSignature( + "CreateIndexerPropertyAccessor", + types.IPropertyAccessor, + weakReferenceType, + types.IPropertyInfo, + intType) + { + IsStatic = true + }); + var indexField = _indexerClosureTypeBuilder.DefineField(intType, "_index", false, false); + var ctor = _indexerClosureTypeBuilder.DefineConstructor(false, intType); + ctor.Generator + .Ldarg_0() + .Ldarg(1) + .Stfld(indexField) + .Ret(); + _indexerClosureTypeBuilder.DefineMethod( + types.IPropertyAccessor, + new[] { weakReferenceType, types.IPropertyInfo }, + IndexerClosureFactoryMethodName, + isPublic: true, + isStatic: false, + isInterfaceImpl: false) + .Generator + .Ldarg(1) + .Ldarg(2) + .LdThisFld(indexField) + .EmitCall(indexAccessorFactoryMethod) + .Ret(); + + return _indexerClosureTypeBuilder.CreateType(); + } + private IXamlIlType EmitCreateAccessorFactoryDelegate(XamlIlEmitContext context, IXamlIlEmitter codeGen) { var types = context.GetAvaloniaTypes(); diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs index 530912be5a..5a7da770a1 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/Xaml/XamlIlTests.cs @@ -302,7 +302,7 @@ namespace Avalonia.Markup.Xaml.UnitTests "); + xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml' x:DataContextType='local:XamlIlBugTestsDataContext' />"); } }