Skip to content

Commit 82b3420

Browse files
authored
Merge pull request swiftlang#29609 from DougGregor/constraint-solver-remove-yet-more-flags
[Constraint solver] Remove yet more of TypeCheckExprFlags
2 parents 9ce20c4 + 9278fb8 commit 82b3420

File tree

5 files changed

+124
-91
lines changed

5 files changed

+124
-91
lines changed

lib/Sema/ConstraintSystem.cpp

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3970,7 +3970,7 @@ ValueDecl *ConstraintSystem::findResolvedMemberRef(ConstraintLocator *locator) {
39703970
}
39713971

39723972
SolutionApplicationTarget::SolutionApplicationTarget(
3973-
Expr *expr, ContextualTypePurpose contextualPurpose,
3973+
Expr *expr, DeclContext *dc, ContextualTypePurpose contextualPurpose,
39743974
TypeLoc convertType, bool isDiscarded) {
39753975
// Verify that a purpose was specified if a convertType was. Note that it is
39763976
// ok to have a purpose without a convertType (which is used for call
@@ -3991,17 +3991,69 @@ SolutionApplicationTarget::SolutionApplicationTarget(
39913991

39923992
kind = Kind::expression;
39933993
expression.expression = expr;
3994+
expression.dc = dc;
39943995
expression.contextualPurpose = contextualPurpose;
39953996
expression.convertType = convertType;
39963997
expression.isDiscarded = isDiscarded;
39973998
}
39983999

3999-
bool SolutionApplicationTarget::contextualTypeIsOnlyAHint(
4000-
bool isOpaqueReturnType) const {
4000+
SolutionApplicationTarget SolutionApplicationTarget::forInitialization(
4001+
Expr *initializer, DeclContext *dc, Type patternType, Pattern *pattern) {
4002+
// Determine the contextual type for the initialization.
4003+
TypeLoc contextualType;
4004+
if (!isa<OptionalSomePattern>(pattern) &&
4005+
patternType && !patternType->isHole()) {
4006+
contextualType = TypeLoc::withoutLoc(patternType);
4007+
4008+
// Only provide a TypeLoc if it makes sense to allow diagnostics.
4009+
if (auto *typedPattern = dyn_cast<TypedPattern>(pattern)) {
4010+
const Pattern *inner = typedPattern->getSemanticsProvidingPattern();
4011+
if (isa<NamedPattern>(inner) || isa<AnyPattern>(inner)) {
4012+
contextualType = typedPattern->getTypeLoc();
4013+
if (!contextualType.getType())
4014+
contextualType.setType(patternType);
4015+
}
4016+
}
4017+
}
4018+
4019+
SolutionApplicationTarget target(
4020+
initializer, dc, CTP_Initialization, contextualType,
4021+
/*isDiscarded=*/false);
4022+
target.expression.pattern = pattern;
4023+
return target;
4024+
}
4025+
4026+
bool SolutionApplicationTarget::infersOpaqueReturnType() const {
4027+
assert(kind == Kind::expression);
4028+
switch (expression.contextualPurpose) {
4029+
case CTP_Initialization:
4030+
if (Type convertType = expression.convertType.getType()) {
4031+
return convertType->is<OpaqueTypeArchetypeType>();
4032+
}
4033+
return false;
4034+
4035+
case CTP_ReturnStmt:
4036+
case CTP_ReturnSingleExpr:
4037+
if (Type convertType = expression.convertType.getType()) {
4038+
if (auto opaqueType = convertType->getAs<OpaqueTypeArchetypeType>()) {
4039+
auto dc = getDeclContext();
4040+
if (auto func = dyn_cast<AbstractFunctionDecl>(dc)) {
4041+
return opaqueType->getDecl()->isOpaqueReturnTypeOfFunction(func);
4042+
}
4043+
}
4044+
}
4045+
return false;
4046+
4047+
default:
4048+
return false;
4049+
}
4050+
}
4051+
4052+
bool SolutionApplicationTarget::contextualTypeIsOnlyAHint() const {
40014053
assert(kind == Kind::expression);
40024054
switch (expression.contextualPurpose) {
40034055
case CTP_Initialization:
4004-
return !isOpaqueReturnType;
4056+
return !infersOpaqueReturnType();
40054057
case CTP_ForEachStmt:
40064058
return true;
40074059
case CTP_Unused:

lib/Sema/ConstraintSystem.h

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,14 +1147,23 @@ class SolutionApplicationTarget {
11471147

11481148
union {
11491149
struct {
1150+
/// The expression being type-checked.
11501151
Expr *expression;
11511152

1153+
/// The declaration context in which the expression is being
1154+
/// type-checked.
1155+
DeclContext *dc;
1156+
11521157
/// The purpose of the contextual type.
11531158
ContextualTypePurpose contextualPurpose;
11541159

11551160
/// The type to which the expression should be converted.
11561161
TypeLoc convertType;
11571162

1163+
/// When initializing a pattern from the expression, this is the
1164+
/// pattern.
1165+
Pattern *pattern = nullptr;
1166+
11581167
/// Whether the expression result will be discarded at the end.
11591168
bool isDiscarded;
11601169
} expression;
@@ -1166,14 +1175,15 @@ class SolutionApplicationTarget {
11661175
};
11671176

11681177
public:
1169-
SolutionApplicationTarget(Expr *expr,
1178+
SolutionApplicationTarget(Expr *expr, DeclContext *dc,
11701179
ContextualTypePurpose contextualPurpose,
11711180
Type convertType, bool isDiscarded)
1172-
: SolutionApplicationTarget(expr, contextualPurpose,
1181+
: SolutionApplicationTarget(expr, dc, contextualPurpose,
11731182
TypeLoc::withoutLoc(convertType),
11741183
isDiscarded) { }
11751184

1176-
SolutionApplicationTarget(Expr *expr, ContextualTypePurpose contextualPurpose,
1185+
SolutionApplicationTarget(Expr *expr, DeclContext *dc,
1186+
ContextualTypePurpose contextualPurpose,
11771187
TypeLoc convertType, bool isDiscarded);
11781188

11791189
SolutionApplicationTarget(AnyFunctionRef fn)
@@ -1185,6 +1195,10 @@ class SolutionApplicationTarget {
11851195
function.body = body;
11861196
}
11871197

1198+
/// Form a target for the initialization of a pattern from an expression.
1199+
static SolutionApplicationTarget forInitialization(
1200+
Expr *initializer, DeclContext *dc, Type patternType, Pattern *pattern);
1201+
11881202
Expr *getAsExpr() const {
11891203
switch (kind) {
11901204
case Kind::expression:
@@ -1195,6 +1209,16 @@ class SolutionApplicationTarget {
11951209
}
11961210
}
11971211

1212+
DeclContext *getDeclContext() const {
1213+
switch (kind) {
1214+
case Kind::expression:
1215+
return expression.dc;
1216+
1217+
case Kind::function:
1218+
return function.function.getAsDeclContext();
1219+
}
1220+
}
1221+
11981222
ContextualTypePurpose getExprContextualTypePurpose() const {
11991223
assert(kind == Kind::expression);
12001224
return expression.contextualPurpose;
@@ -1236,8 +1260,25 @@ class SolutionApplicationTarget {
12361260
expression.convertType = type;
12371261
}
12381262

1263+
/// For a pattern initialization target, retrieve the pattern.
1264+
Pattern *getInitializationPattern() const {
1265+
assert(kind == Kind::expression);
1266+
assert(expression.contextualPurpose == CTP_Initialization);
1267+
return expression.pattern;
1268+
}
1269+
1270+
/// Whether this is an initialization for an Optional.Some pattern.
1271+
bool isOptionalSomePatternInit() const {
1272+
return kind == Kind::expression &&
1273+
expression.contextualPurpose == CTP_Initialization &&
1274+
isa<OptionalSomePattern>(expression.pattern);
1275+
}
1276+
1277+
/// Whether this context infers an opaque return type.
1278+
bool infersOpaqueReturnType() const;
1279+
12391280
/// Whether the contextual type is only a hint, rather than a type
1240-
bool contextualTypeIsOnlyAHint(bool isOpaqueReturnType) const;
1281+
bool contextualTypeIsOnlyAHint() const;
12411282

12421283
bool isDiscardedExpr() const {
12431284
assert(kind == Kind::expression);

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 23 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,11 +2009,11 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20092009
ExprTypeCheckListener *listener,
20102010
ConstraintSystem *baseCS) {
20112011
SolutionApplicationTarget target(
2012-
expr, convertTypePurpose, convertType,
2012+
expr, dc, convertTypePurpose, convertType,
20132013
options.contains(TypeCheckExprFlags::IsDiscarded));
20142014
bool unresolvedTypeExprs = false;
20152015
auto resultTarget = typeCheckExpression(
2016-
target, dc, unresolvedTypeExprs, options, listener, baseCS);
2016+
target, unresolvedTypeExprs, options, listener, baseCS);
20172017
if (!resultTarget) {
20182018
expr = target.getAsExpr();
20192019
return Type();
@@ -2033,14 +2033,14 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20332033
Optional<SolutionApplicationTarget>
20342034
TypeChecker::typeCheckExpression(
20352035
SolutionApplicationTarget &target,
2036-
DeclContext *dc,
20372036
bool &unresolvedTypeExprs,
20382037
TypeCheckExprOptions options,
20392038
ExprTypeCheckListener *listener,
20402039
ConstraintSystem *baseCS) {
20412040
unresolvedTypeExprs = false;
2042-
auto &Context = dc->getASTContext();
20432041
Expr *expr = target.getAsExpr();
2042+
DeclContext *dc = target.getDeclContext();
2043+
auto &Context = dc->getASTContext();
20442044
FrontendStatsTracer StatsTracer(Context.Stats, "typecheck-expr", expr);
20452045
PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
20462046

@@ -2077,12 +2077,11 @@ TypeChecker::typeCheckExpression(
20772077
cs.setContextualType(
20782078
contextualTypeExpr, convertType,
20792079
target.getExprContextualTypePurpose(),
2080-
options.contains(TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType));
2080+
target.infersOpaqueReturnType());
20812081

20822082
// If the convertType is *only* provided for that hint, then null it out so
20832083
// that we don't later treat it as an actual conversion constraint.
2084-
if (target.contextualTypeIsOnlyAHint(
2085-
options.contains(TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType)))
2084+
if (target.contextualTypeIsOnlyAHint())
20862085
convertType = TypeLoc();
20872086

20882087
// If the client can handle unresolved type variables, leave them in the
@@ -2093,7 +2092,7 @@ TypeChecker::typeCheckExpression(
20932092

20942093
Type convertTo = convertType.getType();
20952094

2096-
if (options.contains(TypeCheckExprFlags::ExpressionTypeMustBeOptional)) {
2095+
if (target.isOptionalSomePatternInit()) {
20972096
assert(!convertTo && "convertType and type check options conflict");
20982097
auto *convertTypeLocator =
20992098
cs.getConstraintLocator(expr, LocatorPathElt::ContextualType());
@@ -2108,7 +2107,7 @@ TypeChecker::typeCheckExpression(
21082107

21092108
// Attempt to solve the constraint system.
21102109
SolutionApplicationTarget innerTarget(
2111-
expr, target.getExprContextualTypePurpose(), convertTo,
2110+
expr, dc, target.getExprContextualTypePurpose(), convertTo,
21122111
target.isDiscardedExpr());
21132112
auto viable = cs.solve(innerTarget, listener, allowFreeTypeVariables);
21142113
if (!viable) {
@@ -2207,7 +2206,7 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
22072206
if (needClearType)
22082207
expr->setType(Type());
22092208
SolutionApplicationTarget target(
2210-
expr, CTP_Unused, Type(), /*isDiscarded=*/false);
2209+
expr, dc, CTP_Unused, Type(), /*isDiscarded=*/false);
22112210
auto viable = cs.solve(target, listener, allowFreeTypeVariables);
22122211
if (!viable) {
22132212
recoverOriginalType();
@@ -2288,7 +2287,7 @@ void TypeChecker::getPossibleTypesOfExpressionWithoutApplying(
22882287
expr->setType(Type());
22892288

22902289
SolutionApplicationTarget target(
2291-
expr, CTP_Unused, Type(), /*isDiscarded=*/false);
2290+
expr, dc, CTP_Unused, Type(), /*isDiscarded=*/false);
22922291
if (auto viable = cs.solve(target, listener, allowFreeTypeVariables)) {
22932292
expr = target.getAsExpr();
22942293
for (auto &solution : *viable) {
@@ -2612,54 +2611,22 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
26122611
if (!initializer)
26132612
return true;
26142613

2615-
TypeLoc contextualType;
2616-
auto contextualPurpose = CTP_Unused;
2617-
TypeCheckExprOptions flags = None;
2618-
2619-
// Set the contextual purpose even if the pattern doesn't have a type so
2620-
// if there's an error we can use that information to inform diagnostics.
2621-
contextualPurpose = CTP_Initialization;
2622-
2623-
if (isa<OptionalSomePattern>(pattern)) {
2624-
flags |= TypeCheckExprFlags::ExpressionTypeMustBeOptional;
2625-
} else if (patternType && !patternType->isEqual(Context.TheUnresolvedType)) {
2626-
contextualType = TypeLoc::withoutLoc(patternType);
2627-
2628-
// If we already had an error, don't repeat the problem.
2629-
if (contextualType.getType()->hasError())
2630-
return true;
2631-
2632-
// Allow the initializer expression to establish the underlying type of an
2633-
// opaque type.
2634-
if (auto opaqueType = patternType->getAs<OpaqueTypeArchetypeType>()){
2635-
flags |= TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType;
2636-
}
2637-
2638-
// Only provide a TypeLoc if it makes sense to allow diagnostics.
2639-
if (auto *typedPattern = dyn_cast<TypedPattern>(pattern)) {
2640-
const Pattern *inner = typedPattern->getSemanticsProvidingPattern();
2641-
if (isa<NamedPattern>(inner) || isa<AnyPattern>(inner)) {
2642-
contextualType = typedPattern->getTypeLoc();
2643-
if (!contextualType.getType())
2644-
contextualType.setType(patternType);
2645-
}
2646-
}
2647-
}
2648-
26492614
// Type-check the initializer.
2650-
auto resultTy = typeCheckExpression(initializer, DC, contextualType,
2651-
contextualPurpose, flags, &listener);
2615+
auto target = SolutionApplicationTarget::forInitialization(
2616+
initializer, DC, patternType, pattern);
2617+
bool unresolvedTypeExprs = false;
2618+
auto resultTarget = typeCheckExpression(target, unresolvedTypeExprs,
2619+
None, &listener);
2620+
2621+
if (resultTarget) {
2622+
initializer = resultTarget->getAsExpr();
26522623

2653-
if (resultTy) {
26542624
TypeResolutionOptions options =
26552625
isa<EditorPlaceholderExpr>(initializer->getSemanticsProvidingExpr())
26562626
? TypeResolverContext::EditorPlaceholderExpr
26572627
: TypeResolverContext::InExpression;
26582628
options |= TypeResolutionFlags::OverrideType;
26592629

2660-
// FIXME: initTy should be the same as resultTy; now that typeCheckExpression()
2661-
// returns a Type and not bool, we should be able to simplify the listener
2662-
// implementation here.
26632630
auto initTy = listener.getPatternInitType(nullptr);
26642631
if (initTy->hasDependentMember())
26652632
return true;
@@ -2673,15 +2640,17 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
26732640
} else {
26742641
return true;
26752642
}
2643+
} else {
2644+
initializer = target.getAsExpr();
26762645
}
26772646

2678-
if (!resultTy && !initializer->getType())
2647+
if (!resultTarget && !initializer->getType())
26792648
initializer->setType(ErrorType::get(Context));
26802649

26812650
// If the type of the pattern is inferred, assign error types to the pattern
26822651
// and its variables, to prevent it from being referenced by the constraint
26832652
// system.
2684-
if (!resultTy &&
2653+
if (!resultTarget &&
26852654
(patternType->hasUnresolvedType() ||
26862655
patternType->hasUnboundGenericType())) {
26872656
pattern->setType(ErrorType::get(Context));
@@ -2697,7 +2666,7 @@ bool TypeChecker::typeCheckBinding(Pattern *&pattern, Expr *&initializer,
26972666
});
26982667
}
26992668

2700-
return !resultTy;
2669+
return !resultTarget;
27012670
}
27022671

27032672
bool TypeChecker::typeCheckPatternBinding(PatternBindingDecl *PBD,

lib/Sema/TypeCheckStmt.cpp

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -517,23 +517,6 @@ class StmtChecker : public StmtVisitor<StmtChecker, Stmt*> {
517517

518518
TypeCheckExprOptions options = {};
519519

520-
// If the result type is an opaque type, this is an opportunity to resolve
521-
// the underlying type.
522-
auto isOpaqueReturnTypeOfCurrentFunc = [&](OpaqueTypeDecl *opaque) -> bool {
523-
// Closures currently don't support having opaque types.
524-
auto funcDecl = TheFunc->getAbstractFunctionDecl();
525-
if (!funcDecl)
526-
return false;
527-
528-
return opaque->isOpaqueReturnTypeOfFunction(funcDecl);
529-
};
530-
531-
if (auto opaque = ResultTy->getAs<OpaqueTypeArchetypeType>()) {
532-
if (isOpaqueReturnTypeOfCurrentFunc(opaque->getDecl())) {
533-
options |= TypeCheckExprFlags::ConvertTypeIsOpaqueReturnType;
534-
}
535-
}
536-
537520
if (EndTypeCheckLoc.isValid()) {
538521
assert(DiagnosticSuppression::isEnabled(getASTContext().Diags) &&
539522
"Diagnosing and AllowUnresolvedTypeVariables don't seem to mix");

0 commit comments

Comments
 (0)