diff --git a/test/Constraints/result_builder_infer.swift b/test/Constraints/result_builder_infer.swift index 878a7187818..d514ccbf404 100644 --- a/test/Constraints/result_builder_infer.swift +++ b/test/Constraints/result_builder_infer.swift @@ -1,286 +1,792 @@ -// RUN: %target-typecheck-verify-swift -disable-availability-checking +// First, test everything together. +// +// RUN: %target-typecheck-verify-swift -enum Either { - case first(T) - case second(U) +// Now to the cross-module test. The result builder and protocols go to the +// module, the rest to the importing file. +// +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/src) +// RUN: split-file %s %t/src +// +// RUN: %target-swift-frontend -emit-module -module-name M -emit-module-path %t/M.swiftmodule %t/src/M.swift +// RUN: %target-swift-frontend -typecheck -verify -I %t -D CROSS_MODULE %t/src/test.swift + +//--- M.swift + +public struct Result { + public init() {} } @resultBuilder -struct TupleBuilder { - static func buildBlock() -> () { - return () - } - - static func buildBlock(_ t1: T1) -> (T1) { - return (t1) - } - - static func buildBlock(_ t1: T1, _ t2: T2) -> (T1, T2) { - return (t1, t2) - } - - static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) - -> (T1, T2, T3) { - return (t1, t2, t3) - } - - static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) - -> (T1, T2, T3, T4) { - return (t1, t2, t3, t4) - } - - static func buildBlock( - _ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5 - ) -> (T1, T2, T3, T4, T5) { - return (t1, t2, t3, t4, t5) - } - - static func buildDo(_ value: T) -> T { return value } - static func buildIf(_ value: T?) -> T? { return value } - - static func buildEither(first value: T) -> Either { - return .first(value) - } - static func buildEither(second value: U) -> Either { - return .second(value) - } +public enum Builder { + public static func buildBlock(_: T...) -> Result { Result() } } -protocol Tupled { - associatedtype TupleType - - @TupleBuilder var tuple: TupleType { get } +public protocol P_Builder_Int1 { + @Builder + func function() -> Result + + @Builder + var property1: Result { get } + var property2: Result { @Builder get } + + @Builder + subscript(subscript1 _: Int) -> Result { get } + subscript(subscript2 _: Int) -> Result { @Builder get } } -struct TupleMe: Tupled { - var condition: Bool +public protocol P_Builder_Int2 { + @Builder + func function() -> Result - // Okay: applies the result builder @TupleBuilder. - var tuple: some Any { - "hello" - if condition { - "nested" - } - 3.14159 - "world" - } + @Builder + var property1: Result { get } + var property2: Result { @Builder get } + + @Builder + subscript(subscript1 _: Int) -> Result { get } + subscript(subscript2 _: Int) -> Result { @Builder get } } -// Witness is separated from the context declaring conformance, so don't infer -// the result builder. -struct DoNotTupleMe { - var condition: Bool +public protocol P_Builder_String { + @Builder + func function() -> Result - var tuple: some Any { // expected-error{{function declares an opaque return type, but has no return statements in its body from which to infer an underlying type}} - "hello" // expected-warning{{string literal is unused}} - "world" // expected-warning{{string literal is unused}} - // expected-note@-1 {{did you mean to return the last expression?}} {{5-5=return }} - } + @Builder + var property1: Result { get } + var property2: Result { @Builder get } + + @Builder + subscript(subscript1 _: Int) -> Result { get } + subscript(subscript2 _: Int) -> Result { @Builder get } } -extension DoNotTupleMe: Tupled { } +public protocol P_Builder_Bool { + @Builder + func function() -> Result -@resultBuilder -struct OtherTupleBuilder { - static func buildBlock() -> () { - return () - } + @Builder + var property1: Result { get } + var property2: Result { @Builder get } - static func buildBlock(_ t1: T1) -> (T1) { - return (t1) - } - - static func buildBlock(_ t1: T1, _ t2: T2) -> (T1, T2) { - return (t1, t2) - } - - static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3) - -> (T1, T2, T3) { - return (t1, t2, t3) - } - - static func buildBlock(_ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4) - -> (T1, T2, T3, T4) { - return (t1, t2, t3, t4) - } - - static func buildBlock( - _ t1: T1, _ t2: T2, _ t3: T3, _ t4: T4, _ t5: T5 - ) -> (T1, T2, T3, T4, T5) { - return (t1, t2, t3, t4, t5) - } - - static func buildDo(_ value: T) -> T { return value } - static func buildIf(_ value: T?) -> T? { return value } - - static func buildEither(first value: T) -> Either { - return .first(value) - } - static func buildEither(second value: U) -> Either { - return .second(value) - } + @Builder + subscript(subscript1 _: Int) -> Result { get } + subscript(subscript2 _: Int) -> Result { @Builder get } } -protocol Tupled2 { - associatedtype TupleType - - @TupleBuilder var tuple: TupleType { get } -} +//--- test.swift -struct TupleMe2: Tupled, Tupled2 { - var condition: Bool - - // Okay: applies the result builder @TupleBuilder, even though it satisfies - // two requirements. (They have the same result builder) - var tuple: some Any { - "hello" - if condition { - "nested" - } - 3.14159 - "world" - } -} - -protocol Tupled3 { - associatedtype TupleType - - var tuple: TupleType { @TupleBuilder get } -} - -struct TupleMe3: Tupled3 { - var condition: Bool - - var tuple: some Any { - "hello" - if condition { - "nested" - } - 3.14159 - "world" - } -} - -protocol OtherTupled { - associatedtype OtherTupleType - - @OtherTupleBuilder var tuple: OtherTupleType { get } -} - -struct AmbigTupleMe: Tupled, OtherTupled { - var condition: Bool - - // Ambiguous - // expected-note@+4{{add an explicit 'return' statement to not use a result builder}}{{+3:3-3=return <#expr#>\n}} - // expected-note@+3{{apply result builder 'TupleBuilder' (inferred from protocol 'Tupled')}}{{-1:3-3=@TupleBuilder }} - // expected-note@+2{{apply result builder 'OtherTupleBuilder' (inferred from protocol 'OtherTupled')}}{{-1:3-3=@OtherTupleBuilder }} - internal - var tuple: Void { // expected-error{{ambiguous result builder inferred for 'tuple': 'TupleBuilder' or 'OtherTupleBuilder'}} - "hello" // expected-warning{{string literal is unused}} - "world" // expected-warning{{string literal is unused}} - } -} - -// Separating the conformances resolves the ambiguity. -struct TupleMeResolvedSeparate: Tupled { - var condition: Bool - - var tuple: some Any { - "hello" - if condition { - "nested" - } - 3.14159 - "world" - } -} - -extension TupleMeResolvedSeparate: OtherTupled { } - -struct TupleMeResolvedExplicit: Tupled, OtherTupled { - var condition: Bool - - var tuple: some Any { - return "hello" - } -} - -// Inference through dynamic replacement -struct DynamicTupled: Tupled { - dynamic var tuple: some Any { - return "hello" - } -} - -extension DynamicTupled { - @_dynamicReplacement(for: tuple) - var replacementTuple: some Any { - 1 - 3.14159 - "hello" - } -} - -struct DynamicTupled2: Tupled, OtherTupled { - dynamic var tuple: some Any { - return "hello" - } -} - -extension DynamicTupled2 { - @_dynamicReplacement(for: tuple) - var replacementTuple: some Any { // expected-error{{ambiguous result builder inferred for 'replacementTuple': 'TupleBuilder' or 'OtherTupleBuilder'}} - // expected-note@-1{{add an explicit 'return' statement to not use a result builder}} - // expected-note@-2{{apply result builder 'TupleBuilder' (inferred from protocol 'Tupled')}} - // expected-note@-3{{apply result builder 'OtherTupleBuilder' (inferred from protocol 'OtherTupled')}} - 1 - } -} - -struct DynamicTupled3 { - @TupleBuilder dynamic var dynamicTuple: some Any { - 0 - } -} - -extension DynamicTupled3: OtherTupled { - @_dynamicReplacement(for: dynamicTuple) - var tuple: some Any { // expected-error{{ambiguous result builder inferred for 'tuple': 'OtherTupleBuilder' or 'TupleBuilder'}} - // expected-note@-1{{add an explicit 'return' statement to not use a result builder}} - // expected-note@-2{{apply result builder 'OtherTupleBuilder' (inferred from protocol 'OtherTupled')}} - // expected-note@-3{{apply result builder 'TupleBuilder' (inferred from dynamic replacement of 'dynamicTuple')}} - 0 - } -} +#if CROSS_MODULE +import M +#endif +// Result builder cannot be inferred from overridden declaration. do { - @resultBuilder - enum BuildBoolFrom { - static func buildBlock(_ t: T...) -> Bool {} + class Super { + @Builder func function() -> Result { 1 } } + class Sub: Super { + override public func function() -> Result { Result() } + } +} +// Result builder of dynamic replacement can be inferred from the replaced +// declaration. +struct Test1 { + @Builder + dynamic func function() -> Result { 1 } + + @Builder + dynamic var property1: Result { 1 } + dynamic var property2: Result { @Builder get { 1 } } + + @Builder + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { @Builder get { 1 } } +} +extension Test1 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { 1 } + + @_dynamicReplacement(for: property1) + var replacement_property1: Result { 1 } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { 1 } + // FIXME: expected-error@-1 {{cannot convert return expression}} + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { 1 } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { 1 } + // FIXME: expected-error@-1 {{cannot convert return expression}} +} + +// Edge case: context is a protocol extension. +protocol Test1_1 {} +extension Test1_1 { + @Builder + dynamic func function() -> Result { 1 } + + @_dynamicReplacement(for: function) + func replacement_function() -> Result { 1 } +} + +// Result builders can be inferred from protocol requirements. +do { + struct Test: P_Builder_Int1 { + func function() -> Result { 1 } + + var property1: Result { 1 } + var property2: Result { 1 } + + subscript(subscript1 _: Int) -> Result { 1 } + subscript(subscript2 _: Int) -> Result { 1 } + } +} + +// Exception: inference does not support function parameters. +do { protocol P { - @BuildBoolFrom - var property: Bool { get } + func function(@Builder _: () -> Result) + } + struct Test: P { + func function(_: () -> Result) {} } - struct Conformer1: P { - @BuildBoolFrom - var property: Bool { - // OK, explicit result builder disables inference through protocol. - 1 - 2 - } + Test().function { Result() } +} + +// Result builder of a dynamic replacement can be +// inferred from a protocol requirement that is witnessed by the replaced +// declaration. +struct Test2: P_Builder_Int1 { + dynamic func function() -> Result { 1 } + + dynamic var property1: Result { 1 } + dynamic var property2: Result { 1 } + + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { 1 } +} +extension Test2 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { 1 } + + @_dynamicReplacement(for: property1) + var replacement_property1: Result { 1 } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { 1 } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { 1 } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { 1 } +} + +// Inference from multiple conflicting sources with matching result builder +// types is unambiguous. + +struct Test3: P_Builder_Int1, P_Builder_Int2 { + dynamic func function() -> Result { 1 } + + dynamic var property1: Result { 1 } + dynamic var property2: Result { 1 } + + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { 1 } +} +extension Test3 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { 1 } + + @_dynamicReplacement(for: property1) + var replacement_property1: Result { 1 } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { 1 } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { 1 } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { 1 } +} + +struct Test4 { + @Builder dynamic func replaced_function() -> Result { 1 } + + @Builder dynamic var replaced_property1: Result { 1 } + @Builder dynamic var replaced_property2: Result { 1 } + + @Builder dynamic subscript(replaced_subscript1 _: Int) -> Result { 1 } + @Builder dynamic subscript(replaced_subscript2 _: Int) -> Result { 1 } +} +extension Test4: P_Builder_Int1 { + @_dynamicReplacement(for: replaced_function) + func function() -> Result { 1 } + + @_dynamicReplacement(for: replaced_property1) + var property1: Result { 1 } + @_dynamicReplacement(for: replaced_property2) + var property2: Result { 1 } + + @_dynamicReplacement(for: subscript(replaced_subscript1:)) + subscript(subscript1 _: Int) -> Result { 1 } + @_dynamicReplacement(for: subscript(replaced_subscript2:)) + subscript(subscript2 _: Int) -> Result { 1 } +} + +// Ambiguous inference. + +struct Test5: P_Builder_Int1, P_Builder_Int2, P_Builder_String { + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{-1:3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'function()': 'Builder' or 'Builder'}} + internal dynamic + func function() -> Result { } - struct Conformer2: P { - var property: Bool { - @BuildBoolFrom - get { - // OK, explicit result builder disables inference through protocol. - 1 - 2 - } + // FIXME: 'return' will be inserted without semicolon. + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{13-13=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{-1:3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'property1': 'Builder' or 'Builder'}} + dynamic var property1: Result { + get { 1 } // expected-error {{cannot convert return expression}} + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{10-10=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{-1:3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'property2': 'Builder' or 'Builder'}} + dynamic var property2: Result { + get {} + } + + // expected-note@+5{{add an explicit 'return' statement to not use a result builder}}{{51-51=return <#expr#>\n}} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{3-3=@Builder }} + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+2{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{3-3=@Builder }} + // expected-error@+1{{ambiguous result builder inferred for 'subscript(subscript1:)': 'Builder' or 'Builder'}} + dynamic subscript(subscript1 _: Int) -> Result {} + + // expected-note@+5{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{3-3=@Builder }} + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+2{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{3-3=@Builder }} + // expected-error@+1{{ambiguous result builder inferred for 'subscript(subscript2:)': 'Builder' or 'Builder'}} + dynamic subscript(subscript2 _: Int) -> Result { + } +} +extension Test5 { + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{-1:3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'replacement_function()': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: function) + func replacement_function() -> Result { + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{-1:3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'replacement_property1': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: property1) + var replacement_property1: Result { + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{-1:3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'replacement_property2': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: property2) + var replacement_property2: Result { + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{-1:3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'subscript(replacement_subscript1:)': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int2')}}{{-1:3-3=@Builder }} // FIXME: This is redundant; we already suggested Builder. + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'subscript(replacement_subscript2:)': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { + } +} + +struct Test6 {} +extension Test6: P_Builder_Int1, P_Builder_String { + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+3{{apply result builder 'Builder' (inferred from dynamic replacement of 'replaced_function()')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'function()': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: replaced_function) + func function() -> Result { + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+3{{apply result builder 'Builder' (inferred from dynamic replacement of 'replaced_property1')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'property1': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: replaced_property1) + var property1: Result { + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+3{{apply result builder 'Builder' (inferred from dynamic replacement of 'replaced_property2')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'property2': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: replaced_property2) + var property2: Result { + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+3{{apply result builder 'Builder' (inferred from dynamic replacement of 'subscript(replaced_subscript1:)')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'subscript(subscript1:)': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: subscript(replaced_subscript1:)) + subscript(subscript1 _: Int) -> Result { + } + + // expected-note@+6{{add an explicit 'return' statement to not use a result builder}}{{+1:3-3=return <#expr#>\n}} + // expected-note@+5{{apply result builder 'Builder' (inferred from protocol 'P_Builder_String')}}{{-1:3-3=@Builder }} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P_Builder_Int1')}}{{-1:3-3=@Builder }} + // expected-note@+3{{apply result builder 'Builder' (inferred from dynamic replacement of 'subscript(replaced_subscript2:)')}}{{-1:3-3=@Builder }} + // expected-error@+2{{ambiguous result builder inferred for 'subscript(subscript2:)': 'Builder' or 'Builder'}} + @_dynamicReplacement(for: subscript(replaced_subscript2:)) + subscript(subscript2 _: Int) -> Result { + } +} +extension Test6 { + @Builder dynamic func replaced_function() -> Result { true } + + @Builder dynamic var replaced_property1: Result { true } + @Builder dynamic var replaced_property2: Result { true } + + @Builder dynamic subscript(replaced_subscript1 _: Int) -> Result { true } + @Builder dynamic subscript(replaced_subscript2 _: Int) -> Result { true } +} + +// (?) Overridden result builders in protocol hierarchies still contribute to +// ambiguities. +do { + protocol P1 { + @Builder + func function() -> Result + } + protocol P2: P1 { + @Builder + func function() -> Result + } + protocol P3: P2 { + @Builder + func function() -> Result + } + + struct S: P3 { + // expected-note@+5{{add an explicit 'return' statement to not use a result builder}}{{+1:5-5=return <#expr#>\n}} + // expected-note@+4{{apply result builder 'Builder' (inferred from protocol 'P3')}}{{5-5=@Builder }} + // expected-note@+3{{apply result builder 'Builder' (inferred from protocol 'P1')}}{{5-5=@Builder }} + // expected-note@+2{{apply result builder 'Builder' (inferred from protocol 'P2')}}{{5-5=@Builder }} + // expected-error@+1{{ambiguous result builder inferred for 'function()': 'Builder' or 'Builder'}} + func function() -> Result { } } } + +//============================================================================== +// Inference suppression: explicit result builder. +//============================================================================== + +struct Test7 { + @Builder dynamic func function() -> Result { 1 } + + @Builder + dynamic var property1: Result { 1 } + dynamic var property2: Result { @Builder get { 1 } } + + @Builder + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { @Builder get { 1 } } +} +extension Test7 { + @Builder + @_dynamicReplacement(for: function) + func replacement_function() -> Result { true } + + @Builder + @_dynamicReplacement(for: property1) + var replacement_property1: Result { true } + + @_dynamicReplacement(for: property2) + var replacement_property2: Result { + @Builder get { true } + } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { + @Builder get { true } + } + + @Builder + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { true } +} + +struct Test8: P_Builder_Int1 { + dynamic func function() -> Result { 1 } + + dynamic var property1: Result { 1 } + dynamic var property2: Result { 1 } + + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { 1 } +} +extension Test8 { + @Builder + @_dynamicReplacement(for: function) + func replacement_function() -> Result { true } + + @Builder + @_dynamicReplacement(for: property1) + var replacement_property1: Result { true } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { @Builder get { true } } + + @Builder + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { true } + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { @Builder get { true } } +} + +// Inference from dynamically replaced declaration is prioritized +// above inference from protocol requirements that are witnessed by it. +struct Test9: P_Builder_String { + @Builder + dynamic func function() -> Result { 1 } + + @Builder + dynamic var property2: Result { 1 } + dynamic var property1: Result { @Builder get { 1 } } + + @Builder + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { @Builder get { 1 } } +} +extension Test9 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { 1 } + + @_dynamicReplacement(for: property1) + var replacement_property1: Result { 1 } + // FIXME: expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'String'}} + @_dynamicReplacement(for: property2) + var replacement_property2: Result { 1 } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { 1 } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { 1 } + // FIXME: expected-error@-1 {{cannot convert value of type 'Int' to expected argument type 'String'}} +} + +struct Test10: P_Builder_Int1, P_Builder_String { + @Builder dynamic func function() -> Result { 1 } + + @Builder + dynamic var property1: Result { 1 } + dynamic var property2: Result { @Builder get { 1 } } + + @Builder + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { @Builder get { 1 } } +} +extension Test10 { + @Builder + @_dynamicReplacement(for: function) + func replacement_function() -> Result { true } + + @Builder + @_dynamicReplacement(for: property1) + var replacement_property1: Result { true } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { @Builder get { true } } + + @Builder + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { true } + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { @Builder get { true } } +} + +//============================================================================== +// Inference suppression: return statements. +//============================================================================== + +struct Test11 { + @Builder + dynamic func function() -> Result { 1 } + + @Builder + dynamic var property1: Result { 1 } + dynamic var property2: Result { @Builder get { 1 } } + + @Builder + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { @Builder get { 1 } } +} +extension Test11 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { + do { if true { while true { return Result() } } } + } + + @_dynamicReplacement(for: property2) + var replacement_property2: Result { return Result() } + @_dynamicReplacement(for: property1) + var replacement_property1: Result { get { return Result() } } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { return Result() } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { get { return Result() } } +} + +struct Test12: P_Builder_Int1 { + dynamic func function() -> Result { 1 } + + dynamic var property1: Result { 1 } + dynamic var property2: Result { 1 } + + dynamic subscript(subscript1 _: Int) -> Result { 1 } + dynamic subscript(subscript2 _: Int) -> Result { 1 } +} +extension Test12 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { return Result() } + + @_dynamicReplacement(for: property2) + var replacement_property2: Result { return Result() } + @_dynamicReplacement(for: property1) + var replacement_property1: Result { get { return Result() } } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { return Result() } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { get { return Result() } } +} + +// Return statement in dynamically replaced declaration does not prevent the +// replacement from using it to infer a result builder. + +struct Test13 { + // @expected-note@+1 {{remove the attribute to explicitly disable the result builder}} + @Builder + dynamic func function() -> Result { + return Result() + // @expected-warning@-1 {{application of result builder 'Builder' disabled by explicit 'return' statement}} + // @expected-note@-2 {{remove 'return' statements to apply the result builder}} + } + + // @expected-note@+1 {{remove the attribute to explicitly disable the result builder}} + @Builder + dynamic var property1: Result { + return Result() + // @expected-warning@-1 {{application of result builder 'Builder' disabled by explicit 'return' statement}} + // @expected-note@-2 {{remove 'return' statements to apply the result builder}} + } + dynamic var property2: Result { + // @expected-note@+1 {{remove the attribute to explicitly disable the result builder}} + @Builder + get { + return Result() + // @expected-warning@-1 {{application of result builder 'Builder' disabled by explicit 'return' statement}} + // @expected-note@-2 {{remove 'return' statements to apply the result builder}} + } + } + + // @expected-note@+1 {{remove the attribute to explicitly disable the result builder}} + @Builder + dynamic subscript(subscript1 _: Int) -> Result { + return Result() + // @expected-warning@-1 {{application of result builder 'Builder' disabled by explicit 'return' statement}} + // @expected-note@-2 {{remove 'return' statements to apply the result builder}} + } + dynamic subscript(subscript2 _: Int) -> Result { + // @expected-note@+1 {{remove the attribute to explicitly disable the result builder}} + @Builder get { + return Result() + // @expected-warning@-1 {{application of result builder 'Builder' disabled by explicit 'return' statement}} + // @expected-note@-2 {{remove 'return' statements to apply the result builder}} + } + } +} +extension Test13 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { 1 } + + @_dynamicReplacement(for: property1) + var replacement_property1: Result { 1 } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { 1 } + // FIXME: expected-error@-1 {{cannot convert return expression}} + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { 1 } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { 1 } + // FIXME: expected-error@-1 {{cannot convert return expression}} +} + +struct Test14: P_Builder_Int1 { + dynamic func function() -> Result { return Result() } + + dynamic var property1: Result { return Result() } + dynamic var property2: Result { get { return Result() } } + + dynamic subscript(subscript1 _: Int) -> Result { return Result() } + dynamic subscript(subscript2 _: Int) -> Result { get { return Result() } } +} +extension Test14 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { 1 } + + @_dynamicReplacement(for: property1) + var replacement_property1: Result { 1 } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { 1 } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { 1 } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { 1 } +} + +struct Test15: P_Builder_Int1, P_Builder_String { + dynamic func function() -> Result { return Result() } + + dynamic var property1: Result { return Result() } + dynamic var property2: Result { get { return Result() } } + + dynamic subscript(subscript1 _: Int) -> Result { return Result() } + dynamic subscript(subscript2 _: Int) -> Result { get { return Result() } } +} +extension Test15 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { return Result() } + + @_dynamicReplacement(for: property2) + var replacement_property2: Result { return Result() } + @_dynamicReplacement(for: property1) + var replacement_property1: Result { get { return Result() } } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { return Result() } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { get { return Result() } } +} + +//============================================================================== +// Inference suppression: separation of conformance context & witness context. +// Only conformances declared on the witness context are considered in +// inference from protocol requirements. +//============================================================================== + +struct Test16 { + dynamic func function() -> Result { Result() } + + dynamic var property1: Result { Result() } + dynamic var property2: Result { Result() } + + dynamic subscript(subscript1 _: Int) -> Result { Result() } + dynamic subscript(subscript2 _: Int) -> Result { Result() } +} +extension Test16: P_Builder_Int1 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { Result() } + + @_dynamicReplacement(for: property1) + var replacement_property1: Result { Result() } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { Result() } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { Result() } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { Result() } +} + +struct Test17 { + dynamic func function() -> Result { Result() } +} +extension Test17: P_Builder_Int1 { + @_dynamicReplacement(for: function) + func replacement_function() -> Result { Result() } + + dynamic var property1: Result { 1 } +} +extension Test17: P_Builder_String { + @_dynamicReplacement(for: property1) + var replacement_property1: Result { 1 } + + dynamic var property2: Result { "1" } +} +extension Test17: P_Builder_Bool { + @_dynamicReplacement(for: property2) + var replacement_property2: Result { "1" } + + dynamic subscript(subscript1 _: Int) -> Result { true } +} +extension Test17: P_Builder_Int2 { + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { true } + + dynamic subscript(subscript2 _: Int) -> Result { 1 } +} +extension Test17 { + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { 1 } +} + +struct Test18: P_Builder_Int1, P_Builder_String, P_Builder_Bool {} +extension Test18 { + dynamic func function() -> Result { Result() } + + dynamic var property1: Result { Result() } + dynamic var property2: Result { Result() } + + dynamic subscript(subscript1 _: Int) -> Result { Result() } + dynamic subscript(subscript2 _: Int) -> Result { Result() } + + @_dynamicReplacement(for: function) + func replacement_function() -> Result { Result() } + + @_dynamicReplacement(for: property1) + var replacement_property1: Result { Result() } + @_dynamicReplacement(for: property2) + var replacement_property2: Result { Result() } + + @_dynamicReplacement(for: subscript(subscript1:)) + subscript(replacement_subscript1 _: Int) -> Result { Result() } + @_dynamicReplacement(for: subscript(subscript2:)) + subscript(replacement_subscript2 _: Int) -> Result { Result() } +} diff --git a/test/Constraints/result_builder_infer.swiftinterface b/test/Constraints/result_builder_infer.swiftinterface new file mode 100644 index 00000000000..8114a2aa70d --- /dev/null +++ b/test/Constraints/result_builder_infer.swiftinterface @@ -0,0 +1,48 @@ +// RUN: %target-typecheck-verify-swift + +// swift-interface-format-version: 1.0 +// swift-module-flags: -enable-library-evolution + +import Swift + +public struct Result {} + +@resultBuilder public enum Builder { + public static func buildBlock(_: T...) -> Result +} + +public protocol P_Builder_Int { + @Builder func function() -> Result + @Builder var property: Result { get } + @Builder subscript(_: Int) -> Result { get } +} +public protocol P_Builder_String { + @Builder func function() -> Result + @Builder var property: Result { get } + @Builder subscript(_: Int) -> Result { get } +} + +// Do not call out ambiguous result builder inference if the inferred-for +// function has no body. + +public struct Test : P_Builder_Int, P_Builder_String { + dynamic public func function() -> Result + dynamic public var property: Result { + get + } + dynamic public subscript(_: Int) -> Result { + get + } +} +extension Test { + @_dynamicReplacement(for: function) + public func replacement_function() -> Result + @_dynamicReplacement(for: property) + public var replacement_property: Result { + get + } + @_dynamicReplacement(for: subscript(_:)) + public subscript(replacement_subscript _: Int) -> Result { + get + } +}