@@ -919,3 +919,258 @@ func test_custom_tilde_equals_operator_matching() {
919919 }
920920 }
921921}
922+
923+ struct Values < T> {
924+ var values : T
925+
926+ init ( values: T ) {
927+ self . values = values
928+ }
929+
930+ func map< R> ( _ f: ( T ) -> R ) -> Values < R > {
931+ . init( values: f ( values) )
932+ }
933+ }
934+
935+ @resultBuilder
936+ enum NestedTupleBuilder {
937+ static func buildPartialBlock< T> ( first x: T ) -> Values < T > {
938+ . init( values: x)
939+ }
940+
941+ static func buildPartialBlock< T, U> (
942+ accumulated: Values < T > , next: U
943+ ) -> Values < ( T , U ) > {
944+ . init( values: ( accumulated. values, next) )
945+ }
946+ }
947+
948+ extension Values {
949+ init ( @NestedTupleBuilder nested values: ( ) -> Self ) {
950+ self = values ( )
951+ }
952+ }
953+
954+ let nestedValues = Values ( nested: {
955+ 1
956+ " 2 "
957+ 3.0
958+ " yes "
959+ } )
960+ print ( nestedValues)
961+
962+ @resultBuilder
963+ enum NestedTupleBuilder_Not {
964+ @available ( * , unavailable)
965+ static func buildPartialBlock< T> ( first x: T ) -> Values < T > {
966+ . init( values: x)
967+ }
968+
969+ @available ( * , unavailable)
970+ static func buildPartialBlock< T, U> (
971+ accumulated: Values < T > , next: U
972+ ) -> Values < ( T , U ) > {
973+ . init( values: ( accumulated. values, next) )
974+ }
975+
976+ #if os(macOS)
977+ @available ( macOS 9999 , * )
978+ static func buildPartialBlock( first x: Never ) -> Values < Never > {
979+ fatalError ( )
980+ }
981+
982+ @available ( macOS 9999 , * )
983+ static func buildPartialBlock(
984+ accumulated: Values < Never > , next: Never
985+ ) -> Values < Never > {
986+ fatalError ( )
987+ }
988+ #endif
989+
990+ // This one will be called because no `buildPartialBlock` is available.
991+ static func buildBlock( _ x: Any ... ) -> Values < [ Any ] > {
992+ . init( values: x)
993+ }
994+ }
995+
996+ extension Values {
997+ init ( @NestedTupleBuilder_Not nested_not values: ( ) -> Self ) {
998+ self = values ( )
999+ }
1000+ }
1001+
1002+ let nestedValues_not = Values ( nested_not: {
1003+ 1
1004+ " 2 "
1005+ 3.0
1006+ " yes "
1007+ } )
1008+ print ( nestedValues_not)
1009+
1010+ // CHECK: Values<Array<Any>>(values: [1, "2", 3.0, "yes"])
1011+
1012+ @resultBuilder
1013+ enum FlatTupleBuilder {
1014+ static func buildExpression< T> ( _ x: T ) -> Values < T > {
1015+ . init( values: x)
1016+ }
1017+
1018+ static func buildPartialBlock< T> ( first x: Values < T > ) -> Values < T > {
1019+ . init( values: x. values)
1020+ }
1021+
1022+ static func buildPartialBlock< T, N> (
1023+ accumulated: Values < T > ,
1024+ next: Values < N >
1025+ ) -> Values < ( T , N ) > {
1026+ . init( values: ( accumulated. values, next. values) )
1027+ }
1028+
1029+ static func buildPartialBlock< T0, T1, N> (
1030+ accumulated: Values < ( T0 , T1 ) > ,
1031+ next: Values < N >
1032+ ) -> Values < ( T0 , T1 , N ) > {
1033+ . init( values: ( accumulated. values. 0 , accumulated. values. 1 , next. values) )
1034+ }
1035+
1036+ static func buildPartialBlock< T0, T1, T2, N> (
1037+ accumulated: Values < ( T0 , T1 , T2 ) > ,
1038+ next: Values < N >
1039+ ) -> Values < ( T0 , T1 , T2 , N ) > {
1040+ . init( values: ( accumulated. values. 0 , accumulated. values. 1 , accumulated. values. 2 , next. values) )
1041+ }
1042+
1043+ static func buildPartialBlock< T0, T1, T2, T3, N> (
1044+ accumulated: Values < ( T0 , T1 , T2 , T3 ) > ,
1045+ next: Values < N >
1046+ ) -> Values < ( T0 , T1 , T2 , T3 , N ) > {
1047+ . init( values: ( accumulated. values. 0 , accumulated. values. 1 , accumulated. values. 2 , accumulated. values. 3 , next. values) )
1048+ }
1049+
1050+ static func buildBlock( _ x: Never ... ) -> Values < ( ) > {
1051+ assert ( x. isEmpty, " I should never be called unless it's nullary " )
1052+ return . init( values: ( ) )
1053+ }
1054+
1055+ static func buildEither< T> ( first: T ) -> T {
1056+ first
1057+ }
1058+
1059+ static func buildEither< T> ( second: T ) -> T {
1060+ second
1061+ }
1062+
1063+ static func buildOptional< T> ( _ x: Values < T > ? ) -> Values < T ? > {
1064+ x? . map { $0 } ?? . init( values: nil )
1065+ }
1066+
1067+ static func buildLimitedAvailability< T> ( _ x: Values < T > ) -> Values < T > {
1068+ x
1069+ }
1070+ }
1071+
1072+ extension Values {
1073+ init ( @FlatTupleBuilder flat values: ( ) -> Self ) {
1074+ self = values ( )
1075+ }
1076+ }
1077+
1078+ let flatValues0 = Values ( flat: { } )
1079+ print ( flatValues0)
1080+ // CHECK: Values<()>(values: ())
1081+
1082+ let flatValues1 = Values ( flat: {
1083+ 1
1084+ " 2 "
1085+ 3.0
1086+ } )
1087+ print ( flatValues1)
1088+ // CHECK: Values<(Int, String, Double)>(values: (1, "2", 3.0))
1089+
1090+ let flatValues2 = Values ( flat: {
1091+ 1
1092+ " 2 "
1093+ let y = 3.0 + 4.0
1094+ #if false
1095+ " not gonna happen "
1096+ #endif
1097+ if true {
1098+ " yes "
1099+ } else {
1100+ " no "
1101+ }
1102+ #warning("Beware of pairwise block building")
1103+ #if true
1104+ if false {
1105+ " nah "
1106+ }
1107+ if #available( * ) {
1108+ 5.0
1109+ }
1110+ #endif
1111+ } )
1112+ print ( flatValues2)
1113+
1114+ // CHECK: Values<(Int, String, String, Optional<String>, Optional<Double>)>(values: (1, "2", "yes", nil, Optional(5.0)))
1115+
1116+ struct Nil : CustomStringConvertible {
1117+ var description : String {
1118+ " nil "
1119+ }
1120+ }
1121+ struct Cons < Head, Tail> : CustomStringConvertible {
1122+ var head : Head
1123+ var tail : Tail
1124+
1125+ var description : String {
1126+ " (cons \( String ( reflecting: head) ) \( tail) ) "
1127+ }
1128+ }
1129+
1130+ @resultBuilder
1131+ enum ListBuilder {
1132+ static func buildBlock( ) -> Nil {
1133+ Nil ( )
1134+ }
1135+
1136+ static func buildPartialBlock< T> ( first x: T ) -> Cons < T , Nil > {
1137+ . init( head: x, tail: Nil ( ) )
1138+ }
1139+
1140+ static func buildPartialBlock< New, T> ( accumulated: T , next: New ) -> Cons < New , T > {
1141+ . init( head: next, tail: accumulated)
1142+ }
1143+
1144+ static func buildBlock< T> ( _ x: T ... ) -> [ T ] {
1145+ fatalError ( " I should never be called! " )
1146+ }
1147+ }
1148+
1149+ func list< T> ( @ListBuilder f: ( ) -> T ) -> T {
1150+ f ( )
1151+ }
1152+
1153+ let list0 = list { }
1154+ print ( list0)
1155+ // CHECK: nil
1156+
1157+ let list1 = list { " 1 " }
1158+ print ( list1)
1159+ // Check: (cons 1 nil)
1160+
1161+ let list2 = list {
1162+ 1
1163+ 2
1164+ }
1165+ print ( list2)
1166+ // CHECK: (cons 2 (cons 1 nil))
1167+ let list3 = list {
1168+ 1
1169+ list {
1170+ 2.0
1171+ " 3 "
1172+ }
1173+ " 4 "
1174+ }
1175+ print ( list3)
1176+ // CHECK: (cons "4" (cons (cons "3" (cons 2.0 nil)) (cons 1 nil)))
0 commit comments