Skip to content

Commit ccde540

Browse files
authored
Merge pull request swiftlang#29487 from DougGregor/constraint-system-localized-opaque-result-type-flag
[Constraint system] Eliminate global flag UnderlyingTypeForOpaqueReturnType
2 parents f29de2e + 46a6500 commit ccde540

9 files changed

+186
-113
lines changed

Diff for: lib/Sema/BuilderTransform.cpp

-1
Original file line numberDiff line numberDiff line change
@@ -1041,7 +1041,6 @@ Optional<BraceStmt *> TypeChecker::applyFunctionBuilderBodyTransform(
10411041
ConstraintKind resultConstraintKind = ConstraintKind::Conversion;
10421042
if (auto opaque = resultContextType->getAs<OpaqueTypeArchetypeType>()) {
10431043
if (opaque->getDecl()->isOpaqueReturnTypeOfFunction(func)) {
1044-
options |= ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType;
10451044
resultConstraintKind = ConstraintKind::OpaqueUnderlyingType;
10461045
}
10471046
}

Diff for: lib/Sema/CSApply.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -7507,6 +7507,11 @@ ArrayRef<Solution> SolutionResult::getAmbiguousSolutions() const {
75077507
return makeArrayRef(solutions, numSolutions);
75087508
}
75097509

7510+
MutableArrayRef<Solution> SolutionResult::takeAmbiguousSolutions() && {
7511+
assert(getKind() == Ambiguous);
7512+
return MutableArrayRef<Solution>(solutions, numSolutions);
7513+
}
7514+
75107515
llvm::PointerUnion<Expr *, Stmt *> SolutionApplicationTarget::walk(
75117516
ASTWalker &walker) {
75127517
switch (kind) {

Diff for: lib/Sema/CSGen.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -3831,7 +3831,8 @@ bool ConstraintSystem::generateConstraints(StmtCondition condition,
38313831

38323832
case StmtConditionElement::CK_Boolean: {
38333833
Expr *condExpr = condElement.getBoolean();
3834-
setContextualType(condExpr, TypeLoc::withoutLoc(boolTy), CTP_Condition);
3834+
setContextualType(condExpr, TypeLoc::withoutLoc(boolTy), CTP_Condition,
3835+
/*isOpaqueReturnType=*/false);
38353836

38363837
condExpr = generateConstraints(condExpr, dc);
38373838
if (!condExpr) {

Diff for: lib/Sema/CSSimplify.cpp

+53
Original file line numberDiff line numberDiff line change
@@ -9064,6 +9064,59 @@ void ConstraintSystem::addConstraint(ConstraintKind kind, Type first,
90649064
}
90659065
}
90669066

9067+
void ConstraintSystem::addContextualConversionConstraint(
9068+
Expr *expr, ContextualTypeInfo contextualType) {
9069+
Type convertType = contextualType.getType();
9070+
if (convertType.isNull())
9071+
return;
9072+
9073+
// Determine the type of the constraint.
9074+
auto constraintKind = ConstraintKind::Conversion;
9075+
switch (contextualType.purpose) {
9076+
case CTP_ReturnStmt:
9077+
case CTP_ReturnSingleExpr:
9078+
case CTP_Initialization:
9079+
if (contextualType.isOpaqueReturnType)
9080+
constraintKind = ConstraintKind::OpaqueUnderlyingType;
9081+
break;
9082+
9083+
case CTP_CallArgument:
9084+
constraintKind = ConstraintKind::ArgumentConversion;
9085+
break;
9086+
9087+
case CTP_YieldByReference:
9088+
// In a by-reference yield, we expect the contextual type to be an
9089+
// l-value type, so the result must be bound to that.
9090+
constraintKind = ConstraintKind::Bind;
9091+
break;
9092+
9093+
case CTP_ArrayElement:
9094+
case CTP_AssignSource:
9095+
case CTP_CalleeResult:
9096+
case CTP_CannotFail:
9097+
case CTP_Condition:
9098+
case CTP_Unused:
9099+
case CTP_YieldByValue:
9100+
case CTP_ThrowStmt:
9101+
case CTP_EnumCaseRawValue:
9102+
case CTP_DefaultParameter:
9103+
case CTP_ClosureResult:
9104+
case CTP_DictionaryKey:
9105+
case CTP_DictionaryValue:
9106+
case CTP_CoerceOperand:
9107+
case CTP_SubscriptAssignSource:
9108+
case CTP_ForEachStmt:
9109+
break;
9110+
}
9111+
9112+
// Add the constraint.
9113+
bool isForSingleExprFunction = (contextualType.purpose == CTP_ReturnSingleExpr);
9114+
auto *convertTypeLocator = getConstraintLocator(
9115+
expr, LocatorPathElt::ContextualType(isForSingleExprFunction));
9116+
addConstraint(constraintKind, getType(expr), convertType,
9117+
convertTypeLocator, /*isFavored*/ true);
9118+
}
9119+
90679120
Type ConstraintSystem::addJoinConstraint(
90689121
ConstraintLocator *locator,
90699122
ArrayRef<std::pair<Type, ConstraintLocator *>> inputs) {

Diff for: lib/Sema/CSSolver.cpp

+103-85
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,8 @@ void ConstraintSystem::applySolution(const Solution &solution) {
240240
for (const auto &contextualType : solution.contextualTypes) {
241241
if (!getContextualTypeInfo(contextualType.first)) {
242242
setContextualType(contextualType.first, contextualType.second.typeLoc,
243-
contextualType.second.purpose);
243+
contextualType.second.purpose,
244+
contextualType.second.isOpaqueReturnType);
244245
}
245246
}
246247

@@ -591,7 +592,7 @@ bool ConstraintSystem::Candidate::solve(
591592
cs.Timer.emplace(E, cs);
592593

593594
// Generate constraints for the new system.
594-
if (auto generatedExpr = cs.generateConstraints(E)) {
595+
if (auto generatedExpr = cs.generateConstraints(E, DC)) {
595596
E = generatedExpr;
596597
} else {
597598
// Failure to generate constraint system for sub-expression
@@ -1115,80 +1116,93 @@ bool ConstraintSystem::solve(Expr *&expr,
11151116
getASTContext().TypeCheckerOpts.DebugConstraintSolver,
11161117
debugConstraintSolverForExpr(getASTContext(), expr));
11171118

1118-
// Attempt to solve the constraint system.
1119-
auto solution = solveImpl(expr,
1120-
convertType,
1121-
listener,
1122-
solutions,
1123-
allowFreeTypeVariables);
1124-
1125-
// The constraint system has failed
1126-
if (solution == SolutionKind::Error)
1127-
return true;
1128-
1129-
// If the system is unsolved or there are multiple solutions present but
1130-
// type checker options do not allow unresolved types, let's try to salvage
1131-
if (solution == SolutionKind::Unsolved ||
1132-
(solutions.size() != 1 &&
1133-
!Options.contains(
1134-
ConstraintSystemFlags::AllowUnresolvedTypeVariables))) {
1135-
if (shouldSuppressDiagnostics())
1136-
return true;
1119+
/// Dump solutions for debugging purposes.
1120+
auto dumpSolutions = [&] {
1121+
// Debug-print the set of solutions.
1122+
if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) {
1123+
auto &log = getASTContext().TypeCheckerDebug->getStream();
1124+
if (solutions.size() == 1) {
1125+
log << "---Solution---\n";
1126+
solutions[0].dump(log);
1127+
} else {
1128+
for (unsigned i = 0, e = solutions.size(); i != e; ++i) {
1129+
log << "--- Solution #" << i << " ---\n";
1130+
solutions[i].dump(log);
1131+
}
1132+
}
1133+
}
1134+
};
11371135

1138-
// Try to fix the system or provide a decent diagnostic.
1139-
auto salvagedResult = salvage();
1140-
switch (salvagedResult.getKind()) {
1141-
case SolutionResult::Kind::Success:
1136+
// Take up to two attempts at solving the system. The first attempts to
1137+
// solve a system that is expected to be well-formed, the second kicks in
1138+
// when there is an error and attempts to salvage an ill-formed expression.
1139+
for (unsigned stage = 0; stage != 2; ++stage) {
1140+
auto solution = (stage == 0)
1141+
? solveImpl(expr, convertType, listener, allowFreeTypeVariables)
1142+
: salvage();
1143+
1144+
switch (solution.getKind()) {
1145+
case SolutionResult::Success:
1146+
// Return the successful solution.
11421147
solutions.clear();
1143-
solutions.push_back(std::move(salvagedResult).takeSolution());
1144-
break;
1145-
1146-
case SolutionResult::Kind::Error:
1147-
case SolutionResult::Kind::Ambiguous:
1148-
return true;
1148+
solutions.push_back(std::move(solution).takeSolution());
1149+
dumpSolutions();
1150+
return false;
11491151

1150-
case SolutionResult::Kind::UndiagnosedError:
1151-
diagnoseFailureFor(expr);
1152-
salvagedResult.markAsDiagnosed();
1152+
case SolutionResult::Error:
11531153
return true;
11541154

1155-
case SolutionResult::Kind::TooComplex:
1155+
case SolutionResult::TooComplex:
11561156
getASTContext().Diags.diagnose(expr->getLoc(), diag::expression_too_complex)
1157-
.highlight(expr->getSourceRange());
1158-
salvagedResult.markAsDiagnosed();
1157+
.highlight(expr->getSourceRange());
1158+
solution.markAsDiagnosed();
11591159
return true;
1160-
}
11611160

1162-
// The system was salvaged; continue on as if nothing happened.
1163-
}
1161+
case SolutionResult::Ambiguous:
1162+
// If salvaging produced an ambiguous result, it has already been
1163+
// diagnosed.
1164+
if (stage == 1) {
1165+
solution.markAsDiagnosed();
1166+
return true;
1167+
}
11641168

1165-
if (getExpressionTooComplex(solutions)) {
1166-
getASTContext().Diags.diagnose(expr->getLoc(), diag::expression_too_complex)
1167-
.highlight(expr->getSourceRange());
1168-
return true;
1169-
}
1169+
if (Options.contains(
1170+
ConstraintSystemFlags::AllowUnresolvedTypeVariables)) {
1171+
auto ambiguousSolutions = std::move(solution).takeAmbiguousSolutions();
1172+
solutions.assign(std::make_move_iterator(ambiguousSolutions.begin()),
1173+
std::make_move_iterator(ambiguousSolutions.end()));
1174+
dumpSolutions();
1175+
solution.markAsDiagnosed();
1176+
return false;
1177+
}
11701178

1171-
if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) {
1172-
auto &log = getASTContext().TypeCheckerDebug->getStream();
1173-
if (solutions.size() == 1) {
1174-
log << "---Solution---\n";
1175-
solutions[0].dump(log);
1176-
} else {
1177-
for (unsigned i = 0, e = solutions.size(); i != e; ++i) {
1178-
log << "--- Solution #" << i << " ---\n";
1179-
solutions[i].dump(log);
1179+
LLVM_FALLTHROUGH;
1180+
1181+
case SolutionResult::UndiagnosedError:
1182+
if (shouldSuppressDiagnostics()) {
1183+
solution.markAsDiagnosed();
1184+
return true;
1185+
}
1186+
1187+
if (stage == 1) {
1188+
diagnoseFailureFor(expr);
1189+
solution.markAsDiagnosed();
1190+
return true;
11801191
}
1192+
1193+
// Loop again to try to salvage.
1194+
solution.markAsDiagnosed();
1195+
continue;
11811196
}
11821197
}
11831198

1184-
return false;
1199+
llvm_unreachable("Loop always returns");
11851200
}
11861201

1187-
ConstraintSystem::SolutionKind
1202+
SolutionResult
11881203
ConstraintSystem::solveImpl(Expr *&expr,
11891204
Type convertType,
11901205
ExprTypeCheckListener *listener,
1191-
SmallVectorImpl<Solution> &solutions,
11921206
FreeTypeVariableBinding allowFreeTypeVariables) {
11931207
if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) {
11941208
auto &log = getASTContext().TypeCheckerDebug->getStream();
@@ -1215,53 +1229,46 @@ ConstraintSystem::solveImpl(Expr *&expr,
12151229
shrink(expr);
12161230

12171231
// Generate constraints for the main system.
1218-
if (auto generatedExpr = generateConstraints(expr))
1232+
if (auto generatedExpr = generateConstraints(expr, DC))
12191233
expr = generatedExpr;
12201234
else {
12211235
if (listener)
12221236
listener->constraintGenerationFailed(expr);
1223-
return SolutionKind::Error;
1237+
return SolutionResult::forError();
12241238
}
12251239

12261240
// If there is a type that we're expected to convert to, add the conversion
12271241
// constraint.
12281242
if (convertType) {
1229-
auto constraintKind = ConstraintKind::Conversion;
1230-
1231-
auto ctp = getContextualTypePurpose(origExpr);
1232-
if ((ctp == CTP_ReturnStmt ||
1233-
ctp == CTP_ReturnSingleExpr ||
1234-
ctp == CTP_Initialization)
1235-
&& Options.contains(ConstraintSystemFlags::UnderlyingTypeForOpaqueReturnType))
1236-
constraintKind = ConstraintKind::OpaqueUnderlyingType;
1237-
1238-
if (ctp == CTP_CallArgument)
1239-
constraintKind = ConstraintKind::ArgumentConversion;
1240-
1241-
// In a by-reference yield, we expect the contextual type to be an
1242-
// l-value type, so the result must be bound to that.
1243-
if (ctp == CTP_YieldByReference)
1244-
constraintKind = ConstraintKind::Bind;
1245-
1246-
bool isForSingleExprFunction = ctp == CTP_ReturnSingleExpr;
1247-
auto *convertTypeLocator = getConstraintLocator(
1248-
expr, LocatorPathElt::ContextualType(isForSingleExprFunction));
1243+
// Determine whether we know more about the contextual type.
1244+
ContextualTypePurpose ctp = CTP_Unused;
1245+
bool isOpaqueReturnType = false;
1246+
if (auto contextualInfo = getContextualTypeInfo(origExpr)) {
1247+
ctp = contextualInfo->purpose;
1248+
isOpaqueReturnType = contextualInfo->isOpaqueReturnType;
1249+
}
12491250

1251+
// Substitute type variables in for unresolved types.
12501252
if (allowFreeTypeVariables == FreeTypeVariableBinding::UnresolvedType) {
1253+
bool isForSingleExprFunction = (ctp == CTP_ReturnSingleExpr);
1254+
auto *convertTypeLocator = getConstraintLocator(
1255+
expr, LocatorPathElt::ContextualType(isForSingleExprFunction));
1256+
12511257
convertType = convertType.transform([&](Type type) -> Type {
12521258
if (type->is<UnresolvedType>())
12531259
return createTypeVariable(convertTypeLocator, TVO_CanBindToNoEscape);
12541260
return type;
12551261
});
12561262
}
12571263

1258-
addConstraint(constraintKind, getType(expr), convertType,
1259-
convertTypeLocator, /*isFavored*/ true);
1264+
ContextualTypeInfo info{
1265+
TypeLoc::withoutLoc(convertType), ctp, isOpaqueReturnType};
1266+
addContextualConversionConstraint(expr, info);
12601267
}
12611268

12621269
// Notify the listener that we've built the constraint system.
12631270
if (listener && listener->builtConstraints(*this, expr)) {
1264-
return SolutionKind::Error;
1271+
return SolutionResult::forError();
12651272
}
12661273

12671274
if (getASTContext().TypeCheckerOpts.DebugConstraintSolver) {
@@ -1273,11 +1280,22 @@ ConstraintSystem::solveImpl(Expr *&expr,
12731280
}
12741281

12751282
// Try to solve the constraint system using computed suggestions.
1283+
SmallVector<Solution, 4> solutions;
12761284
solve(solutions, allowFreeTypeVariables);
12771285

1278-
// If there are no solutions let's mark system as unsolved,
1279-
// and solved otherwise even if there are multiple solutions still present.
1280-
return solutions.empty() ? SolutionKind::Unsolved : SolutionKind::Solved;
1286+
if (getExpressionTooComplex(solutions))
1287+
return SolutionResult::forTooComplex();
1288+
1289+
switch (solutions.size()) {
1290+
case 0:
1291+
return SolutionResult::forUndiagnosedError();
1292+
1293+
case 1:
1294+
return SolutionResult::forSolved(std::move(solutions.front()));
1295+
1296+
default:
1297+
return SolutionResult::forAmbiguous(solutions);
1298+
}
12811299
}
12821300

12831301
bool ConstraintSystem::solve(SmallVectorImpl<Solution> &solutions,

0 commit comments

Comments
 (0)