mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Merge pull request #84729 from xedin/rdar-161207705
[CSSimplify] Avoid simplifying dependent members until pack expansion…
This commit is contained in:
@@ -849,12 +849,11 @@ public:
|
||||
/// 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.
|
||||
///
|
||||
|
||||
@@ -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,
|
||||
@@ -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)) {
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user