@@ -29,7 +29,7 @@ fn resolve_expression(
29
29
expr : & mut Expression ,
30
30
property_name : Option < & str > ,
31
31
property_type : Type ,
32
- scope : & ComponentScope ,
32
+ scope : & [ ElementRc ] ,
33
33
type_register : & TypeRegister ,
34
34
type_loader : & crate :: typeloader:: TypeLoader ,
35
35
diag : & mut BuildDiagnostics ,
@@ -38,7 +38,7 @@ fn resolve_expression(
38
38
let mut lookup_ctx = LookupCtx {
39
39
property_name,
40
40
property_type,
41
- component_scope : & scope. 0 ,
41
+ component_scope : scope,
42
42
diag,
43
43
arguments : vec ! [ ] ,
44
44
type_register,
@@ -76,6 +76,23 @@ fn resolve_expression(
76
76
}
77
77
}
78
78
79
+ /// Call the visitor for each children of the element recursively, starting with the element itself
80
+ ///
81
+ /// The item that is being visited will be pushed to the scope and popped once visitation is over.
82
+ fn recurse_elem_with_scope (
83
+ elem : & ElementRc ,
84
+ mut scope : ComponentScope ,
85
+ vis : & mut impl FnMut ( & ElementRc , & ComponentScope ) ,
86
+ ) -> ComponentScope {
87
+ scope. 0 . push ( elem. clone ( ) ) ;
88
+ vis ( elem, & scope) ;
89
+ for sub in & elem. borrow ( ) . children {
90
+ scope = recurse_elem_with_scope ( sub, scope, vis) ;
91
+ }
92
+ scope. 0 . pop ( ) ;
93
+ scope
94
+ }
95
+
79
96
pub fn resolve_expressions (
80
97
doc : & Document ,
81
98
type_loader : & crate :: typeloader:: TypeLoader ,
@@ -84,19 +101,27 @@ pub fn resolve_expressions(
84
101
resolve_two_way_bindings ( doc, & doc. local_registry , diag) ;
85
102
86
103
for component in doc. inner_components . iter ( ) {
87
- let scope = ComponentScope ( vec ! [ ] ) ;
88
-
89
- recurse_elem ( & component. root_element , & scope, & mut |elem, scope| {
90
- let mut new_scope = scope. clone ( ) ;
91
- let mut is_repeated = elem. borrow ( ) . repeated . is_some ( ) ;
92
- new_scope. 0 . push ( elem. clone ( ) ) ;
93
- visit_element_expressions ( elem, |expr, property_name, property_type| {
94
- if is_repeated {
95
- // The first expression is always the model and it needs to be resolved with the parent scope
96
- debug_assert ! ( matches!(
97
- elem. borrow( ) . repeated. as_ref( ) . unwrap( ) . model,
98
- Expression :: Invalid
99
- ) ) ; // should be Invalid because it is taken by the visit_element_expressions function
104
+ recurse_elem_with_scope (
105
+ & component. root_element ,
106
+ ComponentScope ( vec ! [ ] ) ,
107
+ & mut |elem, scope| {
108
+ let mut is_repeated = elem. borrow ( ) . repeated . is_some ( ) ;
109
+ visit_element_expressions ( elem, |expr, property_name, property_type| {
110
+ let scope = if is_repeated {
111
+ // The first expression is always the model and it needs to be resolved with the parent scope
112
+ debug_assert ! ( matches!(
113
+ elem. borrow( ) . repeated. as_ref( ) . unwrap( ) . model,
114
+ Expression :: Invalid
115
+ ) ) ; // should be Invalid because it is taken by the visit_element_expressions function
116
+
117
+ is_repeated = false ;
118
+
119
+ debug_assert ! ( scope. 0 . len( ) > 1 ) ;
120
+ & scope. 0 [ ..scope. 0 . len ( ) - 1 ]
121
+ } else {
122
+ & scope. 0
123
+ } ;
124
+
100
125
resolve_expression (
101
126
expr,
102
127
property_name,
@@ -106,21 +131,9 @@ pub fn resolve_expressions(
106
131
type_loader,
107
132
diag,
108
133
) ;
109
- is_repeated = false ;
110
- } else {
111
- resolve_expression (
112
- expr,
113
- property_name,
114
- property_type ( ) ,
115
- & new_scope,
116
- & doc. local_registry ,
117
- type_loader,
118
- diag,
119
- )
120
- }
121
- } ) ;
122
- new_scope
123
- } )
134
+ } ) ;
135
+ } ,
136
+ ) ;
124
137
}
125
138
}
126
139
@@ -1548,134 +1561,139 @@ fn resolve_two_way_bindings(
1548
1561
diag : & mut BuildDiagnostics ,
1549
1562
) {
1550
1563
for component in doc. inner_components . iter ( ) {
1551
- let scope = ComponentScope ( vec ! [ ] ) ;
1552
-
1553
- recurse_elem ( & component. root_element , & scope, & mut |elem, scope| {
1554
- let mut new_scope = scope. clone ( ) ;
1555
- new_scope. 0 . push ( elem. clone ( ) ) ;
1556
- for ( prop_name, binding) in & elem. borrow ( ) . bindings {
1557
- let mut binding = binding. borrow_mut ( ) ;
1558
- if let Expression :: Uncompiled ( node) = binding. expression . clone ( ) {
1559
- if let Some ( n) = syntax_nodes:: TwoWayBinding :: new ( node. clone ( ) ) {
1560
- let lhs_lookup = elem. borrow ( ) . lookup_property ( prop_name) ;
1561
- if !lhs_lookup. is_valid ( ) {
1562
- // An attempt to resolve this already failed when trying to resolve the property type
1563
- assert ! ( diag. has_errors( ) ) ;
1564
- continue ;
1565
- }
1566
- let mut lookup_ctx = LookupCtx {
1567
- property_name : Some ( prop_name. as_str ( ) ) ,
1568
- property_type : lhs_lookup. property_type . clone ( ) ,
1569
- component_scope : & new_scope. 0 ,
1570
- diag,
1571
- arguments : vec ! [ ] ,
1572
- type_register,
1573
- type_loader : None ,
1574
- current_token : Some ( node. clone ( ) . into ( ) ) ,
1575
- } ;
1576
-
1577
- binding. expression = Expression :: Invalid ;
1578
-
1579
- if let Some ( nr) = resolve_two_way_binding ( n, & mut lookup_ctx) {
1580
- binding. two_way_bindings . push ( nr. clone ( ) ) ;
1581
-
1582
- nr. element ( )
1583
- . borrow ( )
1584
- . property_analysis
1585
- . borrow_mut ( )
1586
- . entry ( nr. name ( ) . into ( ) )
1587
- . or_default ( )
1588
- . is_linked = true ;
1589
-
1590
- if matches ! (
1591
- lhs_lookup. property_visibility,
1592
- PropertyVisibility :: Private | PropertyVisibility :: Output
1593
- ) && !lhs_lookup. is_local_to_component
1594
- {
1595
- // invalid property assignment should have been reported earlier
1596
- assert ! ( diag. has_errors( ) ) ;
1597
- continue ;
1598
- }
1599
-
1600
- // Check the compatibility.
1601
- let mut rhs_lookup = nr. element ( ) . borrow ( ) . lookup_property ( nr. name ( ) ) ;
1602
- if rhs_lookup. property_type == Type :: Invalid {
1564
+ recurse_elem_with_scope (
1565
+ & component. root_element ,
1566
+ ComponentScope ( vec ! [ ] ) ,
1567
+ & mut |elem, scope| {
1568
+ for ( prop_name, binding) in & elem. borrow ( ) . bindings {
1569
+ let mut binding = binding. borrow_mut ( ) ;
1570
+ if let Expression :: Uncompiled ( node) = binding. expression . clone ( ) {
1571
+ if let Some ( n) = syntax_nodes:: TwoWayBinding :: new ( node. clone ( ) ) {
1572
+ let lhs_lookup = elem. borrow ( ) . lookup_property ( prop_name) ;
1573
+ if !lhs_lookup. is_valid ( ) {
1603
1574
// An attempt to resolve this already failed when trying to resolve the property type
1604
1575
assert ! ( diag. has_errors( ) ) ;
1605
1576
continue ;
1606
1577
}
1607
- rhs_lookup. is_local_to_component &=
1608
- lookup_ctx. is_local_element ( & nr. element ( ) ) ;
1609
-
1610
- if !rhs_lookup. is_valid_for_assignment ( ) {
1611
- match (
1578
+ let mut lookup_ctx = LookupCtx {
1579
+ property_name : Some ( prop_name. as_str ( ) ) ,
1580
+ property_type : lhs_lookup. property_type . clone ( ) ,
1581
+ component_scope : & scope. 0 ,
1582
+ diag,
1583
+ arguments : vec ! [ ] ,
1584
+ type_register,
1585
+ type_loader : None ,
1586
+ current_token : Some ( node. clone ( ) . into ( ) ) ,
1587
+ } ;
1588
+
1589
+ binding. expression = Expression :: Invalid ;
1590
+
1591
+ if let Some ( nr) = resolve_two_way_binding ( n, & mut lookup_ctx) {
1592
+ binding. two_way_bindings . push ( nr. clone ( ) ) ;
1593
+
1594
+ nr. element ( )
1595
+ . borrow ( )
1596
+ . property_analysis
1597
+ . borrow_mut ( )
1598
+ . entry ( nr. name ( ) . into ( ) )
1599
+ . or_default ( )
1600
+ . is_linked = true ;
1601
+
1602
+ if matches ! (
1612
1603
lhs_lookup. property_visibility,
1613
- rhs_lookup. property_visibility ,
1614
- ) {
1615
- ( PropertyVisibility :: Input , PropertyVisibility :: Input )
1616
- if !lhs_lookup. is_local_to_component =>
1617
- {
1618
- assert ! ( rhs_lookup. is_local_to_component) ;
1619
- marked_linked_read_only ( elem, prop_name) ;
1620
- }
1621
- (
1622
- PropertyVisibility :: Output | PropertyVisibility :: Private ,
1623
- PropertyVisibility :: Output | PropertyVisibility :: Input ,
1624
- ) => {
1625
- assert ! ( lhs_lookup. is_local_to_component) ;
1626
- marked_linked_read_only ( elem, prop_name) ;
1604
+ PropertyVisibility :: Private | PropertyVisibility :: Output
1605
+ ) && !lhs_lookup. is_local_to_component
1606
+ {
1607
+ // invalid property assignment should have been reported earlier
1608
+ assert ! ( diag. has_errors( ) ) ;
1609
+ continue ;
1610
+ }
1611
+
1612
+ // Check the compatibility.
1613
+ let mut rhs_lookup =
1614
+ nr. element ( ) . borrow ( ) . lookup_property ( nr. name ( ) ) ;
1615
+ if rhs_lookup. property_type == Type :: Invalid {
1616
+ // An attempt to resolve this already failed when trying to resolve the property type
1617
+ assert ! ( diag. has_errors( ) ) ;
1618
+ continue ;
1619
+ }
1620
+ rhs_lookup. is_local_to_component &=
1621
+ lookup_ctx. is_local_element ( & nr. element ( ) ) ;
1622
+
1623
+ if !rhs_lookup. is_valid_for_assignment ( ) {
1624
+ match (
1625
+ lhs_lookup. property_visibility ,
1626
+ rhs_lookup. property_visibility ,
1627
+ ) {
1628
+ ( PropertyVisibility :: Input , PropertyVisibility :: Input )
1629
+ if !lhs_lookup. is_local_to_component =>
1630
+ {
1631
+ assert ! ( rhs_lookup. is_local_to_component) ;
1632
+ marked_linked_read_only ( elem, prop_name) ;
1633
+ }
1634
+ (
1635
+ PropertyVisibility :: Output
1636
+ | PropertyVisibility :: Private ,
1637
+ PropertyVisibility :: Output | PropertyVisibility :: Input ,
1638
+ ) => {
1639
+ assert ! ( lhs_lookup. is_local_to_component) ;
1640
+ marked_linked_read_only ( elem, prop_name) ;
1641
+ }
1642
+ ( PropertyVisibility :: Input , PropertyVisibility :: Output )
1643
+ if !lhs_lookup. is_local_to_component =>
1644
+ {
1645
+ assert ! ( !rhs_lookup. is_local_to_component) ;
1646
+ marked_linked_read_only ( elem, prop_name) ;
1647
+ }
1648
+ _ => {
1649
+ if lookup_ctx. is_legacy_component ( ) {
1650
+ diag. push_warning (
1651
+ format ! (
1652
+ "Link to a {} property is deprecated" ,
1653
+ rhs_lookup. property_visibility
1654
+ ) ,
1655
+ & node,
1656
+ ) ;
1657
+ } else {
1658
+ diag. push_error (
1659
+ format ! (
1660
+ "Cannot link to a {} property" ,
1661
+ rhs_lookup. property_visibility
1662
+ ) ,
1663
+ & node,
1664
+ )
1665
+ }
1666
+ }
1627
1667
}
1628
- ( PropertyVisibility :: Input , PropertyVisibility :: Output )
1629
- if !lhs_lookup. is_local_to_component =>
1668
+ } else if !lhs_lookup. is_valid_for_assignment ( ) {
1669
+ if rhs_lookup. is_local_to_component
1670
+ && rhs_lookup. property_visibility
1671
+ == PropertyVisibility :: InOut
1630
1672
{
1631
- assert ! ( !rhs_lookup. is_local_to_component) ;
1632
- marked_linked_read_only ( elem, prop_name) ;
1633
- }
1634
- _ => {
1635
1673
if lookup_ctx. is_legacy_component ( ) {
1636
- diag. push_warning (
1637
- format ! (
1638
- "Link to a {} property is deprecated" ,
1639
- rhs_lookup. property_visibility
1640
- ) ,
1641
- & node,
1642
- ) ;
1674
+ debug_assert ! ( !diag. is_empty( ) ) ; // warning should already be reported
1643
1675
} else {
1644
1676
diag. push_error (
1645
- format ! (
1646
- "Cannot link to a {} property" ,
1647
- rhs_lookup. property_visibility
1648
- ) ,
1677
+ "Cannot link input property" . into ( ) ,
1649
1678
& node,
1650
- )
1679
+ ) ;
1651
1680
}
1652
- }
1653
- }
1654
- } else if !lhs_lookup. is_valid_for_assignment ( ) {
1655
- if rhs_lookup. is_local_to_component
1656
- && rhs_lookup. property_visibility == PropertyVisibility :: InOut
1657
- {
1658
- if lookup_ctx. is_legacy_component ( ) {
1659
- debug_assert ! ( !diag. is_empty( ) ) ; // warning should already be reported
1681
+ } else if rhs_lookup. property_visibility
1682
+ == PropertyVisibility :: InOut
1683
+ {
1684
+ diag. push_warning ( "Linking input properties to input output properties is deprecated" . into ( ) , & node) ;
1685
+ marked_linked_read_only ( & nr. element ( ) , nr. name ( ) ) ;
1660
1686
} else {
1661
- diag. push_error ( "Cannot link input property" . into ( ) , & node) ;
1687
+ // This is allowed, but then the rhs must also become read only.
1688
+ marked_linked_read_only ( & nr. element ( ) , nr. name ( ) ) ;
1662
1689
}
1663
- } else if rhs_lookup. property_visibility
1664
- == PropertyVisibility :: InOut
1665
- {
1666
- diag. push_warning ( "Linking input properties to input output properties is deprecated" . into ( ) , & node) ;
1667
- marked_linked_read_only ( & nr. element ( ) , nr. name ( ) ) ;
1668
- } else {
1669
- // This is allowed, but then the rhs must also become read only.
1670
- marked_linked_read_only ( & nr. element ( ) , nr. name ( ) ) ;
1671
1690
}
1672
1691
}
1673
1692
}
1674
1693
}
1675
1694
}
1676
- }
1677
- new_scope
1678
- } )
1695
+ } ,
1696
+ ) ;
1679
1697
}
1680
1698
1681
1699
fn marked_linked_read_only ( elem : & ElementRc , prop_name : & str ) {
0 commit comments