Skip to content

Commit f03685b

Browse files
committed
Introduce a command-line option to limit the # of typo corrections.
Typo correction can be particularly expensive, so introduce a command-line flag to limit the number of typo corrections we will perform per type-checker instance. Default this limit to 10. Addresses rdar://problem/28469270 to some extent.
1 parent a6516a9 commit f03685b

File tree

10 files changed

+48
-8
lines changed

10 files changed

+48
-8
lines changed

include/swift/Basic/LangOptions.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ namespace swift {
7979
/// \brief Disable API availability checking.
8080
bool DisableAvailabilityChecking = false;
8181

82-
/// \brief Disable typo correction.
83-
bool DisableTypoCorrection = false;
82+
/// \brief Maximum number of typo corrections we are allowed to perform.
83+
unsigned TypoCorrectionLimit = 10;
8484

8585
/// Should access control be respected?
8686
bool EnableAccessControl = true;

include/swift/Frontend/Frontend.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ class CompilerInvocation {
271271
CodeCompletionBuffer = Buf;
272272
CodeCompletionOffset = Offset;
273273
// We don't need typo-correction for code-completion.
274-
LangOpts.DisableTypoCorrection = true;
274+
// FIXME: This isn't really true, but is a performance issue.
275+
LangOpts.TypoCorrectionLimit = 0;
275276
}
276277

277278
std::pair<llvm::MemoryBuffer *, unsigned> getCodeCompletionPoint() const {

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,11 @@ def warn_swift3_objc_inference_minimal :
295295
Flags<[FrontendOption, DoesNotAffectIncrementalBuild]>,
296296
HelpText<"Warn about deprecated @objc inference in Swift 3 based on direct uses of the Objective-C entrypoint">;
297297

298+
def typo_correction_limit : Separate<["-"], "typo-correction-limit">,
299+
Flags<[FrontendOption, HelpHidden]>,
300+
MetaVarName<"<n>">,
301+
HelpText<"Limit the number of times the compiler will attempt typo correction to <n>">;
302+
298303
def warn_swift3_objc_inference : Flag<["-"], "warn-swift3-objc-inference">,
299304
Alias<warn_swift3_objc_inference_complete>,
300305
Flags<[FrontendOption, DoesNotAffectIncrementalBuild, HelpHidden]>;

lib/Driver/ToolChains.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@ static void addCommonFrontendArgs(const ToolChain &TC,
129129
inputArgs.AddLastArg(arguments,
130130
options::OPT_warn_swift3_objc_inference_minimal,
131131
options::OPT_warn_swift3_objc_inference_complete);
132+
inputArgs.AddLastArg(arguments, options::OPT_typo_correction_limit);
132133
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);
133134
inputArgs.AddLastArg(arguments, options::OPT_enable_testing);
134135
inputArgs.AddLastArg(arguments, options::OPT_g_Group);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -981,7 +981,21 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
981981
= A->getOption().matches(OPT_enable_access_control);
982982
}
983983

984-
Opts.DisableTypoCorrection |= Args.hasArg(OPT_disable_typo_correction);
984+
if (auto A = Args.getLastArg(OPT_disable_typo_correction,
985+
OPT_typo_correction_limit)) {
986+
if (A->getOption().matches(OPT_disable_typo_correction))
987+
Opts.TypoCorrectionLimit = 0;
988+
else {
989+
unsigned limit;
990+
if (StringRef(A->getValue()).getAsInteger(10, limit)) {
991+
Diags.diagnose(SourceLoc(), diag::error_invalid_arg_value,
992+
A->getAsString(Args), A->getValue());
993+
return true;
994+
}
995+
996+
Opts.TypoCorrectionLimit = limit;
997+
}
998+
}
985999

9861000
Opts.CodeCompleteInitsInPostfixExpr |=
9871001
Args.hasArg(OPT_code_complete_inits_in_postfix_expr);

lib/Sema/TypeCheckNameLookup.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -564,12 +564,15 @@ void TypeChecker::performTypoCorrection(DeclContext *DC, DeclRefKind refKind,
564564
LookupResult &result,
565565
GenericSignatureBuilder *gsb,
566566
unsigned maxResults) {
567-
// Disable typo-correction if we won't show the diagnostic anyway.
568-
if (getLangOpts().DisableTypoCorrection ||
567+
// Disable typo-correction if we won't show the diagnostic anyway or if
568+
// we've hit our typo correction limit.
569+
if (NumTypoCorrections >= getLangOpts().TypoCorrectionLimit ||
569570
(Diags.hasFatalErrorOccurred() &&
570571
!Diags.getShowDiagnosticsAfterFatalError()))
571572
return;
572573

574+
++NumTypoCorrections;
575+
573576
// Fill in a collection of the most reasonable entries.
574577
TopCollection<unsigned, ValueDecl*> entries(maxResults);
575578
auto consumer = makeDeclConsumer([&](ValueDecl *decl,

lib/Sema/TypeChecker.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -747,6 +747,9 @@ class TypeChecker final : public LazyResolver {
747747
llvm::DenseMap<AbstractFunctionDecl *, llvm::DenseSet<ApplyExpr *>>
748748
FunctionAsEscapingArg;
749749

750+
/// The # of times we have performed typo correction.
751+
unsigned NumTypoCorrections = 0;
752+
750753
public:
751754
/// Record an occurrence of a function that captures inout values as an
752755
/// argument.

test/Sema/typo_correction.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -typo-correction-limit 20
22
// RUN: not %target-swift-frontend -typecheck -disable-typo-correction %s 2>&1 | %FileCheck %s -check-prefix=DISABLED
3+
// RUN: not %target-swift-frontend -typecheck -typo-correction-limit 0 %s 2>&1 | %FileCheck %s -check-prefix=DISABLED
34
// RUN: not %target-swift-frontend -typecheck -DIMPORT_FAIL %s 2>&1 | %FileCheck %s -check-prefix=DISABLED
45
// DISABLED-NOT: did you mean
56

test/Sema/typo_correction_limit.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %target-typecheck-verify-swift -typo-correction-limit 5
2+
3+
// This is close enough to get typo-correction.
4+
func test_short_and_close() {
5+
let foo = 4 // expected-note 5 {{did you mean 'foo'?}}
6+
let _ = fob + 1 // expected-error {{use of unresolved identifier}}
7+
let _ = fob + 1 // expected-error {{use of unresolved identifier}}
8+
let _ = fob + 1 // expected-error {{use of unresolved identifier}}
9+
let _ = fob + 1 // expected-error {{use of unresolved identifier}}
10+
let _ = fob + 1 // expected-error {{use of unresolved identifier}}
11+
let _ = fob + 1 // expected-error {{use of unresolved identifier}}
12+
}

tools/swift-ide-test/swift-ide-test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2762,7 +2762,7 @@ static int doPrintIndexedSymbols(const CompilerInvocation &InitInvok,
27622762
CompilerInvocation Invocation(InitInvok);
27632763
Invocation.addInputFilename(SourceFileName);
27642764
Invocation.getLangOptions().DisableAvailabilityChecking = false;
2765-
Invocation.getLangOptions().DisableTypoCorrection = true;
2765+
Invocation.getLangOptions().TypoCorrectionLimit = 0;
27662766

27672767
CompilerInstance CI;
27682768

0 commit comments

Comments
 (0)