diff --git a/lib/Sema/TypeCheckExprObjC.cpp b/lib/Sema/TypeCheckExprObjC.cpp index 9aa8fbe6891e7..25703d7e231e8 100644 --- a/lib/Sema/TypeCheckExprObjC.cpp +++ b/lib/Sema/TypeCheckExprObjC.cpp @@ -161,7 +161,8 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, // Local function to perform name lookup for the current index. auto performLookup = [&](unsigned idx, Identifier componentName, - SourceLoc componentNameLoc) -> LookupResult { + SourceLoc componentNameLoc, + Type &lookupType) -> LookupResult { if (state == Beginning) return lookupUnqualified(dc, componentName, componentNameLoc); @@ -170,7 +171,6 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, // Determine the type in which the lookup should occur. If we have // a bridged value type, this will be the Objective-C class to // which it is bridged. - Type lookupType; if (auto bridgedClass = getBridgedToObjC(dc, currentType)) lookupType = bridgedClass; else @@ -210,15 +210,17 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, } // Look for this component. - LookupResult lookup = performLookup(idx, componentName, componentNameLoc); + Type lookupType; + LookupResult lookup = performLookup(idx, componentName, componentNameLoc, + lookupType); // If we didn't find anything, try to apply typo-correction. bool resultsAreFromTypoCorrection = false; if (!lookup) { - performTypoCorrection(dc, DeclRefKind::Ordinary, currentType, + performTypoCorrection(dc, DeclRefKind::Ordinary, lookupType, componentName, componentNameLoc, - (currentType ? defaultMemberTypeLookupOptions - : defaultUnqualifiedLookupOptions), + (lookupType ? defaultMemberTypeLookupOptions + : defaultUnqualifiedLookupOptions), lookup); if (currentType) @@ -263,7 +265,7 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, if (resultsAreFromTypoCorrection) break; - if (currentType) + if (lookupType) diagnose(componentNameLoc, diag::ambiguous_member_overload_set, componentName); else @@ -325,9 +327,9 @@ Optional TypeChecker::checkObjCKeyPathExpr(DeclContext *dc, } Type newType; - if (currentType && !currentType->isAnyObject()) { - newType = currentType->getTypeOfMember(dc->getParentModule(), type, - this); + if (lookupType && !lookupType->isAnyObject()) { + newType = lookupType->getTypeOfMember(dc->getParentModule(), type, + this); } else { newType = type->getDeclaredInterfaceType(); } diff --git a/test/expr/unary/keypath/keypath.swift b/test/expr/unary/keypath/keypath.swift index 5c9687e4fceb2..6da4b815efc75 100644 --- a/test/expr/unary/keypath/keypath.swift +++ b/test/expr/unary/keypath/keypath.swift @@ -33,6 +33,16 @@ class C { var nonObjC: String? // expected-note{{add '@objc' to expose this var to Objective-C}}{{3-3=@objc }} } +extension NSArray { + @objc class Foo : NSObject { + @objc var propString: String = "" + } +} + +extension Array { + typealias Foo = NSArray.Foo +} + func testKeyPath(a: A, b: B) { // Property let _: String = #keyPath(A.propB) @@ -84,6 +94,10 @@ func testKeyPath(a: A, b: B) { // Property with keyword name. let _: String = #keyPath(A.repeat) + + // Nested type of a bridged type (rdar://problem/28061409). + typealias IntArray = [Int] + let _: String = #keyPath(IntArray.Foo.propString) } func testAsStaticString() {