Skip to content
Open
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
3 changes: 1 addition & 2 deletions include/swift/AST/Types.h
Original file line number Diff line number Diff line change
Expand Up @@ -850,12 +850,11 @@ class alignas(1 << TypeAlignInBits) TypeBase
/// type variables referenced by this type.
void getTypeVariables(SmallPtrSetImpl<TypeVariableType *> &typeVariables);

private:
public:
/// If the receiver is a `DependentMemberType`, returns its root. Otherwise,
/// returns the receiver.
Type getDependentMemberRoot();

public:
/// Determine whether this type is a type parameter, which is either a
/// GenericTypeParamType or a DependentMemberType.
///
Expand Down
48 changes: 45 additions & 3 deletions lib/Sema/CSSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7099,6 +7099,20 @@ static bool isTupleWithUnresolvedPackExpansion(Type type) {
return false;
}

static bool isDependentMemberTypeWithBaseThatContainsUnresolvedPackExpansions(
ConstraintSystem &cs, Type type) {
if (!type->is<DependentMemberType>())
return false;

auto baseTy = cs.getFixedTypeRecursive(type->getDependentMemberRoot(),
/*wantRValue=*/true);
llvm::SmallPtrSet<TypeVariableType *, 2> typeVars;
baseTy->getTypeVariables(typeVars);
return llvm::any_of(typeVars, [](const TypeVariableType *typeVar) {
return typeVar->getImpl().isPackExpansion();
});
}

ConstraintSystem::TypeMatchResult
ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
TypeMatchOptions flags,
Expand Down Expand Up @@ -7135,7 +7149,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
//
// along any unsolved path. No other returns should produce
// SolutionKind::Unsolved or inspect TMF_GenerateConstraints.
auto formUnsolvedResult = [&] {
auto formUnsolvedResult = [&](bool useOriginalTypes = false) {
// If we're supposed to generate constraints (i.e., this is a
// newly-generated constraint), do so now.
if (flags.contains(TMF_GenerateConstraints)) {
Expand All @@ -7144,8 +7158,13 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
// this new constraint will be solved at a later point.
// Obviously, this must not happen at the top level, or the
// algorithm would not terminate.
addUnsolvedConstraint(Constraint::create(*this, kind, type1, type2,
getConstraintLocator(locator)));
if (useOriginalTypes) {
addUnsolvedConstraint(Constraint::create(
*this, kind, origType1, origType2, getConstraintLocator(locator)));
} else {
addUnsolvedConstraint(Constraint::create(
*this, kind, type1, type2, getConstraintLocator(locator)));
}
return getTypeMatchSuccess();
}

Expand Down Expand Up @@ -7396,6 +7415,29 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
}
}

// Dependent members cannot be simplified if base type contains unresolved
// pack expansion type variables because they don't give enough information
// to substitution logic to form a correct type. For example:
//
// ```
// protocol P { associatedtype V }
// struct S<each T> : P { typealias V = (repeat (each T)?) }
// ```
//
// If pack expansion is represented as `$T1` and its pattern is `$T2`, a
// reference to `V` would get a type `S<Pack{$T}>.V` and simplified version
// would be `Optional<Pack{$T1}>` instead of `Pack{repeat Optional<$T2>}`
// because `$T1` is treated as a substitution for `each T` until bound.
if (isDependentMemberTypeWithBaseThatContainsUnresolvedPackExpansions(
*this, origType1) ||
isDependentMemberTypeWithBaseThatContainsUnresolvedPackExpansions(
*this, origType2)) {
// It's important to preserve the original types here because any attempt
// at simplification or canonicalization wouldn't produce a correct type
// util pack expansion type variables are bound.
return formUnsolvedResult(/*useOriginalTypes=*/true);
}

llvm::SmallVector<RestrictionOrFix, 4> conversionsOrFixes;

// Decompose parallel structure.
Expand Down
20 changes: 19 additions & 1 deletion test/Constraints/pack-expansion-expressions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ func test_pack_expansion_specialization(tuple: (Int, String, Float)) {
}

// rdar://107280056 - "Ambiguous without more context" with opaque return type + variadics
protocol Q {
protocol Q<B> {
associatedtype B
}

Expand Down Expand Up @@ -815,3 +815,21 @@ func testPackToScalarShortFormConstructor() {
S(repeat each xs) // expected-error {{cannot pass value pack expansion to non-pack parameter of type 'Int'}}
}
}


func test_dependent_members() {
struct Variadic<each T>: Q {
typealias B = (repeat (each T)?)

init(_: repeat each T) {}
static func f(_: repeat each T) -> Self {}
}

func test_init<C1, C2>(_ c1: C1, _ c2: C2) -> some Q<(C1?, C2?)> {
return Variadic(c1, c2) // Ok
}

func test_static<C1, C2>(_ c1: C1, _ c2: C2) -> some Q<(C1?, C2?)> {
return Variadic.f(c1, c2) // Ok
}
}