diff --git a/lib/AST/ParameterPack.cpp b/lib/AST/ParameterPack.cpp index ee98cccfd4a95..c05e1ce82a28e 100644 --- a/lib/AST/ParameterPack.cpp +++ b/lib/AST/ParameterPack.cpp @@ -453,8 +453,11 @@ PackType::getExpandedGenericArgs(ArrayRef params, } PackType *PackType::getSingletonPackExpansion(Type param) { - assert(param->isParameterPack() || param->is()); - return get(param->getASTContext(), {PackExpansionType::get(param, param)}); + SmallVector rootParameterPacks; + param->getTypeParameterPacks(rootParameterPacks); + assert(rootParameterPacks.size() >= 1); + auto count = rootParameterPacks[0]; + return get(param->getASTContext(), {PackExpansionType::get(param, count)}); } CanPackType CanPackType::getSingletonPackExpansion(CanType param) { diff --git a/lib/Sema/CSDiagnostics.h b/lib/Sema/CSDiagnostics.h index 1467e4cb8a5d9..56fdd6fb54c0f 100644 --- a/lib/Sema/CSDiagnostics.h +++ b/lib/Sema/CSDiagnostics.h @@ -449,7 +449,9 @@ class SameShapeExpansionFailure final : public FailureDiagnostic { public: SameShapeExpansionFailure(const Solution &solution, Type lhs, Type rhs, ConstraintLocator *locator) - : FailureDiagnostic(solution, locator), lhs(lhs), rhs(rhs) {} + : FailureDiagnostic(solution, locator), + lhs(resolveType(lhs)), + rhs(resolveType(rhs)) {} bool diagnoseAsError() override; }; diff --git a/lib/Sema/CSSimplify.cpp b/lib/Sema/CSSimplify.cpp index 1d2880e3d552d..d862ad03f3f56 100644 --- a/lib/Sema/CSSimplify.cpp +++ b/lib/Sema/CSSimplify.cpp @@ -1807,7 +1807,14 @@ static ConstraintSystem::TypeMatchResult matchCallArguments( } auto *argPack = PackType::get(cs.getASTContext(), argTypes); - auto *argPackExpansion = PackExpansionType::get(argPack, argPack); + auto argPackExpansion = [&]() { + if (argPack->getNumElements() == 1 && + argPack->getElementType(0)->is()) { + return argPack->getElementType(0)->castTo(); + } + + return PackExpansionType::get(argPack, argPack); + }(); auto firstArgIdx = argTypes.empty() ? paramIdx : parameterBindings[paramIdx].front(); @@ -13624,33 +13631,34 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifySameShapeConstraint( auto argLoc = loc->castLastElementTo(); - if (type1->getAs() && - type2->getAs()) + if (type1->is() && + type2->is()) return recordShapeMismatchFix(); - auto argPack = type1->getAs(); - auto paramPack = type2->getAs(); - - if (!(argPack && paramPack)) - return SolutionKind::Error; + auto numArgs = (shape1->is() + ? shape1->castTo()->getNumElements() + : 1); + auto numParams = (shape2->is() + ? shape2->castTo()->getNumElements() + : 1); // Tailed diagnostic to explode tuples. // FIXME: This is very similar to // 'cannot_convert_single_tuple_into_multiple_arguments'; can we emit // both of these in the same place? - if (argPack->getNumElements() == 1) { - if (argPack->getElementType(0)->is() && - paramPack->getNumElements() >= 1) { + if (numArgs == 1) { + if (type1->is() && + numParams >= 1) { return recordShapeFix( DestructureTupleToMatchPackExpansionParameter::create( - *this, paramPack, loc), - /*impact=*/2 * paramPack->getNumElements()); + *this, + (type2->is() + ? type2->castTo() + : PackType::getSingletonPackExpansion(type2)), loc), + /*impact=*/2 * numParams); } } - auto numArgs = shape1->castTo()->getNumElements(); - auto numParams = shape2->castTo()->getNumElements(); - // Drops `ApplyArgToParam` and left with `ApplyArgument`. path.pop_back(); diff --git a/lib/Sema/ConstraintSystem.cpp b/lib/Sema/ConstraintSystem.cpp index 18aa1f9cf0bd7..0ce68b50738e0 100644 --- a/lib/Sema/ConstraintSystem.cpp +++ b/lib/Sema/ConstraintSystem.cpp @@ -855,25 +855,7 @@ Type ConstraintSystem::openUnboundGenericType(GenericTypeDecl *decl, result = DC->mapTypeIntoContext(result); } - return result.transform([&](Type type) -> Type { - // Although generic parameters are declared with just `each` - // their interface types introduce a pack expansion which - // means that the solver has to extact generic argument type - // variable from Pack{repeat ...} and drop that structure to - // make sure that generic argument gets inferred to a pack type. - if (auto *packTy = type->getAs()) { - assert(packTy->getNumElements() == 1); - auto *expansion = packTy->getElementType(0)->castTo(); - auto *typeVar = expansion->getPatternType()->castTo(); - assert(typeVar->getImpl().getGenericParameter() && - typeVar->getImpl().canBindToPack()); - return typeVar; - } - - if (auto *expansion = dyn_cast(type.getPointer())) - return openPackExpansionType(expansion, replacements, locator); - return type; - }); + return result; } static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type, @@ -1022,18 +1004,6 @@ Type ConstraintSystem::openType(Type type, OpenedTypeMap &replacements, } } - // While opening variadic generic types that appear in other types - // we need to extract generic parameter from Pack{repeat ...} structure - // that gets introduced by the interface type, see - // \c openUnboundGenericType for more details. - if (auto *packTy = type->getAs()) { - if (auto expansionTy = packTy->unwrapSingletonPackExpansion()) { - auto patternTy = expansionTy->getPatternType(); - if (patternTy->isTypeParameter()) - return openType(patternTy, replacements, locator); - } - } - if (auto *expansion = type->getAs()) { return openPackExpansionType(expansion, replacements, locator); } @@ -3927,6 +3897,14 @@ struct TypeSimplifier { auto countType = expansion->getCountType().transform( TypeSimplifier(CS, GetFixedTypeFn)); + if (!countType->is() && + !countType->is()) { + SmallVector rootParameterPacks; + countType->getTypeParameterPacks(rootParameterPacks); + if (!rootParameterPacks.empty()) + countType = rootParameterPacks[0]; + } + // If both pattern and count are resolves, let's just return // the pattern type for `transformWithPosition` to take care // of the rest. diff --git a/test/Constraints/issue-67906.swift b/test/Constraints/issue-67906.swift new file mode 100644 index 0000000000000..56ec1da7a3aa1 --- /dev/null +++ b/test/Constraints/issue-67906.swift @@ -0,0 +1,25 @@ +// RUN: %target-typecheck-verify-swift -disable-availability-checking + +struct G: Sequence { + typealias Element = Int + typealias Iterator = [Int].Iterator + + consuming func makeIterator() -> Iterator { + fatalError() + } +} + +// expected-note@+1 {{in call to function 'foo'}} +func foo(_: repeat each T) -> G { + .init() +} + +// expected-error@+2 {{for-in loop requires '(repeat each T) -> G' to conform to 'Sequence'}} +// expected-error@+1 {{generic parameter 'each T' could not be inferred}} +for a in foo { + print(a) +} + +for a in foo() { + print(a) +} diff --git a/test/Constraints/pack-expansion-expressions.swift b/test/Constraints/pack-expansion-expressions.swift index 907e8231ee48c..84c171732785b 100644 --- a/test/Constraints/pack-expansion-expressions.swift +++ b/test/Constraints/pack-expansion-expressions.swift @@ -139,7 +139,8 @@ func tupleExpansion( _ = zip(repeat each tuple1, with: repeat each tuple1.element) // legacy syntax _ = zip(repeat each tuple1, with: repeat each tuple2) - // expected-error@-1 {{global function 'zip(_:with:)' requires the type packs 'repeat each T' and 'repeat each U' have the same shape}} + // expected-error@-1 {{global function 'zip(_:with:)' requires the type packs 'each T' and 'each U' have the same shape}} + // expected-error@-2 {{pack expansion requires that 'each U' and 'each T' have the same shape}} _ = forward(repeat each tuple3) } @@ -349,37 +350,36 @@ func test_pack_expansions_with_closures() { func test_pack_expansion_specialization(tuple: (Int, String, Float)) { struct Data { init(_: repeat each T) {} // expected-note 4 {{'init(_:)' declared here}} - init(vals: repeat each T) {} // expected-note {{'init(vals:)' declared here}} - init(x: Int, _: repeat each T, y: repeat each U) {} // expected-note 3 {{'init(x:_:y:)' declared here}} + init(vals: repeat each T) {} + init(x: Int, _: repeat each T, y: repeat each U) {} } _ = Data() // expected-error {{missing argument for parameter #1 in call}} _ = Data(0) // Ok _ = Data(42, "") // Ok - _ = Data(42, "") // expected-error {{extra argument in call}} + _ = Data(42, "") // expected-error {{pack expansion requires that 'Int' and 'Int, String' have the same shape}} _ = Data((42, "")) - // expected-error@-1 {{value pack expansion at parameter #0 expects 2 separate arguments; remove extra parentheses to change tuple into separate arguments}} {{25-26=}} {{32-33=}} + // expected-error@-1 {{initializer expects 2 separate arguments; remove extra parentheses to change tuple into separate arguments}} {{25-26=}} {{32-33=}} _ = Data(vals: (42, "", 0)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 3 separate arguments; remove extra parentheses to change tuple into separate arguments}} {{38-39=}} {{48-49=}} + // expected-error@-1 {{pack expansion requires that 'Int, String, Float' and '(Int, String, Int)' have the same shape}} _ = Data((vals: 42, "", 0)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 3 separate arguments; remove extra parentheses to change tuple into separate arguments}} {{32-33=}} {{48-49=}} + // expected-error@-1 {{initializer expects 3 separate arguments; remove extra parentheses to change tuple into separate arguments}} {{32-33=}} {{48-49=}} _ = Data(tuple) - // expected-error@-1 {{value pack expansion at parameter #0 expects 3 separate arguments}} + // expected-error@-1 {{initializer expects 3 separate arguments}} _ = Data(x: 42, tuple) - // expected-error@-1 {{value pack expansion at parameter #1 expects 3 separate arguments}} + // expected-error@-1 {{pack expansion requires that 'Int, String, Float' and '(Int, String, Float)' have the same shape}} _ = Data(x: 42, tuple, y: 1, 2, 3) - // expected-error@-1 {{value pack expansion at parameter #1 expects 3 separate arguments}} + // expected-error@-1 {{pack expansion requires that 'Int, String, Float' and '(Int, String, Float)' have the same shape}} _ = Data(x: 42, (42, "", 0), y: 1, 2, 3) - // expected-error@-1 {{value pack expansion at parameter #1 expects 3 separate arguments}} {{39-40=}} {{49-50=}} + // expected-error@-1 {{pack expansion requires that 'Int, String, Float' and '(Int, String, Int)' have the same shape}} struct Ambiguity { func test(_: repeat each T) -> Int { 42 } - // expected-note@-1 {{value pack expansion at parameter #0 expects 3 separate arguments}} + // expected-note@-1 {{'test' declared here}} func test(_: repeat each T) -> String { "" } - // expected-note@-1 {{value pack expansion at parameter #0 expects 3 separate arguments}} } - _ = Ambiguity().test(tuple) // expected-error {{no exact matches in call to instance method 'test'}} + _ = Ambiguity().test(tuple) // expected-error {{instance method 'test' expects 3 separate arguments}} } // rdar://107280056 - "Ambiguous without more context" with opaque return type + variadics @@ -621,44 +621,40 @@ do { // https://github.com/apple/swift/issues/66393 do { struct S { - var property: (repeat each T) -> Void { // expected-note 4 {{'property' declared here}} + var property: (repeat each T) -> Void { get {} } - func method(_: repeat each T) {} // expected-note 4 {{'method' declared here}} + func method(_: repeat each T) {} } S().method((5, true)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 2 separate arguments; remove extra parentheses to change tuple into separate arguments}} + // expected-error@-1 {{pack expansion requires that 'Int, Bool' and '(Int, Bool)' have the same shape}} S().method((5, true, 6)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 2 separate arguments; remove extra parentheses to change tuple into separate arguments}} + // expected-error@-1 {{pack expansion requires that 'Int, Bool' and '(Int, Bool, Int)' have the same shape}} S().property((5, true)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 2 separate arguments; remove extra parentheses to change tuple into separate arguments}} + // expected-error@-1 {{cannot pass value pack expansion to non-pack parameter of type 'repeat each T'}} S().property((5, true, 6)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 2 separate arguments; remove extra parentheses to change tuple into separate arguments}} + // expected-error@-1 {{cannot pass value pack expansion to non-pack parameter of type 'repeat each T'}} func foo(u: repeat each U) { S().property((3, 4, 5)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 1 separate arguments; remove extra parentheses to change tuple into separate arguments}} + // expected-error@-1 {{cannot pass value pack expansion to non-pack parameter of type 'repeat each T'}} // FIXME: The count of 'repeat each U' is not statically known, but error suggests that it is 1. S().method((3, 4, 5)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 1 separate arguments; remove extra parentheses to change tuple into separate arguments}} - // FIXME: Bad diagnostics - // expected-error@-3 {{pack expansion requires that 'each U' and '_' have the same shape}} - // expected-error@-4 {{pack expansion requires that 'each U' and '_.RawValue' have the same shape}} + // expected-error@-1 {{pack expansion requires that 'each U' and '(Int, Int, Int)' have the same shape}} // FIXME: The count of '(Int, Int), repeat each U' is not statically known, but error suggests that it is 2. S<(Int, Int), repeat each U>().method((3, 4)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 2 separate arguments; remove extra parentheses to change tuple into separate arguments}} - // FIXME: Duplicate diagnostics - // expected-error@-3 2 {{pack expansion requires that 'each U' and '' have the same shape}} + // expected-error@-1 {{pack expansion requires that '(Int, Int), repeat each U' and '(Int, Int)' have the same shape}} + // expected-error@-2 {{pack expansion requires that '' and 'each U' have the same shape}} // FIXME: The count of '(Int, Int), repeat each U' is not statically known, but error suggests that it is 2. S<(Int, Int), repeat each U>().property((3, 4)) - // expected-error@-1 {{value pack expansion at parameter #0 expects 2 separate arguments; remove extra parentheses to change tuple into separate arguments}} + // expected-error@-1 {{cannot pass value pack expansion to non-pack parameter of type 'repeat each T'}} } } diff --git a/test/Constraints/variadic_generic_constraints.swift b/test/Constraints/variadic_generic_constraints.swift index ce3d26786365c..ffb8e81dd48d7 100644 --- a/test/Constraints/variadic_generic_constraints.swift +++ b/test/Constraints/variadic_generic_constraints.swift @@ -73,5 +73,6 @@ func goodCallToZip(t: repeat each T, u: repeat each U) where (re func badCallToZip(t: repeat each T, u: repeat each U) { _ = zip(t: repeat each t, u: repeat each u) - // expected-error@-1 {{global function 'zip(t:u:)' requires the type packs 'repeat each T' and 'repeat each U' have the same shape}} + // expected-error@-1 {{global function 'zip(t:u:)' requires the type packs 'each T' and 'each U' have the same shape}} + // expected-error@-2 {{pack expansion requires that 'each U' and 'each T' have the same shape}} } diff --git a/test/Constraints/variadic_generic_init.swift b/test/Constraints/variadic_generic_init.swift new file mode 100644 index 0000000000000..209cab5ff1e34 --- /dev/null +++ b/test/Constraints/variadic_generic_init.swift @@ -0,0 +1,84 @@ +// RUN: %target-typecheck-verify-swift -disable-availability-checking + +// These test cases exercise variants of rdar://problem/112785081 +// and https://github.com/apple/swift/issues/68160. + +protocol P {} + +protocol Q { + associatedtype A: Q + + var a: A { get } +} + +struct S1: P { + init(_: repeat each T) {} +} + +func foo1a(_ t: repeat each T) -> some P { + return S1(repeat each t) +} + +func foo2a(_ t: repeat each T) -> S1 { + return S1(repeat each t) +} + +func foo3a(_ t: repeat each T) -> some P { + return S1(repeat (each t).a) +} + +func foo4a(_ t: repeat each T) -> S1 { + return S1(repeat (each t).a) +} + +func foo1b(_ t: repeat each T) -> some P { + return S1.init(repeat each t) +} + +func foo2b(_ t: repeat each T) -> S1 { + return S1.init(repeat each t) +} + +func foo3b(_ t: repeat each T) -> some P { + return S1.init(repeat (each t).a) +} + +func foo4b(_ t: repeat each T) -> S1 { + return S1.init(repeat (each t).a) +} + +struct S2: P { + init(arg: (repeat each T)) {} +} + +func bar1a(_ t: repeat each T) -> some P { + return S2(arg: (repeat each t)) +} + +func bar2a(_ t: repeat each T) -> S2 { + return S2(arg: (repeat each t)) +} + +func bar3a(_ t: repeat each T) -> some P { + return S2(arg: (repeat (each t).a)) +} + +func bar4a(_ t: repeat each T) -> S2 { + return S2(arg: (repeat (each t).a)) +} + +func bar1b(_ t: repeat each T) -> some P { + return S2.init(arg: (repeat each t)) +} + +func bar2b(_ t: repeat each T) -> S2 { + return S2.init(arg: (repeat each t)) +} + +func bar3b(_ t: repeat each T) -> some P { + return S2.init(arg: (repeat (each t).a)) +} + +func bar4b(_ t: repeat each T) -> S2 { + return S2.init(arg: (repeat (each t).a)) +} diff --git a/test/Constraints/variadic_generic_types.swift b/test/Constraints/variadic_generic_types.swift index 7a187622d5639..9fdf0a775caf3 100644 --- a/test/Constraints/variadic_generic_types.swift +++ b/test/Constraints/variadic_generic_types.swift @@ -56,6 +56,7 @@ do { return Test("a", 42, repeat each v) // Ok } } + // rdar://107479662 - variadic tuple of Sendable elements does not conform to Sendable do { struct Test : Sendable { @@ -65,3 +66,14 @@ do { struct TestProperty : Sendable { } } + +// https://github.com/apple/swift/issues/68160 +do { + struct G { + let f: (repeat Optional) -> U + + init(f: @escaping (repeat Optional) -> U) { + self.f = f + } + } +} \ No newline at end of file diff --git a/validation-test/compiler_crashers_2_fixed/rdar113463759.swift b/validation-test/compiler_crashers_2_fixed/rdar113463759.swift new file mode 100644 index 0000000000000..4612591e48175 --- /dev/null +++ b/validation-test/compiler_crashers_2_fixed/rdar113463759.swift @@ -0,0 +1,16 @@ +// RUN: %target-swift-frontend -emit-ir %s -disable-availability-checking + +protocol SomeObjectProtocol {} + +struct SomeObject: SomeObjectProtocol {} + +protocol ObjectProviding { + associatedtype Object: SomeObjectProtocol + var object: Object { get } +} + +struct ConformingObject: ObjectProviding { + var object: some SomeObjectProtocol { + SomeObject() + } +}