[XamlC] Correctly load addresses of values in compiled binding paths (#5082)
authorAkihiko Odaki <akihiko.odaki.4i@stu.hosei.ac.jp>
Thu, 14 Mar 2019 12:39:29 +0000 (21:39 +0900)
committerStephane Delcroix <stephane@delcroix.org>
Thu, 14 Mar 2019 12:39:29 +0000 (13:39 +0100)
Xamarin.Forms.Build.Tasks/SetPropertiesVisitor.cs
Xamarin.Forms.Xaml.UnitTests/BindingsCompiler.xaml
Xamarin.Forms.Xaml.UnitTests/BindingsCompiler.xaml.cs

index 5d6194a..0d455f6 100644 (file)
@@ -527,6 +527,8 @@ namespace Xamarin.Forms.Build.Tasks
                                il.Emit(Ret);
                        }
                        else {
+                               var locs = new Dictionary<TypeReference, VariableDefinition>();
+
                                if (tSourceRef.IsValueType)
                                        il.Emit(Ldarga_S, (byte)0);
                                else
@@ -535,6 +537,19 @@ namespace Xamarin.Forms.Build.Tasks
                                for (int i = 0; i < properties.Count; i++) {
                                        (PropertyDefinition property, TypeReference propDeclTypeRef, string indexArg) = properties[i];
 
+                                       if (i > 0 && propDeclTypeRef.IsValueType) {
+                                               var importedPropDeclTypeRef = module.ImportReference(propDeclTypeRef);
+
+                                               if (!locs.TryGetValue(importedPropDeclTypeRef, out var loc)) {
+                                                       loc = new VariableDefinition(importedPropDeclTypeRef);
+                                                       getter.Body.Variables.Add(loc);
+                                                       locs[importedPropDeclTypeRef] = loc;
+                                               }
+
+                                               il.Emit(Stloc, loc);
+                                               il.Emit(Ldloca, loc);
+                                       }
+
                                        if (!property.PropertyType.IsValueType) { //if part of the path is null, return (default(T), false)
                                                var nop = Create(Nop);
                                                il.Emit(Dup);
@@ -543,8 +558,14 @@ namespace Xamarin.Forms.Build.Tasks
                                                il.Emit(Brfalse, nop);
                                                il.Emit(Pop);
                                                if (tPropertyRef.IsValueType) {
-                                                       var defaultValueVarDef = new VariableDefinition(tPropertyRef);
-                                                       getter.Body.Variables.Add(defaultValueVarDef);
+                                                       var importedTPropertyRef = module.ImportReference(tPropertyRef);
+
+                                                       if (!locs.TryGetValue(importedTPropertyRef, out var defaultValueVarDef)) {
+                                                               defaultValueVarDef = new VariableDefinition(tPropertyRef);
+                                                               getter.Body.Variables.Add(defaultValueVarDef);
+                                                               locs[importedTPropertyRef] = defaultValueVarDef;
+                                                       }
+
                                                        il.Emit(Ldloca_S, defaultValueVarDef);
                                                        il.Emit(Initobj, tPropertyRef);
                                                        il.Emit(Ldloc, defaultValueVarDef);
index 59a15f3..fda4a67 100644 (file)
@@ -18,6 +18,7 @@
                        <Entry Text="{Binding Text, Mode=TwoWay}" x:Name="entry0"/>
             <Label Text="{Binding .}" x:Name="label7" x:DataType="sys:Int32"/>
             <Label Text="{Binding Text, Mode=OneTime}" x:Name="label8" />
+                       <Label Text="{Binding StructModel.Text}" x:Name="label9" />
                </StackLayout>
                <Label Text="{Binding Text}" x:Name="labelWithUncompiledBinding" />
        </StackLayout>
index b5f72f8..e9967b9 100644 (file)
@@ -49,6 +49,9 @@ namespace Xamarin.Forms.Xaml.UnitTests
                                        Model = new MockViewModel {
                                                Text = "Text1"
                                        },
+                                       StructModel = new MockStructViewModel {
+                                               Text = "Text9"
+                                       }
                                };
                                vm.Model [3] = "TextIndex";
 
@@ -70,6 +73,7 @@ namespace Xamarin.Forms.Xaml.UnitTests
                                //value types
                                Assert.That(layout.label5.Text, Is.EqualTo("42"));
                                Assert.That(layout.label6.Text, Is.EqualTo("text6"));
+                               Assert.AreEqual("Text9", layout.label9.Text);
 
                                //testing selfPath
                                layout.label4.BindingContext = "Self";
@@ -145,6 +149,15 @@ namespace Xamarin.Forms.Xaml.UnitTests
                        }
                }
 
+               MockStructViewModel _structModel;
+               public MockStructViewModel StructModel {
+                       get { return _structModel; }
+                       set {
+                               _structModel = value;
+                               OnPropertyChanged();
+                       }
+               }
+
                string [] values = new string [5];
                [IndexerName("Indexer")]
                public string this [int v] {