Skip to content

Commit c997080

Browse files
authored
Merge pull request #17980 from xedin/disable-diagnostics-for-codecompletion
[TypeChecker] Disable expression diagnostics for code completion
2 parents 57528ef + 8b3ea21 commit c997080

File tree

8 files changed

+132
-106
lines changed

8 files changed

+132
-106
lines changed

lib/Sema/CSApply.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8088,11 +8088,13 @@ bool ConstraintSystem::applySolutionFix(Expr *expr,
80888088
Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr,
80898089
Type convertType,
80908090
bool discardedExpr,
8091-
bool suppressDiagnostics,
80928091
bool skipClosures) {
80938092
// If any fixes needed to be applied to arrive at this solution, resolve
80948093
// them to specific expressions.
80958094
if (!solution.Fixes.empty()) {
8095+
if (shouldSuppressDiagnostics())
8096+
return nullptr;
8097+
80968098
// If we can diagnose the problem with the fixits that we've pre-assumed,
80978099
// do so now.
80988100
if (applySolutionFixes(expr, solution))
@@ -8108,7 +8110,7 @@ Expr *ConstraintSystem::applySolution(Solution &solution, Expr *expr,
81088110
for (auto &e : solution.Conformances)
81098111
TC.markConformanceUsed(e.second, DC);
81108112

8111-
ExprRewriter rewriter(*this, solution, suppressDiagnostics);
8113+
ExprRewriter rewriter(*this, solution, shouldSuppressDiagnostics());
81128114
ExprWalker walker(rewriter);
81138115

81148116
// Apply the solution to the expression.

lib/Sema/CSGen.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,7 @@ namespace {
11671167
if (!E->isActivated())
11681168
return Type();
11691169

1170+
CS.Options |= ConstraintSystemFlags::SuppressDiagnostics;
11701171
return CS.createTypeVariable(CS.getConstraintLocator(E),
11711172
TVO_CanBindToLValue);
11721173
}
@@ -3562,6 +3563,8 @@ class InferUnresolvedMemberConstraintGenerator : public ConstraintGenerator {
35623563
}
35633564

35643565
Type visitCodeCompletionExpr(CodeCompletionExpr *Expr) override {
3566+
auto &cs = getConstraintSystem();
3567+
cs.Options |= ConstraintSystemFlags::SuppressDiagnostics;
35653568
return createFreeTypeVariableType(Expr);
35663569
}
35673570

lib/Sema/CSSolver.cpp

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1320,12 +1320,63 @@ void ConstraintSystem::shrink(Expr *expr) {
13201320
}
13211321
}
13221322

1323+
bool ConstraintSystem::solve(Expr *&expr,
1324+
Type convertType,
1325+
ExprTypeCheckListener *listener,
1326+
SmallVectorImpl<Solution> &solutions,
1327+
FreeTypeVariableBinding allowFreeTypeVariables) {
1328+
// Attempt to solve the constraint system.
1329+
auto solution = solveImpl(expr,
1330+
convertType,
1331+
listener,
1332+
solutions,
1333+
allowFreeTypeVariables);
1334+
1335+
// The constraint system has failed
1336+
if (solution == SolutionKind::Error)
1337+
return true;
1338+
1339+
// If the system is unsolved or there are multiple solutions present but
1340+
// type checker options do not allow unresolved types, let's try to salvage
1341+
if (solution == SolutionKind::Unsolved ||
1342+
(solutions.size() != 1 &&
1343+
!Options.contains(
1344+
ConstraintSystemFlags::AllowUnresolvedTypeVariables))) {
1345+
if (shouldSuppressDiagnostics())
1346+
return true;
1347+
1348+
// Try to provide a decent diagnostic.
1349+
if (salvage(solutions, expr)) {
1350+
// If salvage produced an error message, then it failed to salvage the
1351+
// expression, just bail out having reported the error.
1352+
return true;
1353+
}
1354+
1355+
// The system was salvaged; continue on as if nothing happened.
1356+
}
1357+
1358+
if (TC.getLangOpts().DebugConstraintSolver) {
1359+
auto &log = getASTContext().TypeCheckerDebug->getStream();
1360+
if (solutions.size() == 1) {
1361+
log << "---Solution---\n";
1362+
solutions[0].dump(log);
1363+
} else {
1364+
for (unsigned i = 0, e = solutions.size(); i != e; ++i) {
1365+
log << "--- Solution #" << i << " ---\n";
1366+
solutions[i].dump(log);
1367+
}
1368+
}
1369+
}
1370+
1371+
return false;
1372+
}
1373+
13231374
ConstraintSystem::SolutionKind
1324-
ConstraintSystem::solve(Expr *&expr,
1325-
Type convertType,
1326-
ExprTypeCheckListener *listener,
1327-
SmallVectorImpl<Solution> &solutions,
1328-
FreeTypeVariableBinding allowFreeTypeVariables) {
1375+
ConstraintSystem::solveImpl(Expr *&expr,
1376+
Type convertType,
1377+
ExprTypeCheckListener *listener,
1378+
SmallVectorImpl<Solution> &solutions,
1379+
FreeTypeVariableBinding allowFreeTypeVariables) {
13291380
if (TC.getLangOpts().DebugConstraintSolver) {
13301381
auto &log = getASTContext().TypeCheckerDebug->getStream();
13311382
log << "---Constraint solving for the expression at ";

lib/Sema/ConstraintSystem.h

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,16 @@ enum class ConstraintSystemFlags {
790790
/// If set, this is going to prevent constraint system from erasing all
791791
/// discovered solutions except the best one.
792792
ReturnAllDiscoveredSolutions = 0x04,
793+
794+
/// Set if the client wants diagnostics suppressed.
795+
SuppressDiagnostics = 0x08,
796+
797+
/// If set, the client wants a best-effort solution to the constraint system,
798+
/// but can tolerate a solution where all of the constraints are solved, but
799+
/// not all type variables have been determined. In this case, the constraint
800+
/// system is not applied to the expression AST, but the ConstraintSystem is
801+
/// left in-tact.
802+
AllowUnresolvedTypeVariables = 0x10,
793803
};
794804

795805
/// Options that affect the constraint system as a whole.
@@ -1716,6 +1726,10 @@ class ConstraintSystem {
17161726
return !solverState || solverState->recordFixes;
17171727
}
17181728

1729+
bool shouldSuppressDiagnostics() {
1730+
return Options.contains(ConstraintSystemFlags::SuppressDiagnostics);
1731+
}
1732+
17191733
/// \brief Log and record the application of the fix. Return true iff any
17201734
/// subsequent solution would be worse than the best known solution.
17211735
bool recordFix(Fix fix, ConstraintLocatorBuilder locator);
@@ -2965,7 +2979,6 @@ class ConstraintSystem {
29652979
bool *foundConsistent);
29662980
bool areBindPairConsistent(Constraint *first, Constraint *second);
29672981

2968-
public:
29692982
/// \brief Solve the system of constraints generated from provided expression.
29702983
///
29712984
/// \param expr The expression to generate constraints from.
@@ -2977,12 +2990,34 @@ class ConstraintSystem {
29772990
///
29782991
/// \returns Error is an error occurred, Solved is system is consistent
29792992
/// and solutions were found, Unsolved otherwise.
2980-
SolutionKind solve(Expr *&expr,
2981-
Type convertType,
2982-
ExprTypeCheckListener *listener,
2983-
SmallVectorImpl<Solution> &solutions,
2984-
FreeTypeVariableBinding allowFreeTypeVariables
2985-
= FreeTypeVariableBinding::Disallow);
2993+
SolutionKind solveImpl(Expr *&expr,
2994+
Type convertType,
2995+
ExprTypeCheckListener *listener,
2996+
SmallVectorImpl<Solution> &solutions,
2997+
FreeTypeVariableBinding allowFreeTypeVariables
2998+
= FreeTypeVariableBinding::Disallow);
2999+
3000+
public:
3001+
/// \brief Solve the system of constraints generated from provided expression.
3002+
///
3003+
/// The expression should have already been pre-checked with
3004+
/// preCheckExpression().
3005+
///
3006+
/// \param expr The expression to generate constraints from.
3007+
/// \param convertType The expected type of the expression.
3008+
/// \param listener The callback to check solving progress.
3009+
/// \param solutions The set of solutions to the system of constraints.
3010+
/// \param allowFreeTypeVariables How to bind free type variables in
3011+
/// the solution.
3012+
///
3013+
/// \returns true is an error occurred, false is system is consistent
3014+
/// and solutions were found.
3015+
bool solve(Expr *&expr,
3016+
Type convertType,
3017+
ExprTypeCheckListener *listener,
3018+
SmallVectorImpl<Solution> &solutions,
3019+
FreeTypeVariableBinding allowFreeTypeVariables
3020+
= FreeTypeVariableBinding::Disallow);
29863021

29873022
/// \brief Solve the system of constraints.
29883023
///
@@ -3070,7 +3105,6 @@ class ConstraintSystem {
30703105
/// non-single expression closures.
30713106
Expr *applySolution(Solution &solution, Expr *expr,
30723107
Type convertType, bool discardedExpr,
3073-
bool suppressDiagnostics,
30743108
bool skipClosures);
30753109

30763110
/// \brief Apply a given solution to the expression to the top-level

lib/Sema/TypeCheckConstraints.cpp

Lines changed: 21 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1909,57 +1909,6 @@ bool GenericRequirementsCheckListener::diagnoseUnsatisfiedRequirement(
19091909
return false;
19101910
}
19111911

1912-
bool TypeChecker::
1913-
solveForExpression(Expr *&expr, DeclContext *dc, Type convertType,
1914-
FreeTypeVariableBinding allowFreeTypeVariables,
1915-
ExprTypeCheckListener *listener, ConstraintSystem &cs,
1916-
SmallVectorImpl<Solution> &viable,
1917-
TypeCheckExprOptions options) {
1918-
// Attempt to solve the constraint system.
1919-
auto solution = cs.solve(expr,
1920-
convertType,
1921-
listener,
1922-
viable,
1923-
allowFreeTypeVariables);
1924-
1925-
// The constraint system has failed
1926-
if (solution == ConstraintSystem::SolutionKind::Error)
1927-
return true;
1928-
1929-
// If the system is unsolved or there are multiple solutions present but
1930-
// type checker options do not allow unresolved types, let's try to salvage
1931-
if (solution == ConstraintSystem::SolutionKind::Unsolved
1932-
|| (viable.size() != 1 &&
1933-
!options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables))) {
1934-
if (options.contains(TypeCheckExprFlags::SuppressDiagnostics))
1935-
return true;
1936-
1937-
// Try to provide a decent diagnostic.
1938-
if (cs.salvage(viable, expr)) {
1939-
// If salvage produced an error message, then it failed to salvage the
1940-
// expression, just bail out having reported the error.
1941-
return true;
1942-
}
1943-
1944-
// The system was salvaged; continue on as if nothing happened.
1945-
}
1946-
1947-
if (getLangOpts().DebugConstraintSolver) {
1948-
auto &log = Context.TypeCheckerDebug->getStream();
1949-
if (viable.size() == 1) {
1950-
log << "---Solution---\n";
1951-
viable[0].dump(log);
1952-
} else {
1953-
for (unsigned i = 0, e = viable.size(); i != e; ++i) {
1954-
log << "--- Solution #" << i << " ---\n";
1955-
viable[i].dump(log);
1956-
}
1957-
}
1958-
}
1959-
1960-
return false;
1961-
}
1962-
19631912
#pragma mark High-level entry points
19641913
Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
19651914
TypeLoc convertType,
@@ -1976,6 +1925,13 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
19761925

19771926
// Construct a constraint system from this expression.
19781927
ConstraintSystemOptions csOptions = ConstraintSystemFlags::AllowFixes;
1928+
1929+
if (options.contains(TypeCheckExprFlags::SuppressDiagnostics))
1930+
csOptions |= ConstraintSystemFlags::SuppressDiagnostics;
1931+
1932+
if (options.contains(TypeCheckExprFlags::AllowUnresolvedTypeVariables))
1933+
csOptions |= ConstraintSystemFlags::AllowUnresolvedTypeVariables;
1934+
19791935
ConstraintSystem cs(*this, dc, csOptions);
19801936
cs.baseCS = baseCS;
19811937
CleanupIllFormedExpressionRAII cleanup(expr);
@@ -2007,9 +1963,6 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20071963
// that we don't later treat it as an actual conversion constraint.
20081964
if (options.contains(TypeCheckExprFlags::ConvertTypeIsOnlyAHint))
20091965
convertType = TypeLoc();
2010-
2011-
bool suppressDiagnostics =
2012-
options.contains(TypeCheckExprFlags::SuppressDiagnostics);
20131966

20141967
// If the client can handle unresolved type variables, leave them in the
20151968
// system.
@@ -2019,8 +1972,8 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20191972

20201973
// Attempt to solve the constraint system.
20211974
SmallVector<Solution, 4> viable;
2022-
if (solveForExpression(expr, dc, convertType.getType(),
2023-
allowFreeTypeVariables, listener, cs, viable, options))
1975+
if (cs.solve(expr, convertType.getType(), listener, viable,
1976+
allowFreeTypeVariables))
20241977
return Type();
20251978

20261979
// If the client allows the solution to have unresolved type expressions,
@@ -2046,11 +1999,10 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20461999
}
20472000

20482001
// Apply the solution to the expression.
2049-
bool isDiscarded = options.contains(TypeCheckExprFlags::IsDiscarded);
2050-
bool skipClosures = options.contains(TypeCheckExprFlags::SkipMultiStmtClosures);
2051-
result = cs.applySolution(solution, result, convertType.getType(),
2052-
isDiscarded, suppressDiagnostics,
2053-
skipClosures);
2002+
result = cs.applySolution(
2003+
solution, result, convertType.getType(),
2004+
options.contains(TypeCheckExprFlags::IsDiscarded),
2005+
options.contains(TypeCheckExprFlags::SkipMultiStmtClosures));
20542006
if (!result) {
20552007
// Failure already diagnosed, above, as part of applying the solution.
20562008
return Type();
@@ -2072,7 +2024,7 @@ Type TypeChecker::typeCheckExpression(Expr *&expr, DeclContext *dc,
20722024

20732025
// Unless the client has disabled them, perform syntactic checks on the
20742026
// expression now.
2075-
if (!suppressDiagnostics &&
2027+
if (!cs.shouldSuppressDiagnostics() &&
20762028
!options.contains(TypeCheckExprFlags::DisableStructuralChecks)) {
20772029
bool isExprStmt = options.contains(TypeCheckExprFlags::IsExprStmt);
20782030
performSyntacticExprDiagnostics(*this, result, dc, isExprStmt);
@@ -2092,7 +2044,7 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
20922044
referencedDecl = nullptr;
20932045

20942046
// Construct a constraint system from this expression.
2095-
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::AllowFixes);
2047+
ConstraintSystem cs(*this, dc, ConstraintSystemFlags::SuppressDiagnostics);
20962048
CleanupIllFormedExpressionRAII cleanup(expr);
20972049

20982050
// Attempt to solve the constraint system.
@@ -2108,9 +2060,8 @@ getTypeOfExpressionWithoutApplying(Expr *&expr, DeclContext *dc,
21082060
// re-check.
21092061
if (needClearType)
21102062
expr->setType(Type());
2111-
if (solveForExpression(expr, dc, /*convertType*/Type(),
2112-
allowFreeTypeVariables, listener, cs, viable,
2113-
TypeCheckExprFlags::SuppressDiagnostics)) {
2063+
if (cs.solve(expr, /*convertType*/Type(), listener, viable,
2064+
allowFreeTypeVariables)) {
21142065
recoverOriginalType();
21152066
return Type();
21162067
}
@@ -2177,8 +2128,8 @@ void TypeChecker::getPossibleTypesOfExpressionWithoutApplying(
21772128

21782129
// Construct a constraint system from this expression.
21792130
ConstraintSystemOptions options;
2180-
options |= ConstraintSystemFlags::AllowFixes;
21812131
options |= ConstraintSystemFlags::ReturnAllDiscoveredSolutions;
2132+
options |= ConstraintSystemFlags::SuppressDiagnostics;
21822133

21832134
ConstraintSystem cs(*this, dc, options);
21842135

@@ -2194,9 +2145,8 @@ void TypeChecker::getPossibleTypesOfExpressionWithoutApplying(
21942145
if (originalType && originalType->hasError())
21952146
expr->setType(Type());
21962147

2197-
solveForExpression(expr, dc, /*convertType*/ Type(), allowFreeTypeVariables,
2198-
listener, cs, viable,
2199-
TypeCheckExprFlags::SuppressDiagnostics);
2148+
cs.solve(expr, /*convertType*/ Type(), listener, viable,
2149+
allowFreeTypeVariables);
22002150
}
22012151

22022152
for (auto &solution : viable) {
@@ -2210,7 +2160,7 @@ bool TypeChecker::typeCheckCompletionSequence(Expr *&expr, DeclContext *DC) {
22102160
PrettyStackTraceExpr stackTrace(Context, "type-checking", expr);
22112161

22122162
// Construct a constraint system from this expression.
2213-
ConstraintSystem CS(*this, DC, ConstraintSystemFlags::AllowFixes);
2163+
ConstraintSystem CS(*this, DC, ConstraintSystemFlags::SuppressDiagnostics);
22142164
CleanupIllFormedExpressionRAII cleanup(expr);
22152165

22162166
auto *SE = cast<SequenceExpr>(expr);

lib/Sema/TypeChecker.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -900,13 +900,17 @@ bool swift::typeCheckExpression(DeclContext *DC, Expr *&parsedExpr) {
900900
auto &ctx = DC->getASTContext();
901901
if (ctx.getLazyResolver()) {
902902
TypeChecker *TC = static_cast<TypeChecker *>(ctx.getLazyResolver());
903-
auto resultTy = TC->typeCheckExpression(parsedExpr, DC);
903+
auto resultTy = TC->typeCheckExpression(parsedExpr, DC, TypeLoc(),
904+
ContextualTypePurpose::CTP_Unused,
905+
TypeCheckExprFlags::SuppressDiagnostics);
904906
return !resultTy;
905907
} else {
906908
// Set up a diagnostics engine that swallows diagnostics.
907909
DiagnosticEngine diags(ctx.SourceMgr);
908910
TypeChecker TC(ctx, diags);
909-
auto resultTy = TC.typeCheckExpression(parsedExpr, DC);
911+
auto resultTy = TC.typeCheckExpression(parsedExpr, DC, TypeLoc(),
912+
ContextualTypePurpose::CTP_Unused,
913+
TypeCheckExprFlags::SuppressDiagnostics);
910914
return !resultTy;
911915
}
912916
}

0 commit comments

Comments
 (0)