Skip to content

Commit 44b5d64

Browse files
authored
Merge pull request #29728 from DougGregor/sink-init-pattern-constraints
[Constraint solver] Sink down initialization pattern handling
2 parents 518509d + 97aaa8a commit 44b5d64

File tree

6 files changed

+189
-172
lines changed

6 files changed

+189
-172
lines changed

lib/Sema/CSApply.cpp

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "MiscDiagnostics.h"
2323
#include "SolutionResult.h"
2424
#include "TypeCheckProtocol.h"
25+
#include "TypeCheckType.h"
2526
#include "swift/AST/ASTVisitor.h"
2627
#include "swift/AST/ASTWalker.h"
2728
#include "swift/AST/ExistentialLayout.h"
@@ -7227,6 +7228,83 @@ bool ConstraintSystem::applySolutionFixes(const Solution &solution) {
72277228
return diagnosedAnyErrors;
72287229
}
72297230

7231+
/// Apply the given solution to the initialization target.
7232+
///
7233+
/// \returns the resulting initialiation expression.
7234+
static Optional<SolutionApplicationTarget> applySolutionToInitialization(
7235+
Solution &solution, SolutionApplicationTarget target,
7236+
Expr *initializer) {
7237+
auto wrappedVar = target.getInitializationWrappedVar();
7238+
Type initType;
7239+
if (wrappedVar) {
7240+
initType = solution.getType(initializer);
7241+
} else {
7242+
initType = solution.getType(target.getInitializationPattern());
7243+
}
7244+
7245+
{
7246+
// Figure out what type the constraints decided on.
7247+
auto ty = solution.simplifyType(initType);
7248+
initType = ty->getRValueType()->reconstituteSugar(/*recursive =*/false);
7249+
}
7250+
7251+
// Convert the initializer to the type of the pattern.
7252+
auto &cs = solution.getConstraintSystem();
7253+
auto locator =
7254+
cs.getConstraintLocator(initializer, LocatorPathElt::ContextualType());
7255+
initializer = solution.coerceToType(initializer, initType, locator);
7256+
if (!initializer)
7257+
return None;
7258+
7259+
SolutionApplicationTarget resultTarget = target;
7260+
resultTarget.setExpr(initializer);
7261+
7262+
// Record the property wrapper type and note that the initializer has
7263+
// been subsumed by the backing property.
7264+
if (wrappedVar) {
7265+
ASTContext &ctx = cs.getASTContext();
7266+
wrappedVar->getParentPatternBinding()->setInitializerSubsumed(0);
7267+
ctx.setSideCachedPropertyWrapperBackingPropertyType(
7268+
wrappedVar, initType->mapTypeOutOfContext());
7269+
7270+
// Record the semantic initializer on the outermost property wrapper.
7271+
wrappedVar->getAttachedPropertyWrappers().front()
7272+
->setSemanticInit(initializer);
7273+
}
7274+
7275+
// Coerce the pattern to the type of the initializer.
7276+
TypeResolutionOptions options =
7277+
isa<EditorPlaceholderExpr>(initializer->getSemanticsProvidingExpr())
7278+
? TypeResolverContext::EditorPlaceholderExpr
7279+
: TypeResolverContext::InExpression;
7280+
options |= TypeResolutionFlags::OverrideType;
7281+
7282+
// Determine the type of the pattern.
7283+
Type finalPatternType = initializer->getType();
7284+
if (wrappedVar) {
7285+
if (!finalPatternType->hasError() && !finalPatternType->is<TypeVariableType>())
7286+
finalPatternType = computeWrappedValueType(wrappedVar, finalPatternType);
7287+
}
7288+
7289+
if (finalPatternType->hasDependentMember())
7290+
return None;
7291+
7292+
finalPatternType = finalPatternType->reconstituteSugar(/*recursive =*/false);
7293+
7294+
// Apply the solution to the pattern as well.
7295+
auto contextualPattern =
7296+
ContextualPattern::forRawPattern(target.getInitializationPattern(),
7297+
target.getDeclContext());
7298+
if (auto coercedPattern = TypeChecker::coercePatternToType(
7299+
contextualPattern, finalPatternType, options)) {
7300+
resultTarget.setPattern(coercedPattern);
7301+
} else {
7302+
return None;
7303+
}
7304+
7305+
return resultTarget;
7306+
}
7307+
72307308
/// Apply a given solution to the expression, producing a fully
72317309
/// type-checked expression.
72327310
Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
@@ -7265,7 +7343,17 @@ Optional<SolutionApplicationTarget> ConstraintSystem::applySolution(
72657343
if (!rewrittenExpr)
72667344
return None;
72677345

7268-
result.setExpr(rewrittenExpr);
7346+
/// Handle application for initializations.
7347+
if (target.getExprContextualTypePurpose() == CTP_Initialization) {
7348+
auto initResultTarget = applySolutionToInitialization(
7349+
solution, target, rewrittenExpr);
7350+
if (!initResultTarget)
7351+
return None;
7352+
7353+
result = *initResultTarget;
7354+
} else {
7355+
result.setExpr(rewrittenExpr);
7356+
}
72697357
} else {
72707358
auto fn = *target.getAsFunction();
72717359

lib/Sema/CSGen.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3831,6 +3831,68 @@ static Expr *generateConstraintsFor(ConstraintSystem &cs, Expr *expr,
38313831
return result;
38323832
}
38333833

3834+
/// Generate constraints to produce the wrapped value type given the property
3835+
/// that has an attached property wrapper.
3836+
///
3837+
/// \param initializerType The type of the adjusted initializer, which
3838+
/// initializes the underlying storage variable.
3839+
/// \param wrappedVar The property that has a property wrapper.
3840+
/// \returns the type of the property.
3841+
static Type generateWrappedPropertyTypeConstraints(
3842+
ConstraintSystem &cs, Type initializerType,
3843+
VarDecl *wrappedVar, ConstraintLocator *locator) {
3844+
Type valueType = LValueType::get(initializerType);
3845+
auto dc = wrappedVar->getInnermostDeclContext();
3846+
3847+
for (unsigned i : indices(wrappedVar->getAttachedPropertyWrappers())) {
3848+
auto wrapperInfo = wrappedVar->getAttachedPropertyWrapperTypeInfo(i);
3849+
if (!wrapperInfo)
3850+
break;
3851+
3852+
locator = cs.getConstraintLocator(locator, ConstraintLocator::Member);
3853+
Type memberType = cs.createTypeVariable(locator, TVO_CanBindToLValue);
3854+
cs.addValueMemberConstraint(
3855+
valueType, wrapperInfo.valueVar->createNameRef(),
3856+
memberType, dc, FunctionRefKind::Unapplied, { }, locator);
3857+
valueType = memberType;
3858+
}
3859+
3860+
// Set up an equality constraint to drop the lvalue-ness of the value
3861+
// type we produced.
3862+
Type propertyType = cs.createTypeVariable(locator, 0);
3863+
cs.addConstraint(ConstraintKind::Equal, propertyType, valueType, locator);
3864+
return propertyType;
3865+
}
3866+
3867+
/// Generate additional constraints for the pattern of an initialization.
3868+
static bool generateInitPatternConstraints(
3869+
ConstraintSystem &cs, SolutionApplicationTarget target, Expr *initializer) {
3870+
auto pattern = target.getInitializationPattern();
3871+
auto locator =
3872+
cs.getConstraintLocator(initializer, LocatorPathElt::ContextualType());
3873+
Type patternType = cs.generateConstraints(pattern, locator);
3874+
if (!patternType)
3875+
return true;
3876+
3877+
// Record the type of this pattern.
3878+
cs.setType(pattern, patternType);
3879+
3880+
if (auto wrappedVar = target.getInitializationWrappedVar()) {
3881+
// Add an equal constraint between the pattern type and the
3882+
// property wrapper's "value" type.
3883+
Type propertyType = generateWrappedPropertyTypeConstraints(
3884+
cs, cs.getType(target.getAsExpr()), wrappedVar, locator);
3885+
cs.addConstraint(ConstraintKind::Equal, patternType,
3886+
propertyType, locator, /*isFavored*/ true);
3887+
} else if (!patternType->is<OpaqueTypeArchetypeType>()) {
3888+
// Add a conversion constraint between the types.
3889+
cs.addConstraint(ConstraintKind::Conversion, cs.getType(target.getAsExpr()),
3890+
patternType, locator, /*isFavored*/true);
3891+
}
3892+
3893+
return false;
3894+
}
3895+
38343896
bool ConstraintSystem::generateConstraints(
38353897
SolutionApplicationTarget &target,
38363898
FreeTypeVariableBinding allowFreeTypeVariables) {
@@ -3873,6 +3935,12 @@ bool ConstraintSystem::generateConstraints(
38733935
isOpaqueReturnType);
38743936
}
38753937

3938+
// For an initialization target, generate constraints for the pattern.
3939+
if (target.getExprContextualTypePurpose() == CTP_Initialization &&
3940+
generateInitPatternConstraints(*this, target, expr)) {
3941+
return true;
3942+
}
3943+
38763944
return false;
38773945
}
38783946

lib/Sema/ConstraintSystem.h

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,12 @@ class SolutionApplicationTarget {
13141314
expression.expression = expr;
13151315
}
13161316

1317+
void setPattern(Pattern *pattern) {
1318+
assert(kind == Kind::expression);
1319+
assert(expression.contextualPurpose == CTP_Initialization);
1320+
expression.pattern = pattern;
1321+
}
1322+
13171323
Optional<AnyFunctionRef> getAsFunction() const {
13181324
switch (kind) {
13191325
case Kind::expression:
@@ -1481,6 +1487,7 @@ class ConstraintSystem {
14811487
llvm::DenseMap<const Expr *, TypeBase *> ExprTypes;
14821488
llvm::DenseMap<const TypeLoc *, TypeBase *> TypeLocTypes;
14831489
llvm::DenseMap<const VarDecl *, TypeBase *> VarTypes;
1490+
llvm::DenseMap<const Pattern *, TypeBase *> PatternTypes;
14841491
llvm::DenseMap<std::pair<const KeyPathExpr *, unsigned>, TypeBase *>
14851492
KeyPathComponentTypes;
14861493

@@ -2235,9 +2242,11 @@ class ConstraintSystem {
22352242
ExprTypes[expr] = type.getPointer();
22362243
} else if (auto typeLoc = node.dyn_cast<const TypeLoc *>()) {
22372244
TypeLocTypes[typeLoc] = type.getPointer();
2238-
} else {
2239-
auto var = node.get<const VarDecl *>();
2245+
} else if (auto var = node.dyn_cast<const VarDecl *>()) {
22402246
VarTypes[var] = type.getPointer();
2247+
} else {
2248+
auto pattern = node.get<const Pattern *>();
2249+
PatternTypes[pattern] = type.getPointer();
22412250
}
22422251

22432252
// Record the fact that we ascribed a type to this node.
@@ -2258,9 +2267,11 @@ class ConstraintSystem {
22582267
ExprTypes.erase(expr);
22592268
} else if (auto typeLoc = node.dyn_cast<const TypeLoc *>()) {
22602269
TypeLocTypes.erase(typeLoc);
2261-
} else {
2262-
auto var = node.get<const VarDecl *>();
2270+
} else if (auto var = node.dyn_cast<const VarDecl *>()) {
22632271
VarTypes.erase(var);
2272+
} else {
2273+
auto pattern = node.get<const Pattern *>();
2274+
PatternTypes.erase(pattern);
22642275
}
22652276
}
22662277

@@ -2287,9 +2298,11 @@ class ConstraintSystem {
22872298
return ExprTypes.find(expr) != ExprTypes.end();
22882299
} else if (auto typeLoc = node.dyn_cast<const TypeLoc *>()) {
22892300
return TypeLocTypes.find(typeLoc) != TypeLocTypes.end();
2290-
} else {
2291-
auto var = node.get<const VarDecl *>();
2301+
} else if (auto var = node.dyn_cast<const VarDecl *>()) {
22922302
return VarTypes.find(var) != VarTypes.end();
2303+
} else {
2304+
auto pattern = node.get<const Pattern *>();
2305+
return PatternTypes.find(pattern) != PatternTypes.end();
22932306
}
22942307
}
22952308

0 commit comments

Comments
 (0)