Skip to content

Commit fa41015

Browse files
committed
[ConstraintSystem] implement implicit pack materialization for abstract tuples instead of explicit '.element'
1 parent 2d238bc commit fa41015

11 files changed

+149
-40
lines changed

include/swift/AST/KnownIdentifiers.def

-1
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,6 @@ IDENTIFIER(size)
325325
IDENTIFIER(speed)
326326
IDENTIFIER(unchecked)
327327
IDENTIFIER(unsafe)
328-
IDENTIFIER(element)
329328

330329
// The singleton instance of TupleTypeDecl in the Builtin module
331330
IDENTIFIER(TheTupleType)

include/swift/Sema/Constraint.h

+4
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,9 @@ enum class ConstraintKind : char {
234234
ExplicitGenericArguments,
235235
/// Both (first and second) pack types should have the same reduced shape.
236236
SameShape,
237+
/// The first type is a tuple containing a single unlabeled element that is a
238+
/// pack expansion. The second type is that pack expansion.
239+
MaterializePackExpansion,
237240
};
238241

239242
/// Classification of the different kinds of constraints.
@@ -703,6 +706,7 @@ class Constraint final : public llvm::ilist_node<Constraint>,
703706
case ConstraintKind::UnresolvedMemberChainBase:
704707
case ConstraintKind::PackElementOf:
705708
case ConstraintKind::SameShape:
709+
case ConstraintKind::MaterializePackExpansion:
706710
return ConstraintClassification::Relational;
707711

708712
case ConstraintKind::ValueMember:

include/swift/Sema/ConstraintSystem.h

+12-1
Original file line numberDiff line numberDiff line change
@@ -4987,6 +4987,13 @@ class ConstraintSystem {
49874987
TypeMatchOptions flags,
49884988
ConstraintLocatorBuilder locator);
49894989

4990+
/// Remove the tuple wrapping of left-hand type if it contains only a single
4991+
/// unlabeled element that is a pack expansion.
4992+
SolutionKind
4993+
simplifyMaterializePackExpansionConstraint(Type type1, Type type2,
4994+
TypeMatchOptions flags,
4995+
ConstraintLocatorBuilder locator);
4996+
49904997
public: // FIXME: Public for use by static functions.
49914998
/// Simplify a conversion constraint with a fix applied to it.
49924999
SolutionKind simplifyFixConstraint(ConstraintFix *fix, Type type1, Type type2,
@@ -5546,7 +5553,8 @@ class OpenPackElementType {
55465553
}
55475554

55485555
cs.addConstraint(ConstraintKind::PackElementOf, elementType,
5549-
packType, cs.getConstraintLocator(elementEnv));
5556+
packType->getRValueType(),
5557+
cs.getConstraintLocator(elementEnv));
55505558
return elementType;
55515559
}
55525560
};
@@ -6229,6 +6237,9 @@ void dumpAnchor(ASTNode anchor, SourceManager *SM, raw_ostream &out);
62296237

62306238
bool isSingleUnlabeledPackExpansionTuple(Type type);
62316239

6240+
/// \returns null if \c type is not a single unlabeled pack expansion tuple.
6241+
Type getPatternTypeOfSingleUnlabeledPackExpansionTuple(Type type);
6242+
62326243
} // end namespace constraints
62336244

62346245
template<typename ...Args>

lib/Sema/CSApply.cpp

+2-3
Original file line numberDiff line numberDiff line change
@@ -3860,9 +3860,8 @@ namespace {
38603860
auto packRefType = cs.getType(packRefExpr);
38613861
if (auto *tuple = packRefType->getRValueType()->getAs<TupleType>();
38623862
tuple && tuple->isSingleUnlabeledPackExpansion()) {
3863-
auto *expansion =
3864-
tuple->getElementType(0)->castTo<PackExpansionType>();
3865-
auto patternType = expansion->getPatternType();
3863+
auto patternType =
3864+
getPatternTypeOfSingleUnlabeledPackExpansionTuple(tuple);
38663865
auto *materializedPackExpr = MaterializePackExpr::create(
38673866
cs.getASTContext(), packRefExpr, packRefExpr->getLoc(),
38683867
patternType, /*implicit*/ true);

lib/Sema/CSBindings.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -1483,6 +1483,7 @@ void PotentialBindings::infer(Constraint *constraint) {
14831483
case ConstraintKind::ExplicitGenericArguments:
14841484
case ConstraintKind::PackElementOf:
14851485
case ConstraintKind::SameShape:
1486+
case ConstraintKind::MaterializePackExpansion:
14861487
// Constraints from which we can't do anything.
14871488
break;
14881489

lib/Sema/CSDiagnostics.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -6229,8 +6229,10 @@ bool InvalidPackElement::diagnoseAsError() {
62296229
}
62306230

62316231
bool InvalidPackReference::diagnoseAsError() {
6232-
emitDiagnostic(diag::pack_reference_outside_expansion,
6233-
packType);
6232+
auto patternType =
6233+
getPatternTypeOfSingleUnlabeledPackExpansionTuple(packType);
6234+
auto diagnosisType = patternType ? patternType : packType;
6235+
emitDiagnostic(diag::pack_reference_outside_expansion, diagnosisType);
62346236
return true;
62356237
}
62366238

lib/Sema/CSGen.cpp

+23-17
Original file line numberDiff line numberDiff line change
@@ -1146,10 +1146,6 @@ struct VarRefCollector : public ASTWalker {
11461146

11471147
Type openPackElement(Type packType, ConstraintLocator *locator,
11481148
PackExpansionExpr *packElementEnvironment) {
1149-
// If 'each t' is written outside of a pack expansion expression, allow the
1150-
// type to bind to a hole. The invalid pack reference will be diagnosed when
1151-
// attempting to bind the type variable for the underlying pack reference to
1152-
// a pack type without TVO_CanBindToPack.
11531149
if (!packElementEnvironment) {
11541150
return CS.createTypeVariable(locator,
11551151
TVO_CanBindToHole | TVO_CanBindToNoEscape);
@@ -3127,8 +3123,14 @@ struct VarRefCollector : public ASTWalker {
31273123
llvm_unreachable("unsupported pack reference ASTNode");
31283124
}
31293125

3126+
auto *elementShape = CS.createTypeVariable(
3127+
CS.getConstraintLocator(pack, ConstraintLocator::PackShape),
3128+
TVO_CanBindToPack);
31303129
CS.addConstraint(
3131-
ConstraintKind::ShapeOf, expansionType->getCountType(), packType,
3130+
ConstraintKind::ShapeOf, elementShape, packType,
3131+
CS.getConstraintLocator(pack, ConstraintLocator::PackShape));
3132+
CS.addConstraint(
3133+
ConstraintKind::Equal, elementShape, expansionType->getCountType(),
31323134
CS.getConstraintLocator(expr, ConstraintLocator::PackShape));
31333135
}
31343136

@@ -3137,27 +3139,31 @@ struct VarRefCollector : public ASTWalker {
31373139

31383140
Type visitPackElementExpr(PackElementExpr *expr) {
31393141
auto packType = CS.getType(expr->getPackRefExpr());
3140-
3141-
if (isSingleUnlabeledPackExpansionTuple(packType)) {
3142-
packType =
3143-
addMemberRefConstraints(expr, expr->getPackRefExpr(),
3144-
DeclNameRef(CS.getASTContext().Id_element),
3145-
FunctionRefKind::Unapplied, {});
3146-
CS.setType(expr->getPackRefExpr(), packType);
3147-
}
3148-
31493142
auto *packEnvironment = CS.getPackEnvironment(expr);
3143+
auto elementType = openPackElement(
3144+
packType, CS.getConstraintLocator(expr), packEnvironment);
31503145
if (packEnvironment) {
31513146
auto expansionType =
31523147
CS.getType(packEnvironment)->castTo<PackExpansionType>();
31533148
CS.addConstraint(ConstraintKind::ShapeOf, expansionType->getCountType(),
3154-
packType,
3149+
elementType,
31553150
CS.getConstraintLocator(packEnvironment,
31563151
ConstraintLocator::PackShape));
3152+
auto *elementShape = CS.createTypeVariable(
3153+
CS.getConstraintLocator(expr, ConstraintLocator::PackShape),
3154+
TVO_CanBindToPack);
3155+
CS.addConstraint(
3156+
ConstraintKind::ShapeOf, elementShape, elementType,
3157+
CS.getConstraintLocator(expr, ConstraintLocator::PackShape));
3158+
CS.addConstraint(
3159+
ConstraintKind::Equal, elementShape, expansionType->getCountType(),
3160+
CS.getConstraintLocator(expr, ConstraintLocator::PackShape));
3161+
} else {
3162+
CS.recordFix(AllowInvalidPackReference::create(
3163+
CS, packType, CS.getConstraintLocator(expr->getPackRefExpr())));
31573164
}
31583165

3159-
return openPackElement(packType, CS.getConstraintLocator(expr),
3160-
packEnvironment);
3166+
return elementType;
31613167
}
31623168

31633169
Type visitMaterializePackExpr(MaterializePackExpr *expr) {

lib/Sema/CSSimplify.cpp

+71-11
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,20 @@ static bool isPackExpansionType(Type type) {
129129

130130
bool constraints::isSingleUnlabeledPackExpansionTuple(Type type) {
131131
auto *tuple = type->getRValueType()->getAs<TupleType>();
132-
// TODO: drop no name requirement
133132
return tuple && (tuple->getNumElements() == 1) &&
134133
isPackExpansionType(tuple->getElementType(0)) &&
135134
!tuple->getElement(0).hasName();
136135
}
137136

137+
Type constraints::getPatternTypeOfSingleUnlabeledPackExpansionTuple(Type type) {
138+
if (!isSingleUnlabeledPackExpansionTuple(type)) {
139+
return {};
140+
}
141+
auto tuple = type->getRValueType()->castTo<TupleType>();
142+
auto *expansion = tuple->getElementType(0)->castTo<PackExpansionType>();
143+
return expansion->getPatternType();
144+
}
145+
138146
static bool containsPackExpansionType(ArrayRef<AnyFunctionType::Param> params) {
139147
return llvm::any_of(params, [&](const auto &param) {
140148
return isPackExpansionType(param.getPlainType());
@@ -2283,6 +2291,7 @@ ConstraintSystem::matchTupleTypes(TupleType *tuple1, TupleType *tuple2,
22832291
case ConstraintKind::ShapeOf:
22842292
case ConstraintKind::ExplicitGenericArguments:
22852293
case ConstraintKind::SameShape:
2294+
case ConstraintKind::MaterializePackExpansion:
22862295
llvm_unreachable("Bad constraint kind in matchTupleTypes()");
22872296
}
22882297

@@ -2643,6 +2652,7 @@ static bool matchFunctionRepresentations(FunctionType::ExtInfo einfo1,
26432652
case ConstraintKind::ShapeOf:
26442653
case ConstraintKind::ExplicitGenericArguments:
26452654
case ConstraintKind::SameShape:
2655+
case ConstraintKind::MaterializePackExpansion:
26462656
return true;
26472657
}
26482658

@@ -3161,6 +3171,7 @@ ConstraintSystem::matchFunctionTypes(FunctionType *func1, FunctionType *func2,
31613171
case ConstraintKind::ShapeOf:
31623172
case ConstraintKind::ExplicitGenericArguments:
31633173
case ConstraintKind::SameShape:
3174+
case ConstraintKind::MaterializePackExpansion:
31643175
llvm_unreachable("Not a relational constraint");
31653176
}
31663177

@@ -6827,6 +6838,7 @@ ConstraintSystem::matchTypes(Type type1, Type type2, ConstraintKind kind,
68276838
case ConstraintKind::ShapeOf:
68286839
case ConstraintKind::ExplicitGenericArguments:
68296840
case ConstraintKind::SameShape:
6841+
case ConstraintKind::MaterializePackExpansion:
68306842
llvm_unreachable("Not a relational constraint");
68316843
}
68326844
}
@@ -9149,13 +9161,13 @@ ConstraintSystem::simplifyPackElementOfConstraint(Type first, Type second,
91499161
}
91509162

91519163
if (isSingleUnlabeledPackExpansionTuple(patternType)) {
9152-
auto *elementVar =
9153-
createTypeVariable(getConstraintLocator(locator), /*options=*/0);
9154-
addValueMemberConstraint(
9155-
patternType, DeclNameRef(getASTContext().Id_element), elementVar, DC,
9156-
FunctionRefKind::Unapplied, {},
9157-
getConstraintLocator(locator, {ConstraintLocator::Member}));
9158-
patternType = elementVar;
9164+
auto *packVar =
9165+
createTypeVariable(getConstraintLocator(locator), TVO_CanBindToPack);
9166+
addConstraint(ConstraintKind::MaterializePackExpansion, patternType,
9167+
packVar,
9168+
getConstraintLocator(locator, {ConstraintLocator::Member}));
9169+
addConstraint(ConstraintKind::PackElementOf, elementType, packVar, locator);
9170+
return SolutionKind::Solved;
91599171
}
91609172

91619173
// Let's try to resolve element type based on the pattern type.
@@ -9175,11 +9187,19 @@ ConstraintSystem::simplifyPackElementOfConstraint(Type first, Type second,
91759187
if (!shapeClass->is<PackArchetypeType>()) {
91769188
if (recordFix(AllowInvalidPackElement::create(*this, patternType, loc)))
91779189
return SolutionKind::Error;
9190+
} else {
9191+
auto envShape = PackExpansionEnvironments.find(loc);
9192+
if (envShape == PackExpansionEnvironments.end()) {
9193+
return SolutionKind::Error;
9194+
}
9195+
auto *fix = SkipSameShapeRequirement::create(
9196+
*this, envShape->second.second, shapeClass,
9197+
getConstraintLocator(loc, ConstraintLocator::PackShape));
9198+
if (recordFix(fix)) {
9199+
return SolutionKind::Error;
9200+
}
91789201
}
91799202

9180-
// Only other posibility is that there is a shape mismatch between
9181-
// elements of the pack expansion pattern which is detected separately.
9182-
91839203
recordAnyTypeVarAsPotentialHole(elementType);
91849204
return SolutionKind::Solved;
91859205
}
@@ -13552,6 +13572,37 @@ ConstraintSystem::SolutionKind ConstraintSystem::simplifySameShapeConstraint(
1355213572
return SolutionKind::Error;
1355313573
}
1355413574

13575+
ConstraintSystem::SolutionKind
13576+
ConstraintSystem::simplifyMaterializePackExpansionConstraint(
13577+
Type type1, Type type2, TypeMatchOptions flags,
13578+
ConstraintLocatorBuilder locator) {
13579+
auto formUnsolved = [&]() {
13580+
// If we're supposed to generate constraints, do so.
13581+
if (flags.contains(TMF_GenerateConstraints)) {
13582+
auto *explictGenericArgs =
13583+
Constraint::create(*this, ConstraintKind::MaterializePackExpansion,
13584+
type1, type2, getConstraintLocator(locator));
13585+
13586+
addUnsolvedConstraint(explictGenericArgs);
13587+
return SolutionKind::Solved;
13588+
}
13589+
13590+
return SolutionKind::Unsolved;
13591+
};
13592+
13593+
type1 = simplifyType(type1);
13594+
if (type1->hasTypeVariable()) {
13595+
return formUnsolved();
13596+
}
13597+
if (auto patternType =
13598+
getPatternTypeOfSingleUnlabeledPackExpansionTuple(type1)) {
13599+
addConstraint(ConstraintKind::Equal, patternType, type2, locator);
13600+
return SolutionKind::Solved;
13601+
}
13602+
13603+
return SolutionKind::Error;
13604+
}
13605+
1355513606
ConstraintSystem::SolutionKind
1355613607
ConstraintSystem::simplifyExplicitGenericArgumentsConstraint(
1355713608
Type type1, Type type2, TypeMatchOptions flags,
@@ -15179,6 +15230,10 @@ ConstraintSystem::addConstraintImpl(ConstraintKind kind, Type first,
1517915230
return simplifyExplicitGenericArgumentsConstraint(
1518015231
first, second, subflags, locator);
1518115232

15233+
case ConstraintKind::MaterializePackExpansion:
15234+
return simplifyMaterializePackExpansionConstraint(first, second, subflags,
15235+
locator);
15236+
1518215237
case ConstraintKind::ValueMember:
1518315238
case ConstraintKind::UnresolvedValueMember:
1518415239
case ConstraintKind::ValueWitness:
@@ -15758,6 +15813,11 @@ ConstraintSystem::simplifyConstraint(const Constraint &constraint) {
1575815813
return simplifyExplicitGenericArgumentsConstraint(
1575915814
constraint.getFirstType(), constraint.getSecondType(),
1576015815
/*flags*/ llvm::None, constraint.getLocator());
15816+
15817+
case ConstraintKind::MaterializePackExpansion:
15818+
return simplifyMaterializePackExpansionConstraint(
15819+
constraint.getFirstType(), constraint.getSecondType(),
15820+
/*flags*/ llvm::None, constraint.getLocator());
1576115821
}
1576215822

1576315823
llvm_unreachable("Unhandled ConstraintKind in switch.");

lib/Sema/Constraint.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second,
8383
case ConstraintKind::ShapeOf:
8484
case ConstraintKind::ExplicitGenericArguments:
8585
case ConstraintKind::SameShape:
86+
case ConstraintKind::MaterializePackExpansion:
8687
assert(!First.isNull());
8788
assert(!Second.isNull());
8889
break;
@@ -173,6 +174,7 @@ Constraint::Constraint(ConstraintKind Kind, Type First, Type Second, Type Third,
173174
case ConstraintKind::ShapeOf:
174175
case ConstraintKind::ExplicitGenericArguments:
175176
case ConstraintKind::SameShape:
177+
case ConstraintKind::MaterializePackExpansion:
176178
llvm_unreachable("Wrong constructor");
177179

178180
case ConstraintKind::KeyPath:
@@ -322,6 +324,7 @@ Constraint *Constraint::clone(ConstraintSystem &cs) const {
322324
case ConstraintKind::ShapeOf:
323325
case ConstraintKind::ExplicitGenericArguments:
324326
case ConstraintKind::SameShape:
327+
case ConstraintKind::MaterializePackExpansion:
325328
return create(cs, getKind(), getFirstType(), getSecondType(), getLocator());
326329

327330
case ConstraintKind::ApplicableFunction:
@@ -579,6 +582,10 @@ void Constraint::print(llvm::raw_ostream &Out, SourceManager *sm,
579582
Out << " explicit generic argument binding ";
580583
break;
581584

585+
case ConstraintKind::MaterializePackExpansion:
586+
Out << " materialize pack expansion ";
587+
break;
588+
582589
case ConstraintKind::Disjunction:
583590
llvm_unreachable("disjunction handled above");
584591
case ConstraintKind::Conjunction:
@@ -748,6 +755,7 @@ gatherReferencedTypeVars(Constraint *constraint,
748755
case ConstraintKind::ShapeOf:
749756
case ConstraintKind::ExplicitGenericArguments:
750757
case ConstraintKind::SameShape:
758+
case ConstraintKind::MaterializePackExpansion:
751759
constraint->getFirstType()->getTypeVariables(typeVars);
752760
constraint->getSecondType()->getTypeVariables(typeVars);
753761
break;

lib/Sema/ConstraintSystem.cpp

+4-4
Original file line numberDiff line numberDiff line change
@@ -3614,9 +3614,8 @@ void ConstraintSystem::resolveOverload(ConstraintLocator *locator,
36143614
// In the future, _if_ the syntax allows for multiple expansions
36153615
// this code would have to be adjusted to project l-value from the
36163616
// base type just like TupleIndex does.
3617-
auto tuple = choice.getBaseType()->getRValueType()->castTo<TupleType>();
3618-
auto *expansion = tuple->getElementType(0)->castTo<PackExpansionType>();
3619-
adjustedRefType = expansion->getPatternType();
3617+
adjustedRefType =
3618+
getPatternTypeOfSingleUnlabeledPackExpansionTuple(choice.getBaseType());
36203619
refType = adjustedRefType;
36213620
break;
36223621
}
@@ -3873,7 +3872,8 @@ struct TypeSimplifier {
38733872
if (typeVar->getImpl().isPackExpansion() &&
38743873
!resolvedType->isEqual(typeVar) &&
38753874
!resolvedType->is<PackExpansionType>() &&
3876-
!resolvedType->is<PackType>()) {
3875+
!resolvedType->is<PackType>() &&
3876+
!resolvedType->is<PackArchetypeType>()) {
38773877
return resolvedType;
38783878
}
38793879
}

0 commit comments

Comments
 (0)