diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 904f05a9a652e..517cf8ba44d77 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -7883,6 +7883,8 @@ NOTE(result_builder_infer_add_return, none, NOTE(result_builder_infer_pick_specific, none, "apply result builder %0 (inferred from %select{protocol|dynamic replacement of}1 %2)", (Type, unsigned, DeclName)) +ERROR(result_builder_generic_inference_failed, none, + "unable to infer generic arguments for result builder %0", (DeclAttribute)) GROUPED_WARNING(result_builder_missing_limited_availability, ResultBuilderMethods, none, "result builder %0 does not implement 'buildLimitedAvailability'; " diff --git a/include/swift/AST/TypeCheckRequests.h b/include/swift/AST/TypeCheckRequests.h index 53ce7d9c4ad38..9dce96eed9dc2 100644 --- a/include/swift/AST/TypeCheckRequests.h +++ b/include/swift/AST/TypeCheckRequests.h @@ -4160,6 +4160,10 @@ enum class CustomAttrTypeKind { /// Global actors are represented as custom type attributes. They don't /// have any particularly interesting semantics. GlobalActor, + + /// Result builder types can have their generics arguments + /// inferred from the attached declaration. + ResultBuilder, }; void simple_display(llvm::raw_ostream &out, CustomAttrTypeKind value); diff --git a/include/swift/Sema/ConstraintSystem.h b/include/swift/Sema/ConstraintSystem.h index 4e94189a1c963..edc7bffb5c893 100644 --- a/include/swift/Sema/ConstraintSystem.h +++ b/include/swift/Sema/ConstraintSystem.h @@ -606,6 +606,9 @@ enum class ConstraintSystemFlags { /// Disable macro expansions. DisableMacroExpansions = 0x40, + + /// Don't record a failed constraint after adding an unsolvable constraint. + DisableRecordFailedConstraint = 0x80, }; /// Options that affect the constraint system as a whole. @@ -2287,6 +2290,9 @@ class ConstraintSystem { /// Whether we should record the failure of a constraint. bool shouldRecordFailedConstraint() const { + if (Options.contains(ConstraintSystemFlags::DisableRecordFailedConstraint)) + return false; + // If we're debugging, always note a failure so we can print it out. if (isDebugMode()) return true; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 44828b5937170..ff67a31a39369 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -568,6 +568,8 @@ Type Decl::getResolvedCustomAttrType(CustomAttr *attr) const { kind = CustomAttrTypeKind::GlobalActor; } else if (nominal->getAttrs().hasAttribute()) { kind = CustomAttrTypeKind::PropertyWrapper; + } else if (nominal->getAttrs().hasAttribute()) { + kind = CustomAttrTypeKind::ResultBuilder; } else { kind = CustomAttrTypeKind::NonGeneric; } diff --git a/lib/AST/TypeCheckRequests.cpp b/lib/AST/TypeCheckRequests.cpp index c81be39752f0c..000890bfe1008 100644 --- a/lib/AST/TypeCheckRequests.cpp +++ b/lib/AST/TypeCheckRequests.cpp @@ -1874,6 +1874,10 @@ void swift::simple_display(llvm::raw_ostream &out, CustomAttrTypeKind value) { case CustomAttrTypeKind::GlobalActor: out << "global-actor"; return; + + case CustomAttrTypeKind::ResultBuilder: + out << "result-builder"; + return; } llvm_unreachable("bad kind"); diff --git a/lib/Sema/TypeCheckRequestFunctions.cpp b/lib/Sema/TypeCheckRequestFunctions.cpp index 4effb4bc8b2b5..542f4ffd138e2 100644 --- a/lib/Sema/TypeCheckRequestFunctions.cpp +++ b/lib/Sema/TypeCheckRequestFunctions.cpp @@ -443,7 +443,7 @@ Type ResultBuilderTypeRequest::evaluate(Evaluator &evaluator, auto &ctx = dc->getASTContext(); Type type = evaluateOrDefault( evaluator, - CustomAttrTypeRequest{mutableAttr, dc, CustomAttrTypeKind::NonGeneric}, + CustomAttrTypeRequest{mutableAttr, dc, CustomAttrTypeKind::ResultBuilder}, Type()); if (!type || type->hasError()) return Type(); diff --git a/lib/Sema/TypeCheckType.cpp b/lib/Sema/TypeCheckType.cpp index 479106cfd1a62..95af241ddfca9 100644 --- a/lib/Sema/TypeCheckType.cpp +++ b/lib/Sema/TypeCheckType.cpp @@ -30,6 +30,7 @@ #include "swift/AST/ASTVisitor.h" #include "swift/AST/ASTWalker.h" #include "swift/AST/ConformanceLookup.h" +#include "swift/AST/Decl.h" #include "swift/AST/DiagnosticsParse.h" #include "swift/AST/DiagnosticsSema.h" #include "swift/AST/ExistentialLayout.h" @@ -57,6 +58,7 @@ #include "swift/ClangImporter/ClangImporter.h" #include "swift/Parse/Lexer.h" #include "swift/Sema/SILTypeResolutionContext.h" +#include "swift/Sema/TypeVariableType.h" #include "swift/Strings.h" #include "swift/Subsystems.h" #include "clang/AST/ASTContext.h" @@ -3681,7 +3683,7 @@ TypeResolver::resolveAttributedType(TypeRepr *repr, TypeResolutionOptions option else ty = resolveASTFunctionType(fnRepr, options, &attrs); - // Boxes + // Boxes } else if (auto boxRepr = dyn_cast(repr)) { ty = resolveSILBoxType(boxRepr, options, &attrs); @@ -7258,20 +7260,278 @@ void TypeChecker::checkExistentialTypes( checker.checkRequirements(genericParams->getRequirements()); } +/// Opens a result builder `UnboundGenericType` into a `BoundGenericType` +/// by creating and solving a constraint between the result builder's +/// result type and the return type of the attached declaration. +struct ResultBuilderUnboundTypeOpener { + DeclContext *dc; + CustomAttr *attr; + + Type operator()(UnboundGenericType *unboundTy) const { + return open(unboundTy, /*genericArgs=*/{}); + } + + // Opens a partially-bound result builder type by evaluating any + // placeholder types in the generic signature + Type openPlaceholders(Type type) const { + auto &ctx = dc->getASTContext(); + + if (!type->hasPlaceholder()) { + return type; + } + + // @Builder<_>: placeholder is in the type's own generic args + if (auto *boundGeneric = type->getAs()) { + if (auto *nominalDecl = + dyn_cast(boundGeneric->getDecl())) { + auto *unboundTy = UnboundGenericType::get( + nominalDecl, boundGeneric->getParent(), ctx); + return open(unboundTy, boundGeneric->getGenericArgs()); + } + } + + // @Array<_>.Builder: placeholder is in the parent type + else if (auto *nominalType = type->getAs()) { + if (auto *parentBoundGeneric = + nominalType->getParent()->getAs()) { + if (auto *parentNominalDecl = + dyn_cast(parentBoundGeneric->getDecl())) { + auto *unboundParent = UnboundGenericType::get( + parentNominalDecl, parentBoundGeneric->getParent(), ctx); + auto solvedParent = + open(unboundParent, parentBoundGeneric->getGenericArgs()); + + if (solvedParent->hasError()) { + return solvedParent; + } + + return NominalType::get(nominalType->getDecl(), solvedParent, ctx); + } + } + } + return type; + } + + /// Opens the given result builder type by solving its generic parameters + /// against the owning declaration's return type. + /// + /// If `genericArgs` is provided, any non-placeholder type remains + /// constrained to that type, and only the placeholders are solved. + Type open(UnboundGenericType *unboundTy, + ArrayRef genericArgs = {}) const { + auto resultBuilderDecl = attr->getNominalDecl(); + if (!resultBuilderDecl) { + return invalidResultBuilderType(); + } + + auto unboundTyDecl = + dyn_cast_or_null(unboundTy->getDecl()); + if (!unboundTyDecl) { + return invalidResultBuilderType(); + } + + auto owningDeclReturnType = getOwningDeclReturnType(); + if (!owningDeclReturnType) { + return invalidResultBuilderType(); + } + + // Retrieve the supported result types of the result builder. + auto resultTypes = getResultBuilderResultTypes(resultBuilderDecl); + if (resultTypes.empty()) { + return invalidResultBuilderType(); + } + + auto genericSig = unboundTyDecl->getGenericSignature(); + + // Try each result type and return the first one that + // produces a valid solution. + for (auto resultType : resultTypes) { + using namespace constraints; + + // Avoid recording failed constraints, which are not used here. + ConstraintSystemOptions options; + options |= ConstraintSystemFlags::DisableRecordFailedConstraint; + + ConstraintSystem cs(dc, options); + + // For each generic parameter position, either pin the fixed argument + // (when genericArgs supplies a non-placeholder at that index) or create a + // type variable to be solved. + llvm::SmallVector typeVarReplacements; + for (unsigned i = 0; i < genericSig.getGenericParams().size(); ++i) { + if (i < genericArgs.size() && !genericArgs[i]->hasPlaceholder()) { + typeVarReplacements.push_back(genericArgs[i]); + } else { + auto locator = cs.getConstraintLocator( + unboundTyDecl, {ConstraintLocator::GenericArgument, i}); + auto makeTypeVar = [&] { + return Type(cs.createTypeVariable(locator, TVO_CanBindToHole)); + }; + + if (i >= genericArgs.size()) { + typeVarReplacements.push_back(makeTypeVar()); + } else { + typeVarReplacements.push_back( + genericArgs[i].transformRec([&](Type t) -> std::optional { + if (t->is()) { + return makeTypeVar(); + } else { + return std::nullopt; + } + })); + } + } + } + + // Replace any references to the result builder's generic params + // in the result type with the corresponding replacements. + auto subMap = SubstitutionMap::get(genericSig, typeVarReplacements, + LookUpConformanceInModule()); + + auto resultTypeWithTypeVars = resultType.subst(subMap); + + // The result builder result type should be equal to the return type of + // the attached declaration. + cs.addConstraint(ConstraintKind::Equal, owningDeclReturnType, + resultTypeWithTypeVars, + /*preparedOverload:*/ nullptr); + + auto solution = cs.solveSingle(); + + // If a solution exists, build the final replacement list by substituting + // all type variables with their solved bindings. + if (solution) { + llvm::SmallVector solvedReplacements; + for (auto replacement : typeVarReplacements) { + solvedReplacements.push_back( + replacement.transformRec([&](Type t) -> std::optional { + if (auto *typeVar = t->getAs()) { + return solution->typeBindings[typeVar]; + } else { + return std::nullopt; + } + })); + } + + return BoundGenericType::get(unboundTyDecl, unboundTy->getParent(), + solvedReplacements); + } + } + + // No result type produced a valid solution + return invalidResultBuilderType(); + } + +private: + Type invalidResultBuilderType() const { + dc->getASTContext().Diags.diagnose( + attr->getTypeExpr()->getLoc(), + diag::result_builder_generic_inference_failed, attr); + + return ErrorType::get(dc->getASTContext()); + } + + /// Retrieve the return type of the owning declaration that + /// provides type inference for the result builder type. + Type getOwningDeclReturnType() const { + Decl *owningDecl = attr->getOwner().getAsDecl(); + if (!owningDecl) { + return nullptr; + } + + Type owningDeclReturnType; + if (auto varDecl = dyn_cast(owningDecl)) { + if (auto closureResultType = + varDecl->getInterfaceType()->getAs()) { + owningDeclReturnType = closureResultType->getResult(); + } else { + owningDeclReturnType = varDecl->getInterfaceType(); + } + } else if (auto funcDecl = dyn_cast(owningDecl)) { + owningDeclReturnType = funcDecl->getResultInterfaceType(); + } + + return owningDeclReturnType; + } + + /// Retrieves the valid result types of the result builder + /// (the return types of `buildFinalResult` / `buildBlock` / + /// `buildPartialBlock`). + llvm::SmallVector + getResultBuilderResultTypes(NominalTypeDecl *builder) const { + ASTContext &ctx = builder->getASTContext(); + llvm::SmallVector resultTypes; + + Identifier methodIds[] = {ctx.Id_buildFinalResult, ctx.Id_buildBlock, + ctx.Id_buildPartialBlock}; + + for (auto methodId : methodIds) { + SmallVector potentialMatches; + bool supportsMethod = TypeChecker::typeSupportsBuilderOp( + builder->getDeclaredInterfaceType(), builder, methodId, + /*argLabels=*/{}, &potentialMatches); + + if (!supportsMethod) + continue; + + for (auto decl : potentialMatches) { + auto func = dyn_cast(decl); + if (!func || !func->isStatic()) + continue; + + auto resultType = func->getResultInterfaceType(); + if (!resultType || resultType->hasError()) + continue; + + // Add the result type if we haven't seen it before + bool isDuplicate = false; + for (auto existingType : resultTypes) { + if (existingType->isEqual(resultType)) { + isDuplicate = true; + break; + } + } + + if (!isDuplicate) { + resultTypes.push_back(resultType); + } + } + } + + return resultTypes; + } +}; + Type CustomAttrTypeRequest::evaluate(Evaluator &eval, CustomAttr *attr, DeclContext *dc, CustomAttrTypeKind typeKind) const { const TypeResolutionOptions options(TypeResolverContext::PatternBindingDecl); OpenUnboundGenericTypeFn unboundTyOpener = nullptr; - // Property delegates allow their type to be an unbound generic. + HandlePlaceholderTypeReprFn placeholderHandler = nullptr; + + // Property wrappers and result builders allow their type to be an unbound + // generic. if (typeKind == CustomAttrTypeKind::PropertyWrapper) { unboundTyOpener = TypeResolution::defaultUnboundTypeOpener; + } else if (typeKind == CustomAttrTypeKind::ResultBuilder) { + auto &ctx = dc->getASTContext(); + void *mem = ctx.Allocate(sizeof(ResultBuilderUnboundTypeOpener), + alignof(ResultBuilderUnboundTypeOpener)); + unboundTyOpener = *new (mem) ResultBuilderUnboundTypeOpener{dc, attr}; + placeholderHandler = PlaceholderType::get; } - const auto type = TypeResolution::resolveContextualType( + auto type = TypeResolution::resolveContextualType( attr->getTypeRepr(), dc, options, unboundTyOpener, - /*placeholderHandler*/ nullptr, /*packElementOpener*/ nullptr); + /*placeholderHandler*/ placeholderHandler, + /*packElementOpener*/ nullptr); + + // Open any pl + if (typeKind == CustomAttrTypeKind::ResultBuilder && type->hasPlaceholder()) { + ResultBuilderUnboundTypeOpener opener{dc, attr}; + type = opener.openPlaceholders(type); + } // We always require the type to resolve to a nominal type. If the type was // not a nominal type, we should have already diagnosed an error via diff --git a/test/Constraints/result_builder_diags.swift b/test/Constraints/result_builder_diags.swift index 709b2dc6403a9..d6fa00ae45dc1 100644 --- a/test/Constraints/result_builder_diags.swift +++ b/test/Constraints/result_builder_diags.swift @@ -1079,3 +1079,350 @@ func testNoDuplicateStmtDiags() { } } } + +@resultBuilder +enum SimpleArrayBuilder { + static func buildBlock(_ elements: ElementKind...) -> [ElementKind] { + elements + } +} + +@resultBuilder +enum SimpleDictionaryBuilder { + static func buildBlock(_ elements: (Key, Value)...) -> [Key: Value] { + var dict = [Key: Value]() + for element in elements { + dict[element.0] = element.1 + } + return dict + } +} + +@resultBuilder +enum CollectionBuilder { + static func buildBlock(_ component: Element...) -> [Element] { + component + } + + static func buildFinalResult(_ component: [Element]) -> [Element] { + component + } + + static func buildFinalResult(_ component: [Element]) -> Set where Element: Hashable { + Set(component) + } +} + +func testInferResultBuilderGenerics() { + @SimpleArrayBuilder + var stringArray: [String] { + "foo" + "bar" + } + + @SimpleArrayBuilder + func makeStringArray() -> Array { + "foo" + "bar" + } + + func takesClosure(@SimpleArrayBuilder _ makeArray: () -> [String]) { + print(makeArray()) + } + + @SimpleArrayBuilder // expected-error{{unable to infer generic arguments for result builder @SimpleArrayBuilder}} + var string: String { + "foo" + } + + @SimpleArrayBuilder + var elements: [String] { + "foo" + "bar" + } + + @SimpleArrayBuilder<(_, _)> + var elements2: [(String, Int)] { + ("foo", 42) + } + + @SimpleArrayBuilder<(String, _)> + var elements3: [(String, Int)] { + ("foo", 42) + } + + @SimpleArrayBuilder<(_, Int)> + var elements4: [(String, Int)] { + ("foo", 42) + } + + @SimpleArrayBuilder<(Int, _)> // expected-error {{unable to infer generic arguments for result builder @SimpleArrayBuilder<(Int, _)>}} expeced-error {{cannot convert return expression of type '(String, Int)' to return type '[(String, Int)]'}} + var elements5: [(String, Int)] { + ("foo", 42) // expected-error {{cannot convert return expression of type '(String, Int)' to return type '[(String, Int)]'}} + } + + @SimpleArrayBuilder<(_, String)> + var elements6: [(String, Int)] { // expected-error {{cannot convert return expression of type '[(String, String)]' to return type '[(String, Int)]'}} expected-note {{arguments to generic parameter 'Element' ('(String, String)' and '(String, Int)') are expected to be equal}} + ("foo", 42) // expected-error {{cannot convert value of type '(String, Int)' to expected argument type '(String, String)'}} + } + + @SimpleArrayBuilder<(Int, String)> + var elements7: [(String, Int)] { // expected-error {{cannot convert return expression of type '[(Int, String)]' to return type '[(String, Int)]'}} expected-note {{arguments to generic parameter 'Element' ('(Int, String)' and '(String, Int)') are expected to be equal}} + ("foo", 42) // expected-error {{cannot convert value of type '(String, Int)' to expected argument type '(Int, String)'}} + } + + @SimpleDictionaryBuilder + var dictionary: [String: Int] { + ("foo", 42) + } + + @SimpleDictionaryBuilder<_, _> + var dictionary2: [String: Int] { + ("foo", 42) + } + + @SimpleDictionaryBuilder + var dictionary3: [String: Int] { + ("foo", 42) + } + + @SimpleDictionaryBuilder<_, Int> + var dictionary4: [String: Int] { + ("foo", 42) + } + + @SimpleDictionaryBuilder + var dictionary5: [String: Int] { // expected-error {{cannot convert return expression of type '[Int : Int]' to return type '[String : Int]'}} expected-note {{arguments to generic parameter 'Key' ('Int' and 'String') are expected to be equal}} + ("foo", 42) // expected-error {{cannot convert value of type '(String, Int)' to expected argument type '(Int, Int)'}} + } + + struct MyValue { + @SimpleArrayBuilder var array1: [String] + @SimpleArrayBuilder var array2: () -> [String] + } + + _ = MyValue( + array1: { + "foo" + "bar" + }, + array2: { + "bar" + "baaz" + }, + ) + + @SimpleArrayBuilder + var makeStringArrayClosure: () -> [String] { // expected-error {{cannot convert return expression of type '[String]' to return type '() -> [String]'}} + { // expected-error {{cannot convert value of type '() -> [String]' to expected argument type 'String'}} + ["foo"] + } + } + + @resultBuilder + struct TupleArrayBuilder { + static func buildBlock(_ elements: (One, Two)...) -> [(One, Two)] { + elements + } + } + + @TupleArrayBuilder + var tupleArray: [(String, Int)] { + ("foo", 1) + ("bar", 2) + } + + @resultBuilder + struct TooManyArgsBuilder { + static func buildBlock(_ elements: (One, Two)...) -> [(One, Two)] { + elements + } + } + + @TooManyArgsBuilder // expected-error {{unable to infer generic arguments for result builder @TooManyArgsBuilder}} + var invalidTupleArray: [(String, Int)] { + ("foo", 1) // expected-warning {{expression of type '(String, Int)' is unused}} + ("bar", 2) // expected-warning {{expression of type '(String, Int)' is unused}} + } + + @resultBuilder + enum ComplexListBuilder { + static func buildBlock(_ elements: Element...) -> [Element] { + elements + } + + static func buildFinalResult(_ component: [Element]) -> Set where Element: Hashable { + Set(component) + } + + static func buildFinalResult(_ component: [Element]) -> ContiguousArray { + ContiguousArray(component) + } + } + + @ComplexListBuilder + var stringSetFromBuildFinalResult: Set { + "foo" + "bar" + } + + @ComplexListBuilder + var contiguousStringsFromBuildFinalResult: ContiguousArray { + "foo" + "bar" + } + + @ComplexListBuilder + var stringArrayFromBuildFinalResult: [String] { // expected-error {{cannot convert return expression of type 'Set' to return type '[String]'}} + "foo" + "bar" + } + + @resultBuilder + enum PartialArrayBuilder { + static func buildPartialBlock(first: Element) -> [Element] { + [first] + } + + static func buildPartialBlock(accumulated: [Element], next: Element) -> [Element] { + accumulated + [next] + } + } + + @PartialArrayBuilder + var stringArrayFromBuildPartial: [String] { + "foo" + "bar" + } + + @CollectionBuilder + var array: [String] { + "a" + "b" + } + + @CollectionBuilder + var set: Set { + "c" + "d" + } + + @CollectionBuilder // expected-error {{unable to infer generic arguments for result builder @CollectionBuilder}} + var contiguousArray: ContiguousArray { + "c" // expected-warning {{string literal is unused}} + "d" // expected-warning {{string literal is unused}} + } +} + +extension Array { + init(@SimpleArrayBuilder build1: () -> Self) { + self = build1() + } + + init(@SimpleArrayBuilder build2: () -> [Element]) { + self = build2() + } + + init(@SimpleArrayBuilder build3: () -> Array) { + self = build3() + } + + init(@SimpleArrayBuilder build3: () -> ContiguousArray) { // expected-error {{unable to infer generic arguments for result builder @SimpleArrayBuilder}} + self = Array(build3()) + } +} + +extension Set { + init(@CollectionBuilder build: () -> Self) { + self = build() + } + + init(@CollectionBuilder build2: () -> [Element]) { + self = Set(build2()) + } + + init(@SimpleArrayBuilder build3: () -> Self) { // expected-error {{unable to infer generic arguments for result builder @SimpleArrayBuilder}} + self = build3() + } +} + +extension Array { + @resultBuilder + struct Builder { + static func buildBlock(_ elements: Element...) -> [Element] { + elements + } + } +} + +extension Dictionary { + @resultBuilder + struct Builder { + static func buildBlock(_ elements: (Key, Value)...) -> Dictionary { + Dictionary(elements, uniquingKeysWith: { $1 }) + } + } +} + +func testNonGenericResultBuildersInGenericTypeExtensions() { + @Array.Builder + var elements: [String] { + "foo" + "bar" + } + + @Array.Builder // expected-error {{unable to infer generic arguments for result builder @Array.Builder}} + var set: Set { + "foo" // expected-warning {{string literal is unused}} + "bar" // expected-warning {{string literal is unused}} + } + + @Dictionary.Builder + var dictionary: [String: String] { + ("foo", "bar") + ("baaz", "quux") + } + + @Dictionary.Builder // expected-error {{unable to infer generic arguments for result builder @Dictionary.Builder}} + var dictionary2: [(String, String)] { + ("foo", "bar") // expected-warning {{expression of type '(String, String)' is unused}} + ("baaz", "quux") // expected-warning {{expression of type '(String, String)' is unused}} + } + + @Array<_>.Builder + var elements2: [String] { + "foo" + "bar" + } + + @Array.Builder + var elements3: [String] { + "foo" + "bar" + } + + @Array<(_, _)>.Builder + var elements4: [(String, Int)] { + ("foo", 42) + } + + @Array<(String, _)>.Builder + var elements5: [(String, Int)] { + ("foo", 42) + } + + @Array<(_, Int)>.Builder + var elements6: [(String, Int)] { + ("foo", 42) + } + + @Array<(Int, _)>.Builder // expected-error {{unable to infer generic arguments for result builder @Array<(Int, _)>.Builder}} + var elements7: [(String, Int)] { + ("foo", 42) // expected-error {{cannot convert return expression of type '(String, Int)' to return type '[(String, Int)]'}} + } + + @Array<(Int, String)>.Builder + var elements8: [(String, Int)] { // expected-error {{cannot convert return expression of type '[(Int, String)]' to return type '[(String, Int)]'}} expected-note {{arguments to generic parameter 'Element' ('(Int, String)' and '(String, Int)') are expected to be equal}} + ("foo", 42) // expected-error {{cannot convert value of type '(String, Int)' to expected argument type '(Int, String)'}} + } +} diff --git a/test/decl/var/result_builders.swift b/test/decl/var/result_builders.swift index 9f3d09887d4f8..60b7f6e1a3476 100644 --- a/test/decl/var/result_builders.swift +++ b/test/decl/var/result_builders.swift @@ -65,20 +65,20 @@ func makerParamAutoclosure(@Maker // expected-error {{result builder attribute ' fn: @autoclosure () -> ()) {} @resultBuilder -struct GenericMaker {} // expected-note {{generic struct 'GenericMaker' declared here}} expected-error {{result builder must provide at least one static 'buildBlock' method}} +struct GenericMaker {} // expected-error {{result builder must provide at least one static 'buildBlock' method}} -struct GenericContainer { // expected-note {{generic struct 'GenericContainer' declared here}} +struct GenericContainer { @resultBuilder struct Maker {} // expected-error {{result builder must provide at least one static 'buildBlock' method}} } -func makeParamUnbound(@GenericMaker // expected-error {{reference to generic type 'GenericMaker' requires arguments}} +func makeParamUnbound(@GenericMaker // expected-error {{unable to infer generic arguments for result builder @GenericMaker}} fn: () -> ()) {} func makeParamBound(@GenericMaker fn: () -> ()) {} -func makeParamNestedUnbound(@GenericContainer.Maker // expected-error {{reference to generic type 'GenericContainer' requires arguments}} +func makeParamNestedUnbound(@GenericContainer.Maker // expected-error {{unable to infer generic arguments for result builder @GenericContainer.Maker}} fn: () -> ()) {} func makeParamNestedBound(@GenericContainer.Maker