Skip to content

Commit 3d0252a

Browse files
authored
Merge pull request #3307 from rjmccall/typo-correction-for-qualified-lookup
2 parents ff5b879 + 6593c53 commit 3d0252a

File tree

9 files changed

+58
-18
lines changed

9 files changed

+58
-18
lines changed

Diff for: include/swift/AST/DiagnosticsSema.def

+2
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,8 @@ ERROR(use_undeclared_type_did_you_mean,none,
555555
"use of undeclared type %0; did you mean to use '%1'?", (Identifier, StringRef))
556556
NOTE(note_typo_candidate,none,
557557
"did you mean '%0'?", (StringRef))
558+
NOTE(note_typo_candidate_implicit_member,none,
559+
"did you mean the implicitly-synthesized %1 '%0'?", (StringRef, StringRef))
558560
NOTE(note_remapped_type,none,
559561
"did you mean to use '%0'?", (StringRef))
560562
ERROR(identifier_init_failure,none,

Diff for: lib/Sema/CSDiag.cpp

+20-1
Original file line numberDiff line numberDiff line change
@@ -2231,6 +2231,14 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
22312231

22322232
// If we found no results at all, mention that fact.
22332233
if (result.UnviableCandidates.empty()) {
2234+
LookupResult correctionResults;
2235+
auto tryTypoCorrection = [&] {
2236+
CS->TC.performTypoCorrection(CS->DC, DeclRefKind::Ordinary, baseObjTy,
2237+
memberName, nameLoc.getBaseNameLoc(),
2238+
defaultMemberLookupOptions,
2239+
correctionResults);
2240+
};
2241+
22342242
// TODO: This should handle tuple member lookups, like x.1231 as well.
22352243
if (memberName.isSimpleName("subscript")) {
22362244
diagnose(loc, diag::type_not_subscriptable, baseObjTy)
@@ -2239,18 +2247,29 @@ diagnoseUnviableLookupResults(MemberLookupResult &result, Type baseObjTy,
22392247
diagnose(loc, diag::could_not_find_type_member,
22402248
MTT->getInstanceType(), memberName)
22412249
.highlight(baseRange).highlight(nameLoc.getSourceRange());
2250+
tryTypoCorrection();
22422251
} else {
22432252
diagnose(loc, diag::could_not_find_value_member,
22442253
baseObjTy, memberName)
22452254
.highlight(baseRange).highlight(nameLoc.getSourceRange());
2255+
tryTypoCorrection();
22462256

22472257
// Check for a few common cases that can cause missing members.
22482258
if (baseObjTy->is<EnumType>() && memberName.isSimpleName("rawValue")) {
22492259
auto loc = baseObjTy->castTo<EnumType>()->getDecl()->getNameLoc();
2250-
if (loc.isValid())
2260+
if (loc.isValid()) {
22512261
diagnose(loc, diag::did_you_mean_raw_type);
2262+
return; // Always prefer this over typo corrections.
2263+
}
22522264
}
22532265
}
2266+
2267+
// Note all the correction candidates.
2268+
for (auto &correction : correctionResults) {
2269+
CS->TC.noteTypoCorrection(memberName, nameLoc, correction);
2270+
}
2271+
2272+
// TODO: recover?
22542273
return;
22552274
}
22562275

Diff for: lib/Sema/TypeCheckNameLookup.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -557,8 +557,7 @@ void TypeChecker::performTypoCorrection(DeclContext *DC, DeclRefKind refKind,
557557
TypoCorrectionResolver resolver(*this, nameLoc);
558558
if (baseTypeOrNull) {
559559
lookupVisibleMemberDecls(consumer, baseTypeOrNull, DC, &resolver,
560-
/*include instance members*/
561-
!(lookupOptions & NameLookupFlags::OnlyTypes));
560+
/*include instance members*/ true);
562561
} else {
563562
lookupVisibleDecls(consumer, DC, &resolver, /*top level*/ true, nameLoc);
564563
}
@@ -580,6 +579,21 @@ diagnoseTypoCorrection(TypeChecker &tc, DeclNameLoc loc, ValueDecl *decl) {
580579
decl->getName().str());
581580
}
582581

582+
if (!decl->getLoc().isValid() && decl->getDeclContext()->isTypeContext()) {
583+
Decl *parentDecl = dyn_cast<ExtensionDecl>(decl->getDeclContext());
584+
if (!parentDecl) parentDecl = cast<NominalTypeDecl>(decl->getDeclContext());
585+
586+
if (parentDecl->getLoc().isValid()) {
587+
StringRef kind = (isa<VarDecl>(decl) ? "property" :
588+
isa<ConstructorDecl>(decl) ? "initializer" :
589+
isa<FuncDecl>(decl) ? "method" :
590+
"member");
591+
592+
return tc.diagnose(parentDecl, diag::note_typo_candidate_implicit_member,
593+
decl->getName().str(), kind);
594+
}
595+
}
596+
583597
return tc.diagnose(decl, diag::note_typo_candidate, decl->getName().str());
584598
}
585599

Diff for: test/Constraints/diagnostics.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -492,7 +492,7 @@ func rdar20868864(_ s: String) {
492492

493493
// <rdar://problem/20491794> Error message does not tell me what the problem is
494494
enum Color {
495-
case Red
495+
case Red // expected-note 2 {{did you mean 'Red'?}}
496496
case Unknown(description: String)
497497

498498
static func rainbow() -> Color {}

Diff for: test/Constraints/dynamic_lookup.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ class Y : P {
3939
init() {}
4040

4141
@objc func foo(_ s: String) { }
42-
@objc func wibble() { }
42+
@objc func wibble() { } // expected-note 2 {{did you mean 'wibble'?}}
4343

4444
@objc func ovl1() -> A { }
4545

Diff for: test/Generics/Inputs/associated_types_multi_file_helper.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
protocol Fooable {
2-
associatedtype AssocType
2+
associatedtype AssocType // expected-note {{did you mean 'AssocType'?}}
33
func foo(x : AssocType)
44
}
55

Diff for: test/NameBinding/name_lookup.swift

+11-11
Original file line numberDiff line numberDiff line change
@@ -35,15 +35,15 @@ class ThisBase1 {
3535

3636
class func baseStaticFunc0() {}
3737

38-
struct BaseNestedStruct {}
38+
struct BaseNestedStruct {} // expected-note {{did you mean 'BaseNestedStruct'?}}
3939
class BaseNestedClass {
4040
init() { }
4141
}
4242
enum BaseNestedUnion {
4343
case BaseUnionX(Int)
4444
}
4545

46-
typealias BaseNestedTypealias = Int
46+
typealias BaseNestedTypealias = Int // expected-note {{did you mean 'BaseNestedTypealias'?}}
4747
}
4848

4949
class ThisDerived1 : ThisBase1 {
@@ -85,7 +85,7 @@ class ThisDerived1 : ThisBase1 {
8585
class DerivedNestedClass {
8686
init() { }
8787
}
88-
enum DerivedNestedUnion {
88+
enum DerivedNestedUnion { // expected-note {{did you mean 'DerivedNestedUnion'?}}
8989
case DerivedUnionX(Int)
9090
}
9191

@@ -351,26 +351,26 @@ extension ThisBase1 {
351351

352352
func baseExtFunc0() {}
353353

354-
var baseExtStaticVar: Int // expected-error {{extensions may not contain stored properties}}
354+
var baseExtStaticVar: Int // expected-error {{extensions may not contain stored properties}} // expected-note 2 {{did you mean 'baseExtStaticVar'?}}
355355

356-
var baseExtStaticProp: Int {
356+
var baseExtStaticProp: Int { // expected-note 2 {{did you mean 'baseExtStaticProp'?}}
357357
get {
358358
return 42
359359
}
360360
set {}
361361
}
362362

363-
class func baseExtStaticFunc0() {}
363+
class func baseExtStaticFunc0() {} // expected-note {{did you mean 'baseExtStaticFunc0'?}}
364364

365-
struct BaseExtNestedStruct {}
366-
class BaseExtNestedClass {
365+
struct BaseExtNestedStruct {} // expected-note 2 {{did you mean 'BaseExtNestedStruct'?}}
366+
class BaseExtNestedClass { // expected-note {{did you mean 'BaseExtNestedClass'?}}
367367
init() { }
368368
}
369-
enum BaseExtNestedUnion {
369+
enum BaseExtNestedUnion { // expected-note {{did you mean 'BaseExtNestedUnion'?}}
370370
case BaseExtUnionX(Int)
371371
}
372372

373-
typealias BaseExtNestedTypealias = Int
373+
typealias BaseExtNestedTypealias = Int // expected-note 2 {{did you mean 'BaseExtNestedTypealias'?}}
374374
}
375375

376376
extension ThisDerived1 {
@@ -398,7 +398,7 @@ extension ThisDerived1 {
398398
class DerivedExtNestedClass {
399399
init() { }
400400
}
401-
enum DerivedExtNestedUnion {
401+
enum DerivedExtNestedUnion { // expected-note {{did you mean 'DerivedExtNestedUnion'?}}
402402
case DerivedExtUnionX(Int)
403403
}
404404

Diff for: test/decl/enum/enumtest.swift

+5
Original file line numberDiff line numberDiff line change
@@ -305,3 +305,8 @@ enum E21269142 { // expected-note {{did you mean to specify a raw type on the e
305305

306306
print(E21269142.Foo.rawValue) // expected-error {{value of type 'E21269142' has no member 'rawValue'}}
307307

308+
// Check that typo correction does something sensible with synthesized members.
309+
enum SyntheticMember { // expected-note {{did you mean the implicitly-synthesized property 'hashValue'?}}
310+
case Foo
311+
}
312+
print(SyntheticMember.Foo.hasValue) // expected-error {{value of type 'SyntheticMember' has no member 'hasValue'}}

Diff for: test/decl/ext/protocol_objc.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// REQUIRES: objc_interop
44

55
@objc protocol OP1 {
6-
func reqOP1a() -> Bool
6+
func reqOP1a() -> Bool // expected-note {{did you mean 'reqOP1a'?}}
77
}
88

99
extension OP1 {

0 commit comments

Comments
 (0)