@@ -1097,6 +1097,79 @@ selectBestBindingDisjunction(ConstraintSystem &cs,
1097
1097
return firstBindDisjunction;
1098
1098
}
1099
1099
1100
+ // / Prioritize `build{Block, Expression, ...}` and any chained
1101
+ // / members that are connected to individual builder elements
1102
+ // / i.e. `ForEach(...) { ... }.padding(...)`, once `ForEach`
1103
+ // / is resolved, `padding` should be prioritized because its
1104
+ // / requirements can help prune the solution space before the
1105
+ // / body is checked.
1106
+ static Constraint *
1107
+ selectDisjunctionInResultBuilderContext (ConstraintSystem &cs,
1108
+ ArrayRef<Constraint *> disjunctions) {
1109
+ auto context = AnyFunctionRef::fromDeclContext (cs.DC );
1110
+ if (!context)
1111
+ return nullptr ;
1112
+
1113
+ if (!cs.getAppliedResultBuilderTransform (context.value ()))
1114
+ return nullptr ;
1115
+
1116
+ std::pair<Constraint *, unsigned > best{nullptr , 0 };
1117
+ for (auto *disjunction : disjunctions) {
1118
+ auto *member =
1119
+ getAsExpr<UnresolvedDotExpr>(disjunction->getLocator ()->getAnchor ());
1120
+ if (!member)
1121
+ continue ;
1122
+
1123
+ // Attempt `build{Block, Expression, ...} first because they
1124
+ // provide contextual information for the inner calls.
1125
+ if (isResultBuilderMethodReference (cs.getASTContext (), member))
1126
+ return disjunction;
1127
+
1128
+ Expr *curr = member;
1129
+ bool disqualified = false ;
1130
+ // Walk up the parent expression chain and check whether this
1131
+ // disjunction represents one of the members in a chain that
1132
+ // leads up to `buildExpression` (if defined by the builder)
1133
+ // or to a pattern binding for `$__builderN` (the walk won't
1134
+ // find any argument position locations in that case).
1135
+ while (auto parent = cs.getParentExpr (curr)) {
1136
+ if (!(isExpr<CallExpr>(parent) || isExpr<UnresolvedDotExpr>(parent))) {
1137
+ disqualified = true ;
1138
+ break ;
1139
+ }
1140
+
1141
+ if (auto *call = getAsExpr<CallExpr>(parent)) {
1142
+ // The current parent appears in an argument position.
1143
+ if (call->getFn () != curr) {
1144
+ // Allow expressions that appear in a argument position to
1145
+ // `build{Expression, Block, ...} methods.
1146
+ if (auto *UDE = getAsExpr<UnresolvedDotExpr>(call->getFn ())) {
1147
+ disqualified =
1148
+ !isResultBuilderMethodReference (cs.getASTContext (), UDE);
1149
+ } else {
1150
+ disqualified = true ;
1151
+ }
1152
+ }
1153
+ }
1154
+
1155
+ if (disqualified)
1156
+ break ;
1157
+
1158
+ curr = parent;
1159
+ }
1160
+
1161
+ if (disqualified)
1162
+ continue ;
1163
+
1164
+ if (auto depth = cs.getExprDepth (member)) {
1165
+ if (!best.first || best.second > depth)
1166
+ best = std::make_pair (disjunction, depth.value ());
1167
+ }
1168
+ }
1169
+
1170
+ return best.first ;
1171
+ }
1172
+
1100
1173
std::optional<std::pair<Constraint *, llvm::TinyPtrVector<Constraint *>>>
1101
1174
ConstraintSystem::selectDisjunction () {
1102
1175
SmallVector<Constraint *, 4 > disjunctions;
@@ -1111,6 +1184,11 @@ ConstraintSystem::selectDisjunction() {
1111
1184
llvm::DenseMap<Constraint *, DisjunctionInfo> favorings;
1112
1185
determineBestChoicesInContext (*this , disjunctions, favorings);
1113
1186
1187
+ if (auto *disjunction =
1188
+ selectDisjunctionInResultBuilderContext (*this , disjunctions)) {
1189
+ return std::make_pair (disjunction, favorings[disjunction].FavoredChoices );
1190
+ }
1191
+
1114
1192
// Pick the disjunction with the smallest number of favored, then active
1115
1193
// choices.
1116
1194
auto bestDisjunction = std::min_element (
0 commit comments