Skip to content

Sema: Fix openType() handling of parameter packs [5.10] #70797

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions lib/AST/ParameterPack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -453,8 +453,11 @@ PackType::getExpandedGenericArgs(ArrayRef<GenericTypeParamType *> params,
}

PackType *PackType::getSingletonPackExpansion(Type param) {
assert(param->isParameterPack() || param->is<PackArchetypeType>());
return get(param->getASTContext(), {PackExpansionType::get(param, param)});
SmallVector<Type, 2> 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) {
Expand Down
4 changes: 3 additions & 1 deletion lib/Sema/CSDiagnostics.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
40 changes: 24 additions & 16 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PackExpansionType>()) {
return argPack->getElementType(0)->castTo<PackExpansionType>();
}

return PackExpansionType::get(argPack, argPack);
}();

auto firstArgIdx =
argTypes.empty() ? paramIdx : parameterBindings[paramIdx].front();
Expand Down Expand Up @@ -13624,33 +13631,34 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifySameShapeConstraint(
auto argLoc =
loc->castLastElementTo<LocatorPathElt::ApplyArgToParam>();

if (type1->getAs<PackArchetypeType>() &&
type2->getAs<PackArchetypeType>())
if (type1->is<PackArchetypeType>() &&
type2->is<PackArchetypeType>())
return recordShapeMismatchFix();

auto argPack = type1->getAs<PackType>();
auto paramPack = type2->getAs<PackType>();

if (!(argPack && paramPack))
return SolutionKind::Error;
auto numArgs = (shape1->is<PackType>()
? shape1->castTo<PackType>()->getNumElements()
: 1);
auto numParams = (shape2->is<PackType>()
? shape2->castTo<PackType>()->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<TupleType>() &&
paramPack->getNumElements() >= 1) {
if (numArgs == 1) {
if (type1->is<TupleType>() &&
numParams >= 1) {
return recordShapeFix(
DestructureTupleToMatchPackExpansionParameter::create(
*this, paramPack, loc),
/*impact=*/2 * paramPack->getNumElements());
*this,
(type2->is<PackType>()
? type2->castTo<PackType>()
: PackType::getSingletonPackExpansion(type2)), loc),
/*impact=*/2 * numParams);
}
}

auto numArgs = shape1->castTo<PackType>()->getNumElements();
auto numParams = shape2->castTo<PackType>()->getNumElements();

// Drops `ApplyArgToParam` and left with `ApplyArgument`.
path.pop_back();

Expand Down
40 changes: 9 additions & 31 deletions lib/Sema/ConstraintSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<PackType>()) {
assert(packTy->getNumElements() == 1);
auto *expansion = packTy->getElementType(0)->castTo<PackExpansionType>();
auto *typeVar = expansion->getPatternType()->castTo<TypeVariableType>();
assert(typeVar->getImpl().getGenericParameter() &&
typeVar->getImpl().canBindToPack());
return typeVar;
}

if (auto *expansion = dyn_cast<PackExpansionType>(type.getPointer()))
return openPackExpansionType(expansion, replacements, locator);
return type;
});
return result;
}

static void checkNestedTypeConstraints(ConstraintSystem &cs, Type type,
Expand Down Expand Up @@ -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<PackType>()) {
if (auto expansionTy = packTy->unwrapSingletonPackExpansion()) {
auto patternTy = expansionTy->getPatternType();
if (patternTy->isTypeParameter())
return openType(patternTy, replacements, locator);
}
}

if (auto *expansion = type->getAs<PackExpansionType>()) {
return openPackExpansionType(expansion, replacements, locator);
}
Expand Down Expand Up @@ -3927,6 +3897,14 @@ struct TypeSimplifier {
auto countType = expansion->getCountType().transform(
TypeSimplifier(CS, GetFixedTypeFn));

if (!countType->is<PackType>() &&
!countType->is<PackArchetypeType>()) {
SmallVector<Type, 2> 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.
Expand Down
25 changes: 25 additions & 0 deletions test/Constraints/issue-67906.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// RUN: %target-typecheck-verify-swift -disable-availability-checking

struct G<each T>: Sequence {
typealias Element = Int
typealias Iterator = [Int].Iterator

consuming func makeIterator() -> Iterator {
fatalError()
}
}

// expected-note@+1 {{in call to function 'foo'}}
func foo<each T>(_: repeat each T) -> G<repeat each T> {
.init()
}

// expected-error@+2 {{for-in loop requires '(repeat each T) -> G<repeat each T>' 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)
}
54 changes: 25 additions & 29 deletions test/Constraints/pack-expansion-expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@ func tupleExpansion<each T, each U>(
_ = 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)
}
Expand Down Expand Up @@ -349,37 +350,36 @@ func test_pack_expansions_with_closures() {
func test_pack_expansion_specialization(tuple: (Int, String, Float)) {
struct Data<each T> {
init(_: repeat each T) {} // expected-note 4 {{'init(_:)' declared here}}
init(vals: repeat each T) {} // expected-note {{'init(vals:)' declared here}}
init<each U>(x: Int, _: repeat each T, y: repeat each U) {} // expected-note 3 {{'init(x:_:y:)' declared here}}
init(vals: repeat each T) {}
init<each U>(x: Int, _: repeat each T, y: repeat each U) {}
}

_ = Data<Int>() // expected-error {{missing argument for parameter #1 in call}}
_ = Data<Int>(0) // Ok
_ = Data<Int, String>(42, "") // Ok
_ = Data<Int>(42, "") // expected-error {{extra argument in call}}
_ = Data<Int>(42, "") // expected-error {{pack expansion requires that 'Int' and 'Int, String' have the same shape}}
_ = Data<Int, String>((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<Int, String, Float>(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<Int, String, Float>((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<Int, String, Float>(tuple)
// expected-error@-1 {{value pack expansion at parameter #0 expects 3 separate arguments}}
// expected-error@-1 {{initializer expects 3 separate arguments}}
_ = Data<Int, String, Float>(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<Int, String, Float>(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<Int, String, Float>(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<each T> {
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<Int, String, Float>().test(tuple) // expected-error {{no exact matches in call to instance method 'test'}}
_ = Ambiguity<Int, String, Float>().test(tuple) // expected-error {{instance method 'test' expects 3 separate arguments}}
}

// rdar://107280056 - "Ambiguous without more context" with opaque return type + variadics
Expand Down Expand Up @@ -621,44 +621,40 @@ do {
// https://github.com/apple/swift/issues/66393
do {
struct S<each T> {
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<Int, Bool>().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<Int, Bool>().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<Int, Bool>().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<Int, Bool>().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<each U>(u: repeat each U) {
S<repeat each U>().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<repeat each U>().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'}}
}
}

Expand Down
3 changes: 2 additions & 1 deletion test/Constraints/variadic_generic_constraints.swift
Original file line number Diff line number Diff line change
Expand Up @@ -73,5 +73,6 @@ func goodCallToZip<each T, each U>(t: repeat each T, u: repeat each U) where (re

func badCallToZip<each T, each U>(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}}
}
84 changes: 84 additions & 0 deletions test/Constraints/variadic_generic_init.swift
Original file line number Diff line number Diff line change
@@ -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<each T: Q>: P {
init(_: repeat each T) {}
}

func foo1a<each T: Q>(_ t: repeat each T) -> some P {
return S1(repeat each t)
}

func foo2a<each T: Q>(_ t: repeat each T) -> S1<repeat each T> {
return S1(repeat each t)
}

func foo3a<each T: Q>(_ t: repeat each T) -> some P {
return S1(repeat (each t).a)
}

func foo4a<each T: Q>(_ t: repeat each T) -> S1<repeat (each T).A> {
return S1(repeat (each t).a)
}

func foo1b<each T: Q>(_ t: repeat each T) -> some P {
return S1.init(repeat each t)
}

func foo2b<each T: Q>(_ t: repeat each T) -> S1<repeat each T> {
return S1.init(repeat each t)
}

func foo3b<each T: Q>(_ t: repeat each T) -> some P {
return S1.init(repeat (each t).a)
}

func foo4b<each T: Q>(_ t: repeat each T) -> S1<repeat (each T).A> {
return S1.init(repeat (each t).a)
}

struct S2<each T: Q>: P {
init(arg: (repeat each T)) {}
}

func bar1a<each T: Q>(_ t: repeat each T) -> some P {
return S2(arg: (repeat each t))
}

func bar2a<each T: Q>(_ t: repeat each T) -> S2<repeat each T> {
return S2(arg: (repeat each t))
}

func bar3a<each T: Q>(_ t: repeat each T) -> some P {
return S2(arg: (repeat (each t).a))
}

func bar4a<each T: Q>(_ t: repeat each T) -> S2<repeat (each T).A> {
return S2(arg: (repeat (each t).a))
}

func bar1b<each T: Q>(_ t: repeat each T) -> some P {
return S2.init(arg: (repeat each t))
}

func bar2b<each T: Q>(_ t: repeat each T) -> S2<repeat each T> {
return S2.init(arg: (repeat each t))
}

func bar3b<each T: Q>(_ t: repeat each T) -> some P {
return S2.init(arg: (repeat (each t).a))
}

func bar4b<each T: Q>(_ t: repeat each T) -> S2<repeat (each T).A> {
return S2.init(arg: (repeat (each t).a))
}
Loading