Skip to content

Commit 3f2f79a

Browse files
committed
[Constraint system] Fold pattern variable binding into constraint gen.
Rather than re-walk the pattern to create type bindings for the variables that show up in the pattern, assign types to each of the variables as part of constraint generation for the pattern. Only do this in contexts where we will need the types, e.g., function builders.
1 parent 644ed76 commit 3f2f79a

File tree

5 files changed

+140
-145
lines changed

5 files changed

+140
-145
lines changed

lib/Sema/BuilderTransform.cpp

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -259,17 +259,13 @@ class BuilderClosureVisitor
259259

260260
// Generate constraints for the initialization.
261261
auto target = SolutionApplicationTarget::forInitialization(
262-
patternBinding->getInit(index), dc, patternType, pattern);
262+
patternBinding->getInit(index), dc, patternType, pattern,
263+
/*bindPatternVarsOneWay=*/true);
263264
if (cs->generateConstraints(target, FreeTypeVariableBinding::Disallow))
264265
continue;
265266

266267
// Keep track of this binding entry.
267268
applied.patternBindingEntries.insert({{patternBinding, index}, target});
268-
269-
// Bind the variables that occur in the pattern to the corresponding
270-
// type entry for the pattern itself.
271-
cs->bindVariablesInPattern(
272-
pattern, cs->getConstraintLocator(target.getAsExpr()));
273269
}
274270
}
275271

lib/Sema/CSGen.cpp

Lines changed: 115 additions & 117 deletions
Original file line numberDiff line numberDiff line change
@@ -2197,7 +2197,9 @@ namespace {
21972197
/// type information with fresh type variables.
21982198
///
21992199
/// \param pattern The pattern.
2200-
Type getTypeForPattern(Pattern *pattern, ConstraintLocatorBuilder locator) {
2200+
Type getTypeForPattern(Pattern *pattern, ConstraintLocatorBuilder locator,
2201+
Type externalPatternType,
2202+
bool bindPatternVarsOneWay) {
22012203
// If there's no pattern, then we have an unknown subpattern. Create a
22022204
// type variable.
22032205
if (!pattern) {
@@ -2213,19 +2215,29 @@ namespace {
22132215
};
22142216

22152217
switch (pattern->getKind()) {
2216-
case PatternKind::Paren:
2218+
case PatternKind::Paren: {
22172219
// Parentheses don't affect the canonical type, but record them as
22182220
// type sugar.
2221+
if (externalPatternType &&
2222+
isa<ParenType>(externalPatternType.getPointer())) {
2223+
externalPatternType = cast<ParenType>(externalPatternType.getPointer())
2224+
->getUnderlyingType();
2225+
}
2226+
22192227
return setType(
22202228
ParenType::get(
22212229
CS.getASTContext(),
22222230
getTypeForPattern(
2223-
cast<ParenPattern>(pattern)->getSubPattern(), locator)));
2231+
cast<ParenPattern>(pattern)->getSubPattern(), locator,
2232+
externalPatternType,
2233+
bindPatternVarsOneWay)));
2234+
}
22242235
case PatternKind::Var:
22252236
// Var doesn't affect the type.
22262237
return setType(
22272238
getTypeForPattern(
2228-
cast<VarPattern>(pattern)->getSubPattern(), locator));
2239+
cast<VarPattern>(pattern)->getSubPattern(), locator,
2240+
externalPatternType, bindPatternVarsOneWay));
22292241
case PatternKind::Any: {
22302242
return setType(
22312243
CS.createTypeVariable(CS.getConstraintLocator(locator),
@@ -2238,16 +2250,47 @@ namespace {
22382250
Type varType = CS.createTypeVariable(
22392251
CS.getConstraintLocator(locator), TVO_CanBindToNoEscape);
22402252

2253+
// When we are supposed to bind pattern variables, create a fresh
2254+
// type variable and a one-way constraint to assign it to either the
2255+
// deduced type or the externally-imposed type.
2256+
Type oneWayVarType;
2257+
if (bindPatternVarsOneWay) {
2258+
oneWayVarType = CS.createTypeVariable(
2259+
CS.getConstraintLocator(locator), TVO_CanBindToNoEscape);
2260+
if (externalPatternType) {
2261+
CS.addConstraint(
2262+
ConstraintKind::OneWayEqual, oneWayVarType,
2263+
externalPatternType, locator);
2264+
} else {
2265+
CS.addConstraint(
2266+
ConstraintKind::OneWayEqual, oneWayVarType, varType, locator);
2267+
}
2268+
}
2269+
2270+
// If there is an externally-imposed type.
2271+
22412272
auto ROK = ReferenceOwnership::Strong;
22422273
if (auto *OA = var->getAttrs().getAttribute<ReferenceOwnershipAttr>())
22432274
ROK = OA->get();
22442275
switch (optionalityOf(ROK)) {
22452276
case ReferenceOwnershipOptionality::Required:
2246-
return setType(TypeChecker::getOptionalType(var->getLoc(), varType));
2277+
varType = TypeChecker::getOptionalType(var->getLoc(), varType);
2278+
if (oneWayVarType) {
2279+
oneWayVarType =
2280+
TypeChecker::getOptionalType(var->getLoc(), oneWayVarType);
2281+
}
2282+
break;
2283+
22472284
case ReferenceOwnershipOptionality::Allowed:
22482285
case ReferenceOwnershipOptionality::Disallowed:
2249-
return setType(varType);
2286+
break;
22502287
}
2288+
2289+
// If we have a type to ascribe to the variable, do so now.
2290+
if (oneWayVarType)
2291+
CS.setType(var, oneWayVarType);
2292+
2293+
return setType(varType);
22512294
}
22522295

22532296
case PatternKind::Typed: {
@@ -2262,47 +2305,93 @@ namespace {
22622305
// ascribed type.
22632306
Type subPatternType =
22642307
getTypeForPattern(
2265-
cast<TypedPattern>(pattern)->getSubPattern(), locator);
2308+
cast<TypedPattern>(pattern)->getSubPattern(), locator,
2309+
Type(), bindPatternVarsOneWay);
22662310
CS.addConstraint(
22672311
ConstraintKind::Conversion, subPatternType, openedType, locator);
22682312
return setType(openedType);
22692313
}
22702314

22712315
case PatternKind::Tuple: {
22722316
auto tuplePat = cast<TuplePattern>(pattern);
2317+
2318+
// If there's an externally-imposed type, decompose it into element
2319+
// types so long as we have the right number of such types.
2320+
SmallVector<AnyFunctionType::Param, 4> externalEltTypes;
2321+
if (externalPatternType) {
2322+
AnyFunctionType::decomposeInput(externalPatternType,
2323+
externalEltTypes);
2324+
2325+
// If we have the wrong number of elements, we may not be able to
2326+
// provide more specific types.
2327+
if (tuplePat->getNumElements() != externalEltTypes.size()) {
2328+
externalEltTypes.clear();
2329+
2330+
// Implicit tupling.
2331+
if (tuplePat->getNumElements() == 1) {
2332+
externalEltTypes.push_back(
2333+
AnyFunctionType::Param(externalPatternType));
2334+
}
2335+
}
2336+
}
2337+
22732338
SmallVector<TupleTypeElt, 4> tupleTypeElts;
22742339
tupleTypeElts.reserve(tuplePat->getNumElements());
22752340
for (unsigned i = 0, e = tuplePat->getNumElements(); i != e; ++i) {
22762341
auto &tupleElt = tuplePat->getElement(i);
2277-
Type eltTy = getTypeForPattern(tupleElt.getPattern(),
2278-
locator.withPathElement(
2279-
LocatorPathElt::TupleElement(i)));
2342+
Type externalEltType;
2343+
if (!externalEltTypes.empty())
2344+
externalEltType = externalEltTypes[i].getPlainType();
2345+
2346+
Type eltTy = getTypeForPattern(
2347+
tupleElt.getPattern(),
2348+
locator.withPathElement(LocatorPathElt::TupleElement(i)),
2349+
externalEltType,
2350+
bindPatternVarsOneWay);
22802351
tupleTypeElts.push_back(TupleTypeElt(eltTy, tupleElt.getLabel()));
22812352
}
2353+
22822354
return setType(TupleType::get(tupleTypeElts, CS.getASTContext()));
22832355
}
22842356

22852357
case PatternKind::OptionalSome: {
2358+
// Remove an optional from the object type.
2359+
if (externalPatternType) {
2360+
if (Type objType = externalPatternType->getOptionalObjectType()) {
2361+
externalPatternType = objType;
2362+
} else {
2363+
Type objVar = CS.createTypeVariable(
2364+
CS.getConstraintLocator(locator), TVO_CanBindToNoEscape);
2365+
CS.addConstraint(
2366+
ConstraintKind::Equal, OptionalType::get(objVar),
2367+
externalPatternType, locator);
2368+
externalPatternType = objVar;
2369+
}
2370+
}
2371+
22862372
// The subpattern must have optional type.
22872373
Type subPatternType = getTypeForPattern(
2288-
cast<OptionalSomePattern>(pattern)->getSubPattern(), locator);
2374+
cast<OptionalSomePattern>(pattern)->getSubPattern(), locator,
2375+
externalPatternType, bindPatternVarsOneWay);
22892376

22902377
return setType(OptionalType::get(subPatternType));
22912378
}
22922379

22932380
case PatternKind::Is: {
22942381
auto isPattern = cast<IsPattern>(pattern);
2382+
2383+
Type castType =
2384+
resolveTypeReferenceInExpression(isPattern->getCastTypeLoc());
2385+
castType = CS.openUnboundGenericType(castType, locator);
2386+
22952387
Type subPatternType =
2296-
getTypeForPattern(isPattern->getSubPattern(), locator);
2388+
getTypeForPattern(isPattern->getSubPattern(), locator, castType,
2389+
bindPatternVarsOneWay);
22972390

22982391
// Make sure we can cast from the subpattern type to the type we're
22992392
// checking; if it's impossible, fail.
2300-
if (Type castType =
2301-
resolveTypeReferenceInExpression(isPattern->getCastTypeLoc())) {
2302-
castType = CS.openUnboundGenericType(castType, locator);
2303-
CS.addConstraint(
2304-
ConstraintKind::CheckedCast, subPatternType, castType, locator);
2305-
}
2393+
CS.addConstraint(
2394+
ConstraintKind::CheckedCast, subPatternType, castType, locator);
23062395

23072396
return setType(subPatternType);
23082397
}
@@ -2358,8 +2447,9 @@ namespace {
23582447
// When there is a subpattern, the member will have function type,
23592448
// and we're matching the type of that subpattern to the parameter
23602449
// types.
2361-
Type subPatternType = getTypeForPattern(subPattern, locator);
2362-
SmallVector<AnyFunctionType::Param, 8> params;
2450+
Type subPatternType = getTypeForPattern(
2451+
subPattern, locator, Type(), bindPatternVarsOneWay);
2452+
SmallVector<AnyFunctionType::Param, 4> params;
23632453
AnyFunctionType::decomposeInput(subPatternType, params);
23642454

23652455
// Remove parameter labels; they aren't used when matching cases,
@@ -3970,7 +4060,8 @@ static bool generateInitPatternConstraints(
39704060
auto pattern = target.getInitializationPattern();
39714061
auto locator =
39724062
cs.getConstraintLocator(initializer, LocatorPathElt::ContextualType());
3973-
Type patternType = cs.generateConstraints(pattern, locator);
4063+
Type patternType = cs.generateConstraints(
4064+
pattern, locator, target.shouldBindPatternVarsOneWay());
39744065
assert(patternType && "All patterns have a type");
39754066

39764067
if (auto wrappedVar = target.getInitializationWrappedVar()) {
@@ -4069,9 +4160,10 @@ Expr *ConstraintSystem::generateConstraints(Expr *expr, DeclContext *dc) {
40694160
}
40704161

40714162
Type ConstraintSystem::generateConstraints(Pattern *pattern,
4072-
ConstraintLocatorBuilder locator) {
4163+
ConstraintLocatorBuilder locator,
4164+
bool bindPatternVarsOneWay) {
40734165
ConstraintGenerator cg(*this, nullptr);
4074-
return cg.getTypeForPattern(pattern, locator);
4166+
return cg.getTypeForPattern(pattern, locator, Type(), bindPatternVarsOneWay);
40754167
}
40764168

40774169
bool ConstraintSystem::canGenerateConstraints(StmtCondition condition) {
@@ -4129,100 +4221,6 @@ bool ConstraintSystem::generateConstraints(StmtCondition condition,
41294221
return false;
41304222
}
41314223

4132-
void ConstraintSystem::bindVariablesInPattern(
4133-
Pattern *pattern, Type patternType, ConstraintLocator *locator) {
4134-
switch (pattern->getKind()) {
4135-
case PatternKind::Paren: {
4136-
// Parentheses don't affect the type, but unwrap a paren type if we have
4137-
// one.
4138-
Type subPatternType;
4139-
if (auto parenType = dyn_cast<ParenType>(patternType.getPointer()))
4140-
subPatternType = parenType->getUnderlyingType();
4141-
else
4142-
subPatternType = patternType;
4143-
return bindVariablesInPattern(
4144-
cast<ParenPattern>(pattern)->getSubPattern(),
4145-
subPatternType, locator);
4146-
}
4147-
4148-
case PatternKind::Var:
4149-
// Var doesn't affect the type.
4150-
return bindVariablesInPattern(cast<VarPattern>(pattern)->getSubPattern(),
4151-
patternType, locator);
4152-
4153-
case PatternKind::Any:
4154-
// Nothing to bind.
4155-
return;
4156-
4157-
case PatternKind::Named: {
4158-
auto var = cast<NamedPattern>(pattern)->getDecl();
4159-
4160-
/// Create a fresh type variable to describe the type of the bound variable.
4161-
Type varType = createTypeVariable(locator, TVO_CanBindToNoEscape);
4162-
4163-
auto ROK = ReferenceOwnership::Strong;
4164-
if (auto *OA = var->getAttrs().getAttribute<ReferenceOwnershipAttr>())
4165-
ROK = OA->get();
4166-
switch (optionalityOf(ROK)) {
4167-
case ReferenceOwnershipOptionality::Required:
4168-
// FIXME: Can we assert this rather than just checking it.
4169-
if (auto optPatternType =
4170-
dyn_cast<OptionalType>(patternType.getPointer())) {
4171-
// Add a one-way constraint from the type variable to the wrapped
4172-
// type of the optional.
4173-
addConstraint(
4174-
ConstraintKind::OneWayEqual, varType, optPatternType->getBaseType(),
4175-
locator);
4176-
4177-
// Make the variable type optional.
4178-
varType = TypeChecker::getOptionalType(var->getLoc(), varType);
4179-
break;
4180-
}
4181-
4182-
// Fall through to treat this normally.
4183-
LLVM_FALLTHROUGH;
4184-
4185-
case ReferenceOwnershipOptionality::Allowed:
4186-
case ReferenceOwnershipOptionality::Disallowed:
4187-
// Add the one-way constraint from the variable type to the pattern
4188-
// type.
4189-
addConstraint(ConstraintKind::OneWayEqual, varType, patternType,
4190-
locator);
4191-
break;
4192-
}
4193-
4194-
// Bind the type of the variable.
4195-
setType(var, varType);
4196-
return;
4197-
}
4198-
4199-
case PatternKind::Typed: {
4200-
// Ignore the type itself; it's part of patternType now.
4201-
return bindVariablesInPattern(
4202-
cast<TypedPattern>(pattern)->getSubPattern(),
4203-
patternType, locator);
4204-
}
4205-
4206-
case PatternKind::Tuple: {
4207-
auto tuplePat = cast<TuplePattern>(pattern);
4208-
auto tupleType = patternType->castTo<TupleType>();
4209-
for (unsigned i = 0, e = tuplePat->getNumElements(); i != e; ++i) {
4210-
bindVariablesInPattern(tuplePat->getElement(i).getPattern(),
4211-
tupleType->getElementType(i), locator);
4212-
}
4213-
return;
4214-
}
4215-
4216-
// FIXME: Refutable patterns will generate additional constraints.
4217-
#define PATTERN(Id, Parent)
4218-
#define REFUTABLE_PATTERN(Id, Parent) case PatternKind::Id:
4219-
#include "swift/AST/PatternNodes.def"
4220-
llvm_unreachable("Refutable patterns are not supported here");
4221-
}
4222-
4223-
llvm_unreachable("Unhandled pattern kind");
4224-
}
4225-
42264224
void ConstraintSystem::optimizeConstraints(Expr *e) {
42274225
if (getASTContext().TypeCheckerOpts.DisableConstraintSolverPerformanceHacks)
42284226
return;

lib/Sema/ConstraintSystem.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4106,6 +4106,7 @@ SolutionApplicationTarget::SolutionApplicationTarget(
41064106
expression.pattern = nullptr;
41074107
expression.wrappedVar = nullptr;
41084108
expression.isDiscarded = isDiscarded;
4109+
expression.bindPatternVarsOneWay = false;
41094110
}
41104111

41114112
void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
@@ -4160,7 +4161,8 @@ void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
41604161
}
41614162

41624163
SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
4163-
Expr *initializer, DeclContext *dc, Type patternType, Pattern *pattern) {
4164+
Expr *initializer, DeclContext *dc, Type patternType, Pattern *pattern,
4165+
bool bindPatternVarsOneWay) {
41644166
// Determine the contextual type for the initialization.
41654167
TypeLoc contextualType;
41664168
if (!isa<OptionalSomePattern>(pattern) &&
@@ -4182,6 +4184,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
41824184
initializer, dc, CTP_Initialization, contextualType,
41834185
/*isDiscarded=*/false);
41844186
target.expression.pattern = pattern;
4187+
target.expression.bindPatternVarsOneWay = bindPatternVarsOneWay;
41854188
target.maybeApplyPropertyWrapper();
41864189
return target;
41874190
}

0 commit comments

Comments
 (0)