Skip to content

Commit caf2f62

Browse files
authored
Merge pull request #29717 from DougGregor/init-via-solution-target
[Constraint system] Sink initialization logic into SolutionApplicationTarget
2 parents d186228 + d70c055 commit caf2f62

File tree

5 files changed

+146
-105
lines changed

5 files changed

+146
-105
lines changed

lib/Sema/CSGen.cpp

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

3834+
bool ConstraintSystem::generateConstraints(
3835+
SolutionApplicationTarget &target,
3836+
FreeTypeVariableBinding allowFreeTypeVariables) {
3837+
if (Expr *expr = target.getAsExpr()) {
3838+
// Try to shrink the system by reducing disjunction domains. This
3839+
// goes through every sub-expression and generate its own sub-system, to
3840+
// try to reduce the domains of those subexpressions.
3841+
shrink(expr);
3842+
target.setExpr(expr);
3843+
3844+
// Generate constraints for the main system.
3845+
expr = generateConstraints(expr, target.getDeclContext());
3846+
if (!expr)
3847+
return true;
3848+
target.setExpr(expr);
3849+
3850+
// If there is a type that we're expected to convert to, add the conversion
3851+
// constraint.
3852+
if (Type convertType = target.getExprConversionType()) {
3853+
// Determine whether we know more about the contextual type.
3854+
ContextualTypePurpose ctp = target.getExprContextualTypePurpose();
3855+
bool isOpaqueReturnType = target.infersOpaqueReturnType();
3856+
3857+
// Substitute type variables in for unresolved types.
3858+
if (allowFreeTypeVariables == FreeTypeVariableBinding::UnresolvedType) {
3859+
bool isForSingleExprFunction = (ctp == CTP_ReturnSingleExpr);
3860+
auto *convertTypeLocator = getConstraintLocator(
3861+
expr, LocatorPathElt::ContextualType(isForSingleExprFunction));
3862+
3863+
convertType = convertType.transform([&](Type type) -> Type {
3864+
if (type->is<UnresolvedType>()) {
3865+
return createTypeVariable(
3866+
convertTypeLocator, TVO_CanBindToNoEscape);
3867+
}
3868+
return type;
3869+
});
3870+
}
3871+
3872+
addContextualConversionConstraint(expr, convertType, ctp,
3873+
isOpaqueReturnType);
3874+
}
3875+
3876+
return false;
3877+
}
3878+
3879+
llvm_unreachable("BOOM");
3880+
}
3881+
38343882
Expr *ConstraintSystem::generateConstraints(ClosureExpr *closure) {
38353883
assert(closure->hasSingleExpressionBody());
38363884
return generateConstraintsFor(*this, closure->getSingleExpressionBody(),

lib/Sema/CSSolver.cpp

Lines changed: 5 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1239,46 +1239,14 @@ ConstraintSystem::solveImpl(SolutionApplicationTarget &target,
12391239
assert(!solverState && "cannot be used directly");
12401240

12411241
// Set up the expression type checker timer.
1242-
Expr *expr = target.getAsExpr();
1243-
Timer.emplace(expr, *this);
1244-
1245-
// Try to shrink the system by reducing disjunction domains. This
1246-
// goes through every sub-expression and generate its own sub-system, to
1247-
// try to reduce the domains of those subexpressions.
1248-
shrink(expr);
1249-
1250-
// Generate constraints for the main system.
1251-
if (auto generatedExpr = generateConstraints(expr, DC))
1252-
expr = generatedExpr;
1253-
else {
1254-
return SolutionResult::forError();
1255-
}
1242+
if (Expr *expr = target.getAsExpr())
1243+
Timer.emplace(expr, *this);
12561244

1257-
// If there is a type that we're expected to convert to, add the conversion
1258-
// constraint.
1259-
if (Type convertType = target.getExprConversionType()) {
1260-
// Determine whether we know more about the contextual type.
1261-
ContextualTypePurpose ctp = target.getExprContextualTypePurpose();
1262-
bool isOpaqueReturnType = target.infersOpaqueReturnType();
1263-
1264-
// Substitute type variables in for unresolved types.
1265-
if (allowFreeTypeVariables == FreeTypeVariableBinding::UnresolvedType) {
1266-
bool isForSingleExprFunction = (ctp == CTP_ReturnSingleExpr);
1267-
auto *convertTypeLocator = getConstraintLocator(
1268-
expr, LocatorPathElt::ContextualType(isForSingleExprFunction));
1269-
1270-
convertType = convertType.transform([&](Type type) -> Type {
1271-
if (type->is<UnresolvedType>())
1272-
return createTypeVariable(convertTypeLocator, TVO_CanBindToNoEscape);
1273-
return type;
1274-
});
1275-
}
1276-
1277-
addContextualConversionConstraint(expr, convertType, ctp,
1278-
isOpaqueReturnType);
1279-
}
1245+
if (generateConstraints(target, allowFreeTypeVariables))
1246+
return SolutionResult::forError();;
12801247

12811248
// Notify the listener that we've built the constraint system.
1249+
Expr *expr = target.getAsExpr();
12821250
if (listener && listener->builtConstraints(*this, expr)) {
12831251
return SolutionResult::forError();
12841252
}

lib/Sema/ConstraintSystem.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3994,9 +3994,62 @@ SolutionApplicationTarget::SolutionApplicationTarget(
39943994
expression.dc = dc;
39953995
expression.contextualPurpose = contextualPurpose;
39963996
expression.convertType = convertType;
3997+
expression.pattern = nullptr;
3998+
expression.wrappedVar = nullptr;
39973999
expression.isDiscarded = isDiscarded;
39984000
}
39994001

4002+
void SolutionApplicationTarget::maybeApplyPropertyWrapper() {
4003+
assert(kind == Kind::expression);
4004+
assert(expression.contextualPurpose == CTP_Initialization);
4005+
auto singleVar = expression.pattern->getSingleVar();
4006+
if (!singleVar)
4007+
return;
4008+
4009+
auto wrapperAttrs = singleVar->getAttachedPropertyWrappers();
4010+
if (wrapperAttrs.empty())
4011+
return;
4012+
4013+
// If the outermost property wrapper is directly initialized, form the
4014+
// call.
4015+
auto &ctx = singleVar->getASTContext();
4016+
auto outermostWrapperAttr = wrapperAttrs.front();
4017+
Expr *backingInitializer;
4018+
if (Expr *initializer = expression.expression) {
4019+
// Form init(wrappedValue:) call(s).
4020+
Expr *wrappedInitializer =
4021+
buildPropertyWrapperInitialValueCall(
4022+
singleVar, Type(), initializer, /*ignoreAttributeArgs=*/false);
4023+
if (!wrappedInitializer)
4024+
return;
4025+
4026+
backingInitializer = wrappedInitializer;
4027+
} else if (auto outermostArg = outermostWrapperAttr->getArg()) {
4028+
Type outermostWrapperType =
4029+
singleVar->getAttachedPropertyWrapperType(0);
4030+
if (!outermostWrapperType)
4031+
return;
4032+
4033+
auto typeExpr = TypeExpr::createImplicitHack(
4034+
outermostWrapperAttr->getTypeLoc().getLoc(),
4035+
outermostWrapperType, ctx);
4036+
backingInitializer = CallExpr::create(
4037+
ctx, typeExpr, outermostArg,
4038+
outermostWrapperAttr->getArgumentLabels(),
4039+
outermostWrapperAttr->getArgumentLabelLocs(),
4040+
/*hasTrailingClosure=*/false,
4041+
/*implicit=*/false);
4042+
} else {
4043+
llvm_unreachable("No initializer anywhere?");
4044+
}
4045+
wrapperAttrs[0]->setSemanticInit(backingInitializer);
4046+
4047+
// Note that we have applied to property wrapper, so we can adjust
4048+
// the initializer type later.
4049+
expression.wrappedVar = singleVar;
4050+
expression.expression = backingInitializer;
4051+
}
4052+
40004053
SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
40014054
Expr *initializer, DeclContext *dc, Type patternType, Pattern *pattern) {
40024055
// Determine the contextual type for the initialization.
@@ -4020,6 +4073,7 @@ SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
40204073
initializer, dc, CTP_Initialization, contextualType,
40214074
/*isDiscarded=*/false);
40224075
target.expression.pattern = pattern;
4076+
target.maybeApplyPropertyWrapper();
40234077
return target;
40244078
}
40254079

lib/Sema/ConstraintSystem.h

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -774,8 +774,8 @@ struct Score {
774774

775775
/// An AST node that can gain type information while solving.
776776
using TypedNode =
777-
llvm::PointerUnion3<const Expr *, const TypeLoc *,
778-
const VarDecl *>;
777+
llvm::PointerUnion4<const Expr *, const TypeLoc *,
778+
const VarDecl *, const Pattern *>;
779779

780780
/// Display a score.
781781
llvm::raw_ostream &operator<<(llvm::raw_ostream &out, const Score &score);
@@ -1161,7 +1161,11 @@ class SolutionApplicationTarget {
11611161

11621162
/// When initializing a pattern from the expression, this is the
11631163
/// pattern.
1164-
Pattern *pattern = nullptr;
1164+
Pattern *pattern;
1165+
1166+
/// The variable to which property wrappers have been applied, if
1167+
/// this is an initialization involving a property wrapper.
1168+
VarDecl *wrappedVar;
11651169

11661170
/// Whether the expression result will be discarded at the end.
11671171
bool isDiscarded;
@@ -1173,6 +1177,11 @@ class SolutionApplicationTarget {
11731177
} function;
11741178
};
11751179

1180+
// If the pattern contains a single variable that has an attached
1181+
// property wrapper, set up the initializer expression to initialize
1182+
// the backing storage.
1183+
void maybeApplyPropertyWrapper();
1184+
11761185
public:
11771186
SolutionApplicationTarget(Expr *expr, DeclContext *dc,
11781187
ContextualTypePurpose contextualPurpose,
@@ -1281,6 +1290,14 @@ class SolutionApplicationTarget {
12811290
isa<OptionalSomePattern>(expression.pattern);
12821291
}
12831292

1293+
/// Retrieve the wrapped variable when initializing a pattern with a
1294+
/// property wrapper.
1295+
VarDecl *getInitializationWrappedVar() const {
1296+
assert(kind == Kind::expression);
1297+
assert(expression.contextualPurpose == CTP_Initialization);
1298+
return expression.wrappedVar;
1299+
}
1300+
12841301
/// Whether this context infers an opaque return type.
12851302
bool infersOpaqueReturnType() const;
12861303

@@ -3231,6 +3248,12 @@ class ConstraintSystem {
32313248
return allocateCopy(vec.begin(), vec.end());
32323249
}
32333250

3251+
/// Generate constraints for the given solution target.
3252+
///
3253+
/// \returns true if an error occurred, false otherwise.
3254+
bool generateConstraints(SolutionApplicationTarget &target,
3255+
FreeTypeVariableBinding allowFreeTypeVariables);
3256+
32343257
/// Generate constraints for the body of the given single-statement closure.
32353258
///
32363259
/// \returns a possibly-sanitized expression, or null if an error occurred.

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 13 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -2417,8 +2417,8 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
24172417
/// Type checking listener for pattern binding initializers.
24182418
class BindingListener : public ExprTypeCheckListener {
24192419
ASTContext &context;
2420-
Pattern *&pattern;
2421-
Expr *&initializer;
2420+
2421+
SolutionApplicationTarget target;
24222422

24232423
/// The locator we're using.
24242424
ConstraintLocator *Locator;
@@ -2430,11 +2430,9 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
24302430
VarDecl *wrappedVar = nullptr;
24312431

24322432
public:
2433-
explicit BindingListener(ASTContext &ctx, Pattern *&pattern,
2434-
Expr *&initializer)
2435-
: context(ctx), pattern(pattern), initializer(initializer),
2436-
Locator(nullptr) {
2437-
maybeApplyPropertyWrapper();
2433+
explicit BindingListener(ASTContext &ctx, SolutionApplicationTarget target)
2434+
: context(ctx), target(target), Locator(nullptr) {
2435+
wrappedVar = target.getInitializationWrappedVar();
24382436
}
24392437

24402438
/// Retrieve the type to which the pattern should be coerced.
@@ -2448,7 +2446,7 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
24482446
if (cs) {
24492447
Type valueType = LValueType::get(initType);
24502448
auto dc = wrappedVar->getInnermostDeclContext();
2451-
auto *loc = cs->getConstraintLocator(initializer);
2449+
auto *loc = cs->getConstraintLocator(target.getAsExpr());
24522450

24532451
for (unsigned i : indices(wrappedVar->getAttachedPropertyWrappers())) {
24542452
auto wrapperInfo = wrappedVar->getAttachedPropertyWrapperTypeInfo(i);
@@ -2481,7 +2479,8 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
24812479
Locator = cs.getConstraintLocator(expr, LocatorPathElt::ContextualType());
24822480

24832481
// Collect constraints from the pattern.
2484-
Type patternType = cs.generateConstraints(pattern, Locator);
2482+
Type patternType =
2483+
cs.generateConstraints(target.getInitializationPattern(), Locator);
24852484
if (!patternType)
24862485
return true;
24872486

@@ -2506,7 +2505,6 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
25062505
}
25072506

25082507
// The expression has been pre-checked; save it in case we fail later.
2509-
initializer = expr;
25102508
return false;
25112509
}
25122510

@@ -2536,70 +2534,20 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
25362534
->setSemanticInit(expr);
25372535
}
25382536

2539-
initializer = expr;
25402537
return expr;
25412538
}
2542-
2543-
private:
2544-
// If the pattern contains a single variable that has an attached
2545-
// property wrapper, set up the initializer expression to initialize
2546-
// the backing storage.
2547-
void maybeApplyPropertyWrapper() {
2548-
auto singleVar = pattern->getSingleVar();
2549-
if (!singleVar)
2550-
return;
2551-
2552-
auto wrapperAttrs = singleVar->getAttachedPropertyWrappers();
2553-
if (wrapperAttrs.empty())
2554-
return;
2555-
2556-
// If the outermost property wrapper is directly initialized, form the
2557-
// call.
2558-
auto &ctx = singleVar->getASTContext();
2559-
auto outermostWrapperAttr = wrapperAttrs.front();
2560-
if (initializer) {
2561-
// Form init(wrappedValue:) call(s).
2562-
Expr *wrappedInitializer =
2563-
buildPropertyWrapperInitialValueCall(
2564-
singleVar, Type(), initializer, /*ignoreAttributeArgs=*/false);
2565-
if (!wrappedInitializer)
2566-
return;
2567-
2568-
initializer = wrappedInitializer;
2569-
} else if (auto outermostArg = outermostWrapperAttr->getArg()) {
2570-
Type outermostWrapperType =
2571-
singleVar->getAttachedPropertyWrapperType(0);
2572-
if (!outermostWrapperType)
2573-
return;
2574-
2575-
auto typeExpr = TypeExpr::createImplicitHack(
2576-
outermostWrapperAttr->getTypeLoc().getLoc(),
2577-
outermostWrapperType, ctx);
2578-
initializer = CallExpr::create(
2579-
ctx, typeExpr, outermostArg,
2580-
outermostWrapperAttr->getArgumentLabels(),
2581-
outermostWrapperAttr->getArgumentLabelLocs(),
2582-
/*hasTrailingClosure=*/false,
2583-
/*implicit=*/false);
2584-
} else {
2585-
llvm_unreachable("No initializer anywhere?");
2586-
}
2587-
wrapperAttrs[0]->setSemanticInit(initializer);
2588-
2589-
// Note that we have applied to property wrapper, so we can adjust
2590-
// the initializer type later.
2591-
wrappedVar = singleVar;
2592-
}
25932539
};
25942540

25952541
auto &Context = DC->getASTContext();
2596-
BindingListener listener(Context, pattern, initializer);
2542+
auto target = SolutionApplicationTarget::forInitialization(
2543+
initializer, DC, patternType, pattern);
2544+
initializer = target.getAsExpr();
2545+
2546+
BindingListener listener(Context, target);
25972547
if (!initializer)
25982548
return true;
25992549

26002550
// Type-check the initializer.
2601-
auto target = SolutionApplicationTarget::forInitialization(
2602-
initializer, DC, patternType, pattern);
26032551
bool unresolvedTypeExprs = false;
26042552
auto resultTarget = typeCheckExpression(target, unresolvedTypeExprs,
26052553
None, &listener);

0 commit comments

Comments
 (0)