Skip to content

Commit 0596283

Browse files
committed
Merge pull request #23722 from jrose-apple/type-disadvantage
Implementation-only import checking for types used in decls (cherry picked from commit be48d64)
1 parent b566dcc commit 0596283

10 files changed

+776
-124
lines changed

include/swift/AST/AccessScopeChecker.h

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,47 +23,79 @@
2323

2424
namespace swift {
2525

26-
class AbstractStorageDecl;
27-
class ExtensionDecl;
26+
class BoundGenericType;
27+
class ComponentIdentTypeRepr;
28+
class NominalType;
2829
class SourceFile;
29-
class ValueDecl;
30+
class TypeAliasType;
3031

3132
class AccessScopeChecker {
3233
const SourceFile *File;
3334
bool TreatUsableFromInlineAsPublic;
3435

35-
protected:
36-
ASTContext &Context;
3736
Optional<AccessScope> Scope = AccessScope::getPublic();
3837

3938
AccessScopeChecker(const DeclContext *useDC,
4039
bool treatUsableFromInlineAsPublic);
41-
bool visitDecl(ValueDecl *VD);
42-
};
43-
44-
class TypeReprAccessScopeChecker : private ASTWalker, AccessScopeChecker {
45-
TypeReprAccessScopeChecker(const DeclContext *useDC,
46-
bool treatUsableFromInlineAsPublic);
47-
48-
bool walkToTypeReprPre(TypeRepr *TR) override;
49-
bool walkToTypeReprPost(TypeRepr *TR) override;
40+
bool visitDecl(const ValueDecl *VD);
5041

5142
public:
5243
static Optional<AccessScope>
5344
getAccessScope(TypeRepr *TR, const DeclContext *useDC,
5445
bool treatUsableFromInlineAsPublic = false);
46+
static Optional<AccessScope>
47+
getAccessScope(Type T, const DeclContext *useDC,
48+
bool treatUsableFromInlineAsPublic = false);
5549
};
5650

57-
class TypeAccessScopeChecker : private TypeWalker, AccessScopeChecker {
58-
TypeAccessScopeChecker(const DeclContext *useDC,
59-
bool treatUsableFromInlineAsPublic);
51+
/// Walks a Type to find all NominalTypes, BoundGenericTypes, and
52+
/// TypeAliasTypes.
53+
class TypeDeclFinder : public TypeWalker {
54+
Action walkToTypePre(Type T) override;
55+
56+
public:
57+
virtual Action visitNominalType(const NominalType *ty) {
58+
return Action::Continue;
59+
}
60+
virtual Action visitBoundGenericType(const BoundGenericType *ty) {
61+
return Action::Continue;
62+
}
63+
virtual Action visitTypeAliasType(const TypeAliasType *ty) {
64+
return Action::Continue;
65+
}
66+
};
6067

61-
Action walkToTypePre(Type T);
68+
/// A TypeDeclFinder for use cases where all types should be treated
69+
/// equivalently and where generic arguments can be walked to separately from
70+
/// the generic type.
71+
class SimpleTypeDeclFinder : public TypeDeclFinder {
72+
/// The function to call when a ComponentIdentTypeRepr is seen.
73+
llvm::function_ref<Action(const TypeDecl *)> Callback;
74+
75+
Action visitNominalType(const NominalType *ty) override;
76+
Action visitBoundGenericType(const BoundGenericType *ty) override;
77+
Action visitTypeAliasType(const TypeAliasType *ty) override;
6278

6379
public:
64-
static Optional<AccessScope>
65-
getAccessScope(Type T, const DeclContext *useDC,
66-
bool treatUsableFromInlineAsPublic = false);
80+
explicit SimpleTypeDeclFinder(
81+
llvm::function_ref<Action(const TypeDecl *)> callback)
82+
: Callback(callback) {}
83+
};
84+
85+
/// Walks a TypeRepr to find all ComponentIdentTypeReprs with bound TypeDecls.
86+
///
87+
/// Subclasses can either override #visitTypeDecl if they only care about
88+
/// types on their own, or #visitComponentIdentTypeRepr if they want to keep
89+
/// the TypeRepr around.
90+
class TypeReprIdentFinder : public ASTWalker {
91+
/// The function to call when a ComponentIdentTypeRepr is seen.
92+
llvm::function_ref<bool(const ComponentIdentTypeRepr *)> Callback;
93+
94+
bool walkToTypeReprPost(TypeRepr *TR) override;
95+
public:
96+
explicit TypeReprIdentFinder(
97+
llvm::function_ref<bool(const ComponentIdentTypeRepr *)> callback)
98+
: Callback(callback) {}
6799
};
68100

69101
}

include/swift/AST/DiagnosticsSema.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2397,6 +2397,11 @@ NOTE(enum_raw_value_incrementing_from_zero,none,
23972397
NOTE(construct_raw_representable_from_unwrapped_value,none,
23982398
"construct %0 from unwrapped %1 value", (Type, Type))
23992399

2400+
ERROR(decl_from_implementation_only_module,none,
2401+
"cannot use %0 here; %1 has been imported as "
2402+
"'@_implementationOnly'",
2403+
(DeclName, Identifier))
2404+
24002405
// Derived conformances
24012406
ERROR(cannot_synthesize_init_in_extension_of_nonfinal,none,
24022407
"implementation of %0 for non-final class cannot be automatically "

lib/AST/AccessScopeChecker.cpp

Lines changed: 49 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -24,68 +24,76 @@ using namespace swift;
2424
AccessScopeChecker::AccessScopeChecker(const DeclContext *useDC,
2525
bool treatUsableFromInlineAsPublic)
2626
: File(useDC->getParentSourceFile()),
27-
TreatUsableFromInlineAsPublic(treatUsableFromInlineAsPublic),
28-
Context(File->getASTContext()) {}
27+
TreatUsableFromInlineAsPublic(treatUsableFromInlineAsPublic) {}
2928

3029
bool
31-
AccessScopeChecker::visitDecl(ValueDecl *VD) {
32-
if (!VD || isa<GenericTypeParamDecl>(VD))
30+
AccessScopeChecker::visitDecl(const ValueDecl *VD) {
31+
if (isa<GenericTypeParamDecl>(VD))
3332
return true;
3433

3534
auto AS = VD->getFormalAccessScope(File, TreatUsableFromInlineAsPublic);
3635
Scope = Scope->intersectWith(AS);
3736
return Scope.hasValue();
3837
}
3938

40-
TypeReprAccessScopeChecker::TypeReprAccessScopeChecker(const DeclContext *useDC,
41-
bool treatUsableFromInlineAsPublic)
42-
: AccessScopeChecker(useDC, treatUsableFromInlineAsPublic) {
39+
bool TypeReprIdentFinder::walkToTypeReprPost(TypeRepr *TR) {
40+
auto CITR = dyn_cast<ComponentIdentTypeRepr>(TR);
41+
if (!CITR || !CITR->getBoundDecl())
42+
return true;
43+
return Callback(CITR);
4344
}
4445

45-
bool
46-
TypeReprAccessScopeChecker::walkToTypeReprPre(TypeRepr *TR) {
47-
if (auto CITR = dyn_cast<ComponentIdentTypeRepr>(TR))
48-
return visitDecl(CITR->getBoundDecl());
49-
return true;
46+
Optional<AccessScope>
47+
AccessScopeChecker::getAccessScope(TypeRepr *TR, const DeclContext *useDC,
48+
bool treatUsableFromInlineAsPublic) {
49+
AccessScopeChecker checker(useDC, treatUsableFromInlineAsPublic);
50+
TR->walk(TypeReprIdentFinder([&](const ComponentIdentTypeRepr *typeRepr) {
51+
return checker.visitDecl(typeRepr->getBoundDecl());
52+
}));
53+
return checker.Scope;
5054
}
5155

52-
bool
53-
TypeReprAccessScopeChecker::walkToTypeReprPost(TypeRepr *TR) {
54-
return Scope.hasValue();
55-
}
56+
TypeWalker::Action TypeDeclFinder::walkToTypePre(Type T) {
57+
if (auto *TAT = dyn_cast<TypeAliasType>(T.getPointer()))
58+
return visitTypeAliasType(TAT);
5659

57-
Optional<AccessScope>
58-
TypeReprAccessScopeChecker::getAccessScope(TypeRepr *TR, const DeclContext *useDC,
59-
bool treatUsableFromInlineAsPublic) {
60-
TypeReprAccessScopeChecker checker(useDC, treatUsableFromInlineAsPublic);
61-
TR->walk(checker);
62-
return checker.Scope;
60+
// FIXME: We're looking through sugar here so that we visit, e.g.,
61+
// Swift.Array when we see `[Int]`. But that means we do redundant work when
62+
// we see sugar that's purely structural, like `(Int)`. Fortunately, paren
63+
// types are the only such purely structural sugar at the time this comment
64+
// was written, and they're not so common in the first place.
65+
if (auto *BGT = T->getAs<BoundGenericType>())
66+
return visitBoundGenericType(BGT);
67+
if (auto *NT = T->getAs<NominalType>())
68+
return visitNominalType(NT);
69+
70+
return Action::Continue;
6371
}
6472

65-
TypeAccessScopeChecker::TypeAccessScopeChecker(const DeclContext *useDC,
66-
bool treatUsableFromInlineAsPublic)
67-
: AccessScopeChecker(useDC, treatUsableFromInlineAsPublic) {}
73+
TypeWalker::Action
74+
SimpleTypeDeclFinder::visitNominalType(const NominalType *ty) {
75+
return Callback(ty->getDecl());
76+
}
6877

6978
TypeWalker::Action
70-
TypeAccessScopeChecker::walkToTypePre(Type T) {
71-
ValueDecl *VD;
72-
if (auto *BNAD = dyn_cast<TypeAliasType>(T.getPointer()))
73-
VD = BNAD->getDecl();
74-
else if (auto *NTD = T->getAnyNominal())
75-
VD = NTD;
76-
else
77-
VD = nullptr;
78-
79-
if (!visitDecl(VD))
80-
return Action::Stop;
79+
SimpleTypeDeclFinder::visitBoundGenericType(const BoundGenericType *ty) {
80+
return Callback(ty->getDecl());
81+
}
8182

82-
return Action::Continue;
83+
TypeWalker::Action
84+
SimpleTypeDeclFinder::visitTypeAliasType(const TypeAliasType *ty) {
85+
return Callback(ty->getDecl());
8386
}
8487

88+
8589
Optional<AccessScope>
86-
TypeAccessScopeChecker::getAccessScope(Type T, const DeclContext *useDC,
87-
bool treatUsableFromInlineAsPublic) {
88-
TypeAccessScopeChecker checker(useDC, treatUsableFromInlineAsPublic);
89-
T.walk(checker);
90+
AccessScopeChecker::getAccessScope(Type T, const DeclContext *useDC,
91+
bool treatUsableFromInlineAsPublic) {
92+
AccessScopeChecker checker(useDC, treatUsableFromInlineAsPublic);
93+
T.walk(SimpleTypeDeclFinder([&](const ValueDecl *VD) {
94+
if (checker.visitDecl(VD))
95+
return TypeWalker::Action::Continue;
96+
return TypeWalker::Action::Stop;
97+
}));
9098
return checker.Scope;
9199
}

0 commit comments

Comments
 (0)