@@ -1097,6 +1097,79 @@ selectBestBindingDisjunction(ConstraintSystem &cs,
10971097 return firstBindDisjunction;
10981098}
10991099
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+
11001173std::optional<std::pair<Constraint *, llvm::TinyPtrVector<Constraint *>>>
11011174ConstraintSystem::selectDisjunction () {
11021175 SmallVector<Constraint *, 4 > disjunctions;
@@ -1111,6 +1184,11 @@ ConstraintSystem::selectDisjunction() {
11111184 llvm::DenseMap<Constraint *, DisjunctionInfo> favorings;
11121185 determineBestChoicesInContext (*this , disjunctions, favorings);
11131186
1187+ if (auto *disjunction =
1188+ selectDisjunctionInResultBuilderContext (*this , disjunctions)) {
1189+ return std::make_pair (disjunction, favorings[disjunction].FavoredChoices );
1190+ }
1191+
11141192 // Pick the disjunction with the smallest number of favored, then active
11151193 // choices.
11161194 auto bestDisjunction = std::min_element (
0 commit comments