Skip to content

Commit 447ce81

Browse files
authored
Merge pull request swiftlang#75746 from tshortli/member-import-visibility-import-accurate-access-levels
Sema: Look through missing imports during type lookup
2 parents 2a6c662 + 178315e commit 447ce81

File tree

4 files changed

+127
-51
lines changed

4 files changed

+127
-51
lines changed

lib/AST/NameLookup.cpp

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,10 @@ enum class DirectlyReferencedTypeLookupFlags {
10921092
/// Include results that are members of protocols to which the contextual
10931093
/// type conforms.
10941094
AllowProtocolMembers = 1 << 2,
1095+
1096+
/// Include members that would normally be excluded because they come from
1097+
/// modules that have not been imported directly.
1098+
IgnoreMissingImports = 1 << 3,
10951099
};
10961100

10971101
using DirectlyReferencedTypeLookupOptions =
@@ -2917,6 +2921,10 @@ static DirectlyReferencedTypeDecls directReferencesForUnqualifiedTypeLookup(
29172921
DirectlyReferencedTypeLookupFlags::AllowUsableFromInline))
29182922
options |= UnqualifiedLookupFlags::IncludeUsableFromInline;
29192923

2924+
if (typeLookupOptions.contains(
2925+
DirectlyReferencedTypeLookupFlags::IgnoreMissingImports))
2926+
options |= UnqualifiedLookupFlags::IgnoreMissingImports;
2927+
29202928
// Manually exclude macro expansions here since the source location
29212929
// is overridden below.
29222930
if (namelookup::isInMacroArgument(dc->getParentSourceFile(), loc))
@@ -2968,14 +2976,10 @@ static DirectlyReferencedTypeDecls directReferencesForUnqualifiedTypeLookup(
29682976
}
29692977

29702978
/// Perform qualified name lookup for types.
2971-
static llvm::TinyPtrVector<TypeDecl *>
2972-
directReferencesForQualifiedTypeLookup(Evaluator &evaluator,
2973-
ASTContext &ctx,
2974-
ArrayRef<TypeDecl *> baseTypes,
2975-
DeclNameRef name,
2976-
DeclContext *dc,
2977-
SourceLoc loc,
2978-
bool allowUsableFromInline=false) {
2979+
static llvm::TinyPtrVector<TypeDecl *> directReferencesForQualifiedTypeLookup(
2980+
Evaluator &evaluator, ASTContext &ctx, ArrayRef<TypeDecl *> baseTypes,
2981+
DeclNameRef name, DeclContext *dc, SourceLoc loc,
2982+
DirectlyReferencedTypeLookupOptions typeLookupOptions) {
29792983
llvm::TinyPtrVector<TypeDecl *> result;
29802984
auto addResults = [&result](ArrayRef<ValueDecl *> found){
29812985
for (auto decl : found){
@@ -2990,9 +2994,14 @@ directReferencesForQualifiedTypeLookup(Evaluator &evaluator,
29902994
SmallVector<ValueDecl *, 4> members;
29912995
auto options = NL_RemoveNonVisible | NL_OnlyTypes;
29922996

2993-
if (allowUsableFromInline)
2997+
if (typeLookupOptions.contains(
2998+
DirectlyReferencedTypeLookupFlags::AllowUsableFromInline))
29942999
options |= NL_IncludeUsableFromInline;
29953000

3001+
if (typeLookupOptions.contains(
3002+
DirectlyReferencedTypeLookupFlags::IgnoreMissingImports))
3003+
options |= NL_IgnoreMissingImports;
3004+
29963005
// Look through the type declarations we were given, resolving them down
29973006
// to nominal type declarations, module declarations, and
29983007
SmallVector<ModuleDecl *, 2> moduleDecls;
@@ -3031,8 +3040,7 @@ static DirectlyReferencedTypeDecls directReferencesForDeclRefTypeRepr(
30313040
// For a qualified identifier, perform qualified name lookup.
30323041
result.first = directReferencesForQualifiedTypeLookup(
30333042
evaluator, ctx, result.first, repr->getNameRef(), dc, repr->getLoc(),
3034-
options.contains(
3035-
DirectlyReferencedTypeLookupFlags::AllowUsableFromInline));
3043+
options);
30363044

30373045
return result;
30383046
}
@@ -3419,6 +3427,16 @@ ExtendedNominalRequest::evaluate(Evaluator &evaluator,
34193427
DirectlyReferencedTypeDecls referenced = directReferencesForTypeRepr(
34203428
evaluator, ctx, typeRepr, ext->getParent(), options);
34213429

3430+
// If there were no results, expand the lookup to include members that are
3431+
// inaccessible due to missing imports. The missing imports will be diagnosed
3432+
// elsewhere.
3433+
if (referenced.first.empty() &&
3434+
ctx.LangOpts.hasFeature(Feature::MemberImportVisibility)) {
3435+
options |= DirectlyReferencedTypeLookupFlags::IgnoreMissingImports;
3436+
referenced = directReferencesForTypeRepr(evaluator, ctx, typeRepr,
3437+
ext->getParent(), options);
3438+
}
3439+
34223440
// Resolve those type declarations to nominal type declarations.
34233441
SmallVector<ModuleDecl *, 2> modulesFound;
34243442
bool anyObject = false;

lib/Sema/CSDiagnostics.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -90,12 +90,6 @@ class FailureDiagnostic {
9090

9191
ConstraintLocator *getLocator() const { return Locator; }
9292

93-
SourceLoc getBestAddImportFixItLocation(const Decl *Member,
94-
SourceFile *sourceFile) const {
95-
auto &engine = Member->getASTContext().Diags;
96-
return engine.getBestAddImportFixItLoc(Member, sourceFile);
97-
}
98-
9993
Type getType(ASTNode node, bool wantRValue = true) const;
10094

10195
/// Get type associated with a given ASTNode without resolving it,

lib/Sema/TypeCheckType.cpp

Lines changed: 31 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1381,20 +1381,6 @@ static Type diagnoseUnknownType(const TypeResolution &resolution,
13811381
return ErrorType::get(ctx);
13821382
}
13831383

1384-
// Try ignoring missing imports.
1385-
relookupOptions |= NameLookupFlags::IgnoreMissingImports;
1386-
auto nonImportedResults = TypeChecker::lookupUnqualifiedType(
1387-
dc, repr->getNameRef(), repr->getLoc(), relookupOptions);
1388-
if (!nonImportedResults.empty()) {
1389-
auto first = cast<TypeDecl>(nonImportedResults.front().getValueDecl());
1390-
auto nameLoc = repr->getNameLoc();
1391-
maybeDiagnoseMissingImportForMember(first, dc, nameLoc.getStartLoc());
1392-
1393-
// Don't try to recover here; we'll get more access-related diagnostics
1394-
// downstream if we do.
1395-
return ErrorType::get(ctx);
1396-
}
1397-
13981384
// Fallback.
13991385
auto L = repr->getNameLoc();
14001386
SourceRange R = repr->getNameLoc().getSourceRange();
@@ -1486,19 +1472,6 @@ static Type diagnoseUnknownType(const TypeResolution &resolution,
14861472
return ErrorType::get(ctx);
14871473
}
14881474

1489-
// Try ignoring missing imports.
1490-
relookupOptions |= NameLookupFlags::IgnoreMissingImports;
1491-
auto nonImportedMembers = TypeChecker::lookupMemberType(
1492-
dc, parentType, repr->getNameRef(), repr->getLoc(), relookupOptions);
1493-
if (nonImportedMembers) {
1494-
const TypeDecl *first = nonImportedMembers.front().Member;
1495-
auto nameLoc = repr->getNameLoc();
1496-
maybeDiagnoseMissingImportForMember(first, dc, nameLoc.getStartLoc());
1497-
// Don't try to recover here; we'll get more access-related diagnostics
1498-
// downstream if we do.
1499-
return ErrorType::get(ctx);
1500-
}
1501-
15021475
// FIXME: Typo correction!
15031476

15041477
// Lookup into a type.
@@ -1656,6 +1629,16 @@ resolveUnqualifiedIdentTypeRepr(const TypeResolution &resolution,
16561629
auto globals =
16571630
TypeChecker::lookupUnqualifiedType(DC, id, repr->getLoc(), lookupOptions);
16581631

1632+
// If the look up did not yield any results, try again but allow members from
1633+
// modules that are not directly imported to be accessible.
1634+
bool didIgnoreMissingImports = false;
1635+
if (!globals && ctx.LangOpts.hasFeature(Feature::MemberImportVisibility)) {
1636+
lookupOptions |= NameLookupFlags::IgnoreMissingImports;
1637+
globals = TypeChecker::lookupUnqualifiedType(DC, id, repr->getLoc(),
1638+
lookupOptions);
1639+
didIgnoreMissingImports = true;
1640+
}
1641+
16591642
// If we're doing structural resolution and one of the results is an
16601643
// associated type, ignore any other results found from the same
16611644
// DeclContext; they are going to be protocol typealiases, possibly
@@ -1730,6 +1713,11 @@ resolveUnqualifiedIdentTypeRepr(const TypeResolution &resolution,
17301713

17311714
// If we found a type declaration with the given name, return it now.
17321715
if (current) {
1716+
if (didIgnoreMissingImports &&
1717+
maybeDiagnoseMissingImportForMember(currentDecl, DC, repr->getLoc())) {
1718+
repr->setInvalid();
1719+
return ErrorType::get(ctx);
1720+
}
17331721
repr->setValue(currentDecl, currentDC);
17341722
return current;
17351723
}
@@ -1901,10 +1889,25 @@ static Type resolveQualifiedIdentTypeRepr(const TypeResolution &resolution,
19011889
if (options.contains(TypeResolutionFlags::AllowUsableFromInline))
19021890
lookupOptions |= NameLookupFlags::IncludeUsableFromInline;
19031891
LookupTypeResult memberTypes;
1904-
if (parentTy->mayHaveMembers())
1892+
if (parentTy->mayHaveMembers()) {
19051893
memberTypes = TypeChecker::lookupMemberType(
19061894
DC, parentTy, repr->getNameRef(), repr->getLoc(), lookupOptions);
19071895

1896+
// If no members were found, try ignoring missing imports.
1897+
if (!memberTypes &&
1898+
ctx.LangOpts.hasFeature(Feature::MemberImportVisibility)) {
1899+
lookupOptions |= NameLookupFlags::IgnoreMissingImports;
1900+
memberTypes = TypeChecker::lookupMemberType(
1901+
DC, parentTy, repr->getNameRef(), repr->getLoc(), lookupOptions);
1902+
1903+
if (memberTypes.size() == 1) {
1904+
if (maybeDiagnoseMissingImportForMember(memberTypes.back().Member, DC,
1905+
repr->getLoc()))
1906+
return ErrorType::get(ctx);
1907+
}
1908+
}
1909+
}
1910+
19081911
// Name lookup was ambiguous. Complain.
19091912
// FIXME: Could try to apply generic arguments first, and see whether
19101913
// that resolves things. But do we really want that to succeed?

test/NameLookup/members_transitive_multifile_access_level.swift

Lines changed: 67 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
// RUN: %target-swift-frontend -emit-module -o %t %t/Exports.swift -I %t
1111
// RUN: %target-swift-frontend -typecheck -verify -swift-version 5 \
1212
// RUN: -primary-file %t/function_bodies.swift \
13-
// RUN: -primary-file %t/function_signatures.swift \
13+
// RUN: -primary-file %t/function_signatures_unqualified.swift \
14+
// RUN: -primary-file %t/function_signatures_qualified.swift \
15+
// RUN: -primary-file %t/extensions.swift \
1416
// RUN: %t/imports.swift \
1517
// RUN: -I %t -package-name Package \
1618
// RUN: -enable-experimental-feature MemberImportVisibility
@@ -45,24 +47,76 @@ func internalFunc(_ x: Int) {
4547
_ = x.memberInMixedUses // expected-error {{property 'memberInMixedUses' is not available due to missing import of defining module 'MixedUses'}}
4648
}
4749

48-
//--- function_signatures.swift
50+
//--- function_signatures_unqualified.swift
4951

50-
// FIXME: The access level is wrong on many of these fix-its.
5152
import Swift // Just here to anchor the fix-its
5253
// expected-note 2 {{add import of module 'InternalUsesOnly'}}{{1-1=internal import InternalUsesOnly\n}}
53-
// expected-note@-1 {{add import of module 'PackageUsesOnly'}}{{1-1=internal import PackageUsesOnly\n}}
54-
// expected-note@-2 {{add import of module 'PublicUsesOnly'}}{{1-1=internal import PublicUsesOnly\n}}
55-
// expected-note@-3 2 {{add import of module 'MixedUses'}}{{1-1=internal import MixedUses\n}}
54+
// expected-note@-1 {{add import of module 'PackageUsesOnly'}}{{1-1=package import PackageUsesOnly\n}}
55+
// expected-note@-2 {{add import of module 'PublicUsesOnly'}}{{1-1=public import PublicUsesOnly\n}}
56+
// expected-note@-3 2 {{add import of module 'MixedUses'}}{{1-1=public import MixedUses\n}}
5657

5758
extension Int {
5859
private func usesTypealiasInInternalUsesOnly_Private(x: TypealiasInInternalUsesOnly) {} // expected-error {{type alias 'TypealiasInInternalUsesOnly' is not available due to missing import of defining module 'InternalUsesOnly'}}
5960
internal func usesTypealiasInInternalUsesOnly(x: TypealiasInInternalUsesOnly) {} // expected-error {{type alias 'TypealiasInInternalUsesOnly' is not available due to missing import of defining module 'InternalUsesOnly'}}
6061
package func usesTypealiasInPackageUsesOnly(x: TypealiasInPackageUsesOnly) {} // expected-error {{type alias 'TypealiasInPackageUsesOnly' is not available due to missing import of defining module 'PackageUsesOnly'}}
6162
public func usesTypealiasInPublicUsesOnly(x: TypealiasInPublicUsesOnly) {} // expected-error {{type alias 'TypealiasInPublicUsesOnly' is not available due to missing import of defining module 'PublicUsesOnly'}}
63+
// expected-warning@-1 {{cannot use type alias 'TypealiasInPublicUsesOnly' here; 'PublicUsesOnly' was not imported by this file}}
6264
public func usesTypealiasInMixedUses(x: TypealiasInMixedUses) {} // expected-error {{type alias 'TypealiasInMixedUses' is not available due to missing import of defining module 'MixedUses'}}
65+
// expected-warning@-1 {{cannot use type alias 'TypealiasInMixedUses' here; 'MixedUses' was not imported by this file}}
6366
internal func usesTypealiasInMixedUses_Internal(x: TypealiasInMixedUses) {} // expected-error {{type alias 'TypealiasInMixedUses' is not available due to missing import of defining module 'MixedUses'}}
6467
}
6568

69+
//--- function_signatures_qualified.swift
70+
71+
import Swift // Just here to anchor the fix-its
72+
// expected-note 2 {{add import of module 'InternalUsesOnly'}}{{1-1=internal import InternalUsesOnly\n}}
73+
// expected-note@-1 {{add import of module 'PackageUsesOnly'}}{{1-1=package import PackageUsesOnly\n}}
74+
// expected-note@-2 {{add import of module 'PublicUsesOnly'}}{{1-1=public import PublicUsesOnly\n}}
75+
// expected-note@-3 2 {{add import of module 'MixedUses'}}{{1-1=public import MixedUses\n}}
76+
77+
private func usesTypealiasInInternalUsesOnly_Private(x: Int.TypealiasInInternalUsesOnly) {} // expected-error {{type alias 'TypealiasInInternalUsesOnly' is not available due to missing import of defining module 'InternalUsesOnly'}}
78+
internal func usesTypealiasInInternalUsesOnly(x: Int.TypealiasInInternalUsesOnly) {} // expected-error {{type alias 'TypealiasInInternalUsesOnly' is not available due to missing import of defining module 'InternalUsesOnly'}}
79+
package func usesTypealiasInPackageUsesOnly(x: Int.TypealiasInPackageUsesOnly) {} // expected-error {{type alias 'TypealiasInPackageUsesOnly' is not available due to missing import of defining module 'PackageUsesOnly'}}
80+
public func usesTypealiasInPublicUsesOnly(x: Int.TypealiasInPublicUsesOnly) {} // expected-error {{type alias 'TypealiasInPublicUsesOnly' is not available due to missing import of defining module 'PublicUsesOnly'}}
81+
// expected-warning@-1 {{cannot use type alias 'TypealiasInPublicUsesOnly' here; 'PublicUsesOnly' was not imported by this file}}
82+
public func usesTypealiasInMixedUses(x: Int.TypealiasInMixedUses) {} // expected-error {{type alias 'TypealiasInMixedUses' is not available due to missing import of defining module 'MixedUses'}}
83+
// expected-warning@-1 {{cannot use type alias 'TypealiasInMixedUses' here; 'MixedUses' was not imported by this file}}
84+
internal func usesTypealiasInMixedUses_Internal(x: Int.TypealiasInMixedUses) {} // expected-error {{type alias 'TypealiasInMixedUses' is not available due to missing import of defining module 'MixedUses'}}
85+
86+
//--- extensions.swift
87+
88+
import Swift // Just here to anchor the fix-its
89+
// expected-note 2 {{add import of module 'InternalUsesOnly'}}{{1-1=internal import InternalUsesOnly\n}}
90+
// expected-note@-1 {{add import of module 'PackageUsesOnly'}}{{1-1=package import PackageUsesOnly\n}}
91+
// expected-note@-2 {{add import of module 'PublicUsesOnly'}}{{1-1=public import PublicUsesOnly\n}}
92+
// expected-note@-3 2 {{add import of module 'MixedUses'}}{{1-1=public import MixedUses\n}}
93+
94+
extension Int.NestedInInternalUsesOnly { // expected-error {{struct 'NestedInInternalUsesOnly' is not available due to missing import of defining module 'InternalUsesOnly'}}
95+
private func privateMethod() {}
96+
}
97+
98+
extension Int.NestedInInternalUsesOnly { // expected-error {{struct 'NestedInInternalUsesOnly' is not available due to missing import of defining module 'InternalUsesOnly'}}
99+
internal func internalMethod() {}
100+
}
101+
102+
extension Int.NestedInPackageUsesOnly { // expected-error {{struct 'NestedInPackageUsesOnly' is not available due to missing import of defining module 'PackageUsesOnly'}}
103+
package func packageMethod() {}
104+
}
105+
106+
extension Int.NestedInPublicUsesOnly { // expected-error {{struct 'NestedInPublicUsesOnly' is not available due to missing import of defining module 'PublicUsesOnly'}}
107+
// expected-warning@-1 {{cannot use struct 'NestedInPublicUsesOnly' in an extension with public or '@usableFromInline' members; 'PublicUsesOnly' was not imported by this file}}
108+
public func publicMethod() {}
109+
}
110+
111+
extension Int.NestedInMixedUses { // expected-error {{struct 'NestedInMixedUses' is not available due to missing import of defining module 'MixedUses'}}
112+
// expected-warning@-1 {{cannot use struct 'NestedInMixedUses' in an extension with public or '@usableFromInline' members; 'MixedUses' was not imported by this file}}
113+
public func publicMethod() {}
114+
}
115+
116+
extension Int.NestedInMixedUses { // expected-error {{struct 'NestedInMixedUses' is not available due to missing import of defining module 'MixedUses'}}
117+
internal func internalMethod() {}
118+
}
119+
66120
//--- imports.swift
67121

68122
internal import InternalUsesOnly
@@ -77,48 +131,55 @@ internal import Exports
77131

78132
extension Int {
79133
public typealias TypealiasInInternalUsesOnly = Self
134+
public struct NestedInInternalUsesOnly {}
80135
public var memberInInternalUsesOnly: Int { return self }
81136
}
82137

83138
//--- InternalUsesOnlyDefaultedImport.swift
84139

85140
extension Int {
86141
public typealias TypealiasInInternalUsesOnlyDefaultedImport = Self
142+
public struct NestedInInternalUsesOnlyDefaultedImport {}
87143
public var memberInInternalUsesOnlyDefaultedImport: Int { return self }
88144
}
89145

90146
//--- PackageUsesOnly.swift
91147

92148
extension Int {
93149
public typealias TypealiasInPackageUsesOnly = Self
150+
public struct NestedInPackageUsesOnly {}
94151
public var memberInPackageUsesOnly: Int { return self }
95152
}
96153

97154
//--- PublicUsesOnly.swift
98155

99156
extension Int {
100157
public typealias TypealiasInPublicUsesOnly = Self
158+
public struct NestedInPublicUsesOnly {}
101159
public var memberInPublicUsesOnly: Int { return self }
102160
}
103161

104162
//--- PublicUsesOnlyDefaultedImport.swift
105163

106164
extension Int {
107165
public typealias TypealiasInPublicUsesOnlyDefaultedImport = Self
166+
public struct NestedInPublicUsesOnlyDefaultedImport {}
108167
public var memberInPublicUsesOnlyDefaultedImport: Int { return self }
109168
}
110169

111170
//--- MixedUses.swift
112171

113172
extension Int {
114173
public typealias TypealiasInMixedUses = Self
174+
public struct NestedInMixedUses {}
115175
public var memberInMixedUses: Int { return self }
116176
}
117177

118178
//--- InternalUsesOnlyTransitivelyImported.swift
119179

120180
extension Int {
121181
public typealias TypealiasInInternalUsesOnlyTransitivelyImported = Self
182+
public struct NestedInInternalUsesOnlyTransitivelyImported {}
122183
public var memberInInternalUsesOnlyTransitivelyImported: Int { return self }
123184
}
124185

0 commit comments

Comments
 (0)