Skip to content

Commit 0fbf70e

Browse files
authored
Merge pull request #84659 from tshortli/member-import-visibility-resolve-decl-ref-expr-fix
Sema: Fix a MemberImportVisibility regression in `resolveDeclRefExpr()`
2 parents cd7924a + 8053120 commit 0fbf70e

File tree

5 files changed

+211
-137
lines changed

5 files changed

+211
-137
lines changed

lib/Sema/PreCheckTarget.cpp

Lines changed: 164 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -518,11 +518,12 @@ diagnoseUnqualifiedInit(UnresolvedDeclRefExpr *initExpr, DeclContext *dc,
518518
initExpr->getNameLoc(), /*implicit=*/true);
519519
}
520520

521-
/// Bind an UnresolvedDeclRefExpr by performing name lookup and
522-
/// returning the resultant expression. Context is the DeclContext used
523-
/// for the lookup.
524-
Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
525-
DeclContext *DC) {
521+
/// Bind an UnresolvedDeclRefExpr by performing name lookup using the given
522+
/// options and returning the resultant expression. `DC` is the DeclContext
523+
/// used for the lookup. If the lookup doesn't find any results, returns
524+
/// `nullptr`.
525+
static Expr *resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE, DeclContext *DC,
526+
NameLookupOptions lookupOptions) {
526527
auto &Context = DC->getASTContext();
527528
DeclNameRef Name = UDRE->getName();
528529
SourceLoc Loc = UDRE->getLoc();
@@ -562,14 +563,6 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
562563
LookupName = DeclNameRef(lookupName);
563564
}
564565

565-
// Perform standard value name lookup.
566-
NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions;
567-
// TODO: Include all of the possible members to give a solver a
568-
// chance to diagnose name shadowing which requires explicit
569-
// name/module qualifier to access top-level name.
570-
lookupOptions |= NameLookupFlags::IncludeOuterResults;
571-
lookupOptions |= NameLookupFlags::IgnoreMissingImports;
572-
573566
LookupResult Lookup;
574567

575568
bool AllDeclRefs = true;
@@ -628,17 +621,8 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
628621
}
629622

630623
if (!Lookup) {
631-
// If we failed lookup of an operator, check to see if this is a range
632-
// operator misspelling. Otherwise try to diagnose a juxtaposition
633-
// e.g. (x*-4) that needs whitespace.
634-
if (diagnoseRangeOperatorMisspell(Context.Diags, UDRE) ||
635-
diagnoseIncDecOperator(Context.Diags, UDRE) ||
636-
diagnoseOperatorJuxtaposition(UDRE, DC) ||
637-
diagnoseNonexistentPowerOperator(Context.Diags, UDRE, DC)) {
638-
return errorResult();
639-
}
640-
641-
// Try ignoring access control.
624+
// For the purpose of diagnosing inaccessible results, try the lookup again
625+
// but ignore access control.
642626
NameLookupOptions relookupOptions = lookupOptions;
643627
relookupOptions |= NameLookupFlags::IgnoreAccessControl;
644628
auto inaccessibleResults =
@@ -663,117 +647,8 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
663647
return errorResult();
664648
}
665649

666-
// TODO: Name will be a compound name if it was written explicitly as
667-
// one, but we should also try to propagate labels into this.
668-
DeclNameLoc nameLoc = UDRE->getNameLoc();
669-
670-
Identifier simpleName = Name.getBaseIdentifier();
671-
const char *buffer = simpleName.get();
672-
llvm::SmallString<64> expectedIdentifier;
673-
bool isConfused = false;
674-
uint32_t codepoint;
675-
uint32_t firstConfusableCodepoint = 0;
676-
int totalCodepoints = 0;
677-
int offset = 0;
678-
while ((codepoint = validateUTF8CharacterAndAdvance(buffer,
679-
buffer +
680-
strlen(buffer)))
681-
!= ~0U) {
682-
int length = (buffer - simpleName.get()) - offset;
683-
if (auto expectedCodepoint =
684-
confusable::tryConvertConfusableCharacterToASCII(codepoint)) {
685-
if (firstConfusableCodepoint == 0) {
686-
firstConfusableCodepoint = codepoint;
687-
}
688-
isConfused = true;
689-
expectedIdentifier += expectedCodepoint;
690-
} else {
691-
expectedIdentifier += (char)codepoint;
692-
}
693-
694-
totalCodepoints++;
695-
696-
offset += length;
697-
}
698-
699-
auto emitBasicError = [&] {
700-
701-
if (Name.isSimpleName(Context.Id_self)) {
702-
// `self` gets diagnosed with a different error when it can't be found.
703-
Context.Diags
704-
.diagnose(Loc, diag::cannot_find_self_in_scope)
705-
.highlight(UDRE->getSourceRange());
706-
} else {
707-
Context.Diags
708-
.diagnose(Loc, diag::cannot_find_in_scope, Name,
709-
Name.isOperator())
710-
.highlight(UDRE->getSourceRange());
711-
}
712-
713-
if (!Context.LangOpts.DisableExperimentalClangImporterDiagnostics) {
714-
Context.getClangModuleLoader()->diagnoseTopLevelValue(
715-
Name.getFullName());
716-
}
717-
};
718-
719-
if (!isConfused) {
720-
if (Name.isSimpleName(Context.Id_Self)) {
721-
if (DeclContext *typeContext = DC->getInnermostTypeContext()){
722-
Type SelfType = typeContext->getSelfInterfaceType();
723-
724-
if (typeContext->getSelfClassDecl() &&
725-
!typeContext->getSelfClassDecl()->isForeignReferenceType())
726-
SelfType = DynamicSelfType::get(SelfType, Context);
727-
return new (Context)
728-
TypeExpr(new (Context) SelfTypeRepr(SelfType, Loc));
729-
}
730-
}
731-
732-
TypoCorrectionResults corrections(Name, nameLoc);
733-
734-
// FIXME: Don't perform typo correction inside macro arguments, because it
735-
// will invoke synthesizing declarations in this scope, which will attempt to
736-
// expand this macro which leads to circular reference errors.
737-
if (!namelookup::isInMacroArgument(DC->getParentSourceFile(), UDRE->getLoc())) {
738-
TypeChecker::performTypoCorrection(DC, UDRE->getRefKind(), Type(),
739-
lookupOptions, corrections);
740-
}
741-
742-
if (auto typo = corrections.claimUniqueCorrection()) {
743-
auto diag = Context.Diags.diagnose(
744-
Loc, diag::cannot_find_in_scope_corrected, Name,
745-
Name.isOperator(), typo->CorrectedName.getBaseIdentifier().str());
746-
diag.highlight(UDRE->getSourceRange());
747-
typo->addFixits(diag);
748-
} else {
749-
emitBasicError();
750-
}
751-
752-
corrections.noteAllCandidates();
753-
} else {
754-
emitBasicError();
755-
756-
if (totalCodepoints == 1) {
757-
auto charNames = confusable::getConfusableAndBaseCodepointNames(
758-
firstConfusableCodepoint);
759-
Context.Diags
760-
.diagnose(Loc, diag::single_confusable_character,
761-
UDRE->getName().isOperator(), simpleName.str(),
762-
charNames.first, expectedIdentifier, charNames.second)
763-
.fixItReplace(Loc, expectedIdentifier);
764-
} else {
765-
Context.Diags
766-
.diagnose(Loc, diag::confusable_character,
767-
UDRE->getName().isOperator(), simpleName.str(),
768-
expectedIdentifier)
769-
.fixItReplace(Loc, expectedIdentifier);
770-
}
771-
}
772-
773-
// TODO: consider recovering from here. We may want some way to suppress
774-
// downstream diagnostics, though.
775-
776-
return errorResult();
650+
// No results were found.
651+
return nullptr;
777652
}
778653

779654
// FIXME: Need to refactor the way we build an AST node from a lookup result!
@@ -892,8 +767,9 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
892767
UDRE->getNameLoc().getStartLoc());
893768
}
894769

895-
return buildRefExpr(ResultValues, DC, UDRE->getNameLoc(),
896-
UDRE->isImplicit(), UDRE->getFunctionRefInfo());
770+
return TypeChecker::buildRefExpr(ResultValues, DC, UDRE->getNameLoc(),
771+
UDRE->isImplicit(),
772+
UDRE->getFunctionRefInfo());
897773
}
898774

899775
ResultValues.clear();
@@ -983,6 +859,157 @@ Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
983859
return errorResult();
984860
}
985861

862+
Expr *TypeChecker::resolveDeclRefExpr(UnresolvedDeclRefExpr *UDRE,
863+
DeclContext *DC) {
864+
auto &Context = DC->getASTContext();
865+
866+
// Perform standard value name lookup.
867+
NameLookupOptions lookupOptions = defaultUnqualifiedLookupOptions;
868+
// TODO: Include all of the possible members to give a solver a
869+
// chance to diagnose name shadowing which requires explicit
870+
// name/module qualifier to access top-level name.
871+
lookupOptions |= NameLookupFlags::IncludeOuterResults;
872+
873+
Expr *result = ::resolveDeclRefExpr(UDRE, DC, lookupOptions);
874+
if (!result && Context.LangOpts.hasFeature(Feature::MemberImportVisibility,
875+
/*allowMigration=*/true)) {
876+
// If we didn't find a result, try again but this time relax
877+
// MemberImportVisibility restrictions. Note that diagnosing the missing
878+
// import is already handled by resolveDeclRefExpr().
879+
lookupOptions |= NameLookupFlags::IgnoreMissingImports;
880+
result = ::resolveDeclRefExpr(UDRE, DC, lookupOptions);
881+
}
882+
883+
if (result)
884+
return result;
885+
886+
// We didn't find any results. Look for common mistakes to diagnose.
887+
DeclNameRef Name = UDRE->getName();
888+
SourceLoc Loc = UDRE->getLoc();
889+
if (Loc.isInvalid())
890+
DC = DC->getModuleScopeContext();
891+
892+
auto errorResult = [&]() -> Expr * {
893+
return new (Context) ErrorExpr(UDRE->getSourceRange());
894+
};
895+
896+
// If we failed lookup of an operator, check to see if this is a range
897+
// operator misspelling. Otherwise try to diagnose a juxtaposition
898+
// e.g. (x*-4) that needs whitespace.
899+
if (diagnoseRangeOperatorMisspell(Context.Diags, UDRE) ||
900+
diagnoseIncDecOperator(Context.Diags, UDRE) ||
901+
diagnoseOperatorJuxtaposition(UDRE, DC) ||
902+
diagnoseNonexistentPowerOperator(Context.Diags, UDRE, DC)) {
903+
return errorResult();
904+
}
905+
906+
// TODO: Name will be a compound name if it was written explicitly as
907+
// one, but we should also try to propagate labels into this.
908+
DeclNameLoc nameLoc = UDRE->getNameLoc();
909+
910+
Identifier simpleName = Name.getBaseIdentifier();
911+
const char *buffer = simpleName.get();
912+
llvm::SmallString<64> expectedIdentifier;
913+
bool isConfused = false;
914+
uint32_t codepoint;
915+
uint32_t firstConfusableCodepoint = 0;
916+
int totalCodepoints = 0;
917+
int offset = 0;
918+
while ((codepoint = validateUTF8CharacterAndAdvance(
919+
buffer, buffer + strlen(buffer))) != ~0U) {
920+
int length = (buffer - simpleName.get()) - offset;
921+
if (auto expectedCodepoint =
922+
confusable::tryConvertConfusableCharacterToASCII(codepoint)) {
923+
if (firstConfusableCodepoint == 0) {
924+
firstConfusableCodepoint = codepoint;
925+
}
926+
isConfused = true;
927+
expectedIdentifier += expectedCodepoint;
928+
} else {
929+
expectedIdentifier += (char)codepoint;
930+
}
931+
932+
totalCodepoints++;
933+
934+
offset += length;
935+
}
936+
937+
auto emitBasicError = [&] {
938+
if (Name.isSimpleName(Context.Id_self)) {
939+
// `self` gets diagnosed with a different error when it can't be found.
940+
Context.Diags.diagnose(Loc, diag::cannot_find_self_in_scope)
941+
.highlight(UDRE->getSourceRange());
942+
} else {
943+
Context.Diags
944+
.diagnose(Loc, diag::cannot_find_in_scope, Name, Name.isOperator())
945+
.highlight(UDRE->getSourceRange());
946+
}
947+
948+
if (!Context.LangOpts.DisableExperimentalClangImporterDiagnostics) {
949+
Context.getClangModuleLoader()->diagnoseTopLevelValue(Name.getFullName());
950+
}
951+
};
952+
953+
if (!isConfused) {
954+
if (Name.isSimpleName(Context.Id_Self)) {
955+
if (DeclContext *typeContext = DC->getInnermostTypeContext()) {
956+
Type SelfType = typeContext->getSelfInterfaceType();
957+
958+
if (typeContext->getSelfClassDecl() &&
959+
!typeContext->getSelfClassDecl()->isForeignReferenceType())
960+
SelfType = DynamicSelfType::get(SelfType, Context);
961+
return new (Context)
962+
TypeExpr(new (Context) SelfTypeRepr(SelfType, Loc));
963+
}
964+
}
965+
966+
TypoCorrectionResults corrections(Name, nameLoc);
967+
968+
// FIXME: Don't perform typo correction inside macro arguments, because it
969+
// will invoke synthesizing declarations in this scope, which will attempt
970+
// to expand this macro which leads to circular reference errors.
971+
if (!namelookup::isInMacroArgument(DC->getParentSourceFile(),
972+
UDRE->getLoc())) {
973+
TypeChecker::performTypoCorrection(DC, UDRE->getRefKind(), Type(),
974+
lookupOptions, corrections);
975+
}
976+
977+
if (auto typo = corrections.claimUniqueCorrection()) {
978+
auto diag = Context.Diags.diagnose(
979+
Loc, diag::cannot_find_in_scope_corrected, Name, Name.isOperator(),
980+
typo->CorrectedName.getBaseIdentifier().str());
981+
diag.highlight(UDRE->getSourceRange());
982+
typo->addFixits(diag);
983+
} else {
984+
emitBasicError();
985+
}
986+
987+
corrections.noteAllCandidates();
988+
} else {
989+
emitBasicError();
990+
991+
if (totalCodepoints == 1) {
992+
auto charNames = confusable::getConfusableAndBaseCodepointNames(
993+
firstConfusableCodepoint);
994+
Context.Diags
995+
.diagnose(Loc, diag::single_confusable_character,
996+
UDRE->getName().isOperator(), simpleName.str(),
997+
charNames.first, expectedIdentifier, charNames.second)
998+
.fixItReplace(Loc, expectedIdentifier);
999+
} else {
1000+
Context.Diags
1001+
.diagnose(Loc, diag::confusable_character,
1002+
UDRE->getName().isOperator(), simpleName.str(),
1003+
expectedIdentifier)
1004+
.fixItReplace(Loc, expectedIdentifier);
1005+
}
1006+
}
1007+
1008+
// TODO: consider recovering from here. We may want some way to suppress
1009+
// downstream diagnostics, though.
1010+
return errorResult();
1011+
}
1012+
9861013
/// If an expression references 'self.init' or 'super.init' in an
9871014
/// initializer context, returns the implicit 'self' decl of the constructor.
9881015
/// Otherwise, return nil.

test/NameLookup/Inputs/MemberImportVisibility/members_A.swift

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,24 @@ infix operator <<<
1616
infix operator >>>
1717
infix operator <>
1818

19+
@available(*, deprecated)
20+
public func shadowedByMemberOnXinA() { }
21+
22+
@available(*, deprecated)
23+
public func shadowedByMemberOnXinB() { }
24+
25+
@available(*, deprecated)
26+
public func shadowedByMemberOnXinC() { }
27+
28+
@available(*, deprecated)
29+
public func shadowedByStaticMemberOnXinA() { }
30+
31+
@available(*, deprecated)
32+
public func shadowedByStaticMemberOnXinB() { }
33+
34+
@available(*, deprecated)
35+
public func shadowedByStaticMemberOnXinC() { }
36+
1937
extension X {
2038
public func XinA() { }
2139

@@ -28,6 +46,9 @@ extension X {
2846

2947
public struct NestedInA {}
3048
public protocol ProtoNestedInA {}
49+
50+
public func shadowedByMemberOnXinA() { }
51+
public static func shadowedByStaticMemberOnXinA() { }
3152
}
3253

3354
extension Y {

test/NameLookup/Inputs/MemberImportVisibility/members_B.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,11 @@ extension X {
1111
public var propXinB: Bool { return true }
1212
package var propXinB_package: Bool { return true }
1313

14+
public func shadowedByMemberOnXinB() { }
15+
public static func shadowedByStaticMemberOnXinB() { }
16+
17+
public static var max: Int { return Int.min }
18+
1419
public static func >>>(a: Self, b: Self) -> Self { b }
1520

1621
public struct NestedInB {}

test/NameLookup/Inputs/MemberImportVisibility/members_C.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ extension X {
1010

1111
public var propXinC: Bool { return true }
1212

13+
public func shadowedByMemberOnXinC() { }
14+
public static func shadowedByStaticMemberOnXinC() { }
15+
1316
public static func <>(a: Self, b: Self) -> Self { a }
1417

1518
public struct NestedInC {}

0 commit comments

Comments
 (0)