Skip to content

Commit

Permalink
Merge pull request apple#23722 from jrose-apple/type-disadvantage
Browse files Browse the repository at this point in the history
Implementation-only import checking for types used in decls

(cherry picked from commit be48d64)
  • Loading branch information
jrose-apple committed Apr 8, 2019
1 parent b566dcc commit 0596283
Show file tree
Hide file tree
Showing 10 changed files with 776 additions and 124 deletions.
74 changes: 53 additions & 21 deletions include/swift/AST/AccessScopeChecker.h
Expand Up @@ -23,47 +23,79 @@

namespace swift {

class AbstractStorageDecl;
class ExtensionDecl;
class BoundGenericType;
class ComponentIdentTypeRepr;
class NominalType;
class SourceFile;
class ValueDecl;
class TypeAliasType;

class AccessScopeChecker {
const SourceFile *File;
bool TreatUsableFromInlineAsPublic;

protected:
ASTContext &Context;
Optional<AccessScope> Scope = AccessScope::getPublic();

AccessScopeChecker(const DeclContext *useDC,
bool treatUsableFromInlineAsPublic);
bool visitDecl(ValueDecl *VD);
};

class TypeReprAccessScopeChecker : private ASTWalker, AccessScopeChecker {
TypeReprAccessScopeChecker(const DeclContext *useDC,
bool treatUsableFromInlineAsPublic);

bool walkToTypeReprPre(TypeRepr *TR) override;
bool walkToTypeReprPost(TypeRepr *TR) override;
bool visitDecl(const ValueDecl *VD);

public:
static Optional<AccessScope>
getAccessScope(TypeRepr *TR, const DeclContext *useDC,
bool treatUsableFromInlineAsPublic = false);
static Optional<AccessScope>
getAccessScope(Type T, const DeclContext *useDC,
bool treatUsableFromInlineAsPublic = false);
};

class TypeAccessScopeChecker : private TypeWalker, AccessScopeChecker {
TypeAccessScopeChecker(const DeclContext *useDC,
bool treatUsableFromInlineAsPublic);
/// Walks a Type to find all NominalTypes, BoundGenericTypes, and
/// TypeAliasTypes.
class TypeDeclFinder : public TypeWalker {
Action walkToTypePre(Type T) override;

public:
virtual Action visitNominalType(const NominalType *ty) {
return Action::Continue;
}
virtual Action visitBoundGenericType(const BoundGenericType *ty) {
return Action::Continue;
}
virtual Action visitTypeAliasType(const TypeAliasType *ty) {
return Action::Continue;
}
};

Action walkToTypePre(Type T);
/// A TypeDeclFinder for use cases where all types should be treated
/// equivalently and where generic arguments can be walked to separately from
/// the generic type.
class SimpleTypeDeclFinder : public TypeDeclFinder {
/// The function to call when a ComponentIdentTypeRepr is seen.
llvm::function_ref<Action(const TypeDecl *)> Callback;

Action visitNominalType(const NominalType *ty) override;
Action visitBoundGenericType(const BoundGenericType *ty) override;
Action visitTypeAliasType(const TypeAliasType *ty) override;

public:
static Optional<AccessScope>
getAccessScope(Type T, const DeclContext *useDC,
bool treatUsableFromInlineAsPublic = false);
explicit SimpleTypeDeclFinder(
llvm::function_ref<Action(const TypeDecl *)> callback)
: Callback(callback) {}
};

/// Walks a TypeRepr to find all ComponentIdentTypeReprs with bound TypeDecls.
///
/// Subclasses can either override #visitTypeDecl if they only care about
/// types on their own, or #visitComponentIdentTypeRepr if they want to keep
/// the TypeRepr around.
class TypeReprIdentFinder : public ASTWalker {
/// The function to call when a ComponentIdentTypeRepr is seen.
llvm::function_ref<bool(const ComponentIdentTypeRepr *)> Callback;

bool walkToTypeReprPost(TypeRepr *TR) override;
public:
explicit TypeReprIdentFinder(
llvm::function_ref<bool(const ComponentIdentTypeRepr *)> callback)
: Callback(callback) {}
};

}
Expand Down
5 changes: 5 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Expand Up @@ -2397,6 +2397,11 @@ NOTE(enum_raw_value_incrementing_from_zero,none,
NOTE(construct_raw_representable_from_unwrapped_value,none,
"construct %0 from unwrapped %1 value", (Type, Type))

ERROR(decl_from_implementation_only_module,none,
"cannot use %0 here; %1 has been imported as "
"'@_implementationOnly'",
(DeclName, Identifier))

// Derived conformances
ERROR(cannot_synthesize_init_in_extension_of_nonfinal,none,
"implementation of %0 for non-final class cannot be automatically "
Expand Down
90 changes: 49 additions & 41 deletions lib/AST/AccessScopeChecker.cpp
Expand Up @@ -24,68 +24,76 @@ using namespace swift;
AccessScopeChecker::AccessScopeChecker(const DeclContext *useDC,
bool treatUsableFromInlineAsPublic)
: File(useDC->getParentSourceFile()),
TreatUsableFromInlineAsPublic(treatUsableFromInlineAsPublic),
Context(File->getASTContext()) {}
TreatUsableFromInlineAsPublic(treatUsableFromInlineAsPublic) {}

bool
AccessScopeChecker::visitDecl(ValueDecl *VD) {
if (!VD || isa<GenericTypeParamDecl>(VD))
AccessScopeChecker::visitDecl(const ValueDecl *VD) {
if (isa<GenericTypeParamDecl>(VD))
return true;

auto AS = VD->getFormalAccessScope(File, TreatUsableFromInlineAsPublic);
Scope = Scope->intersectWith(AS);
return Scope.hasValue();
}

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

bool
TypeReprAccessScopeChecker::walkToTypeReprPre(TypeRepr *TR) {
if (auto CITR = dyn_cast<ComponentIdentTypeRepr>(TR))
return visitDecl(CITR->getBoundDecl());
return true;
Optional<AccessScope>
AccessScopeChecker::getAccessScope(TypeRepr *TR, const DeclContext *useDC,
bool treatUsableFromInlineAsPublic) {
AccessScopeChecker checker(useDC, treatUsableFromInlineAsPublic);
TR->walk(TypeReprIdentFinder([&](const ComponentIdentTypeRepr *typeRepr) {
return checker.visitDecl(typeRepr->getBoundDecl());
}));
return checker.Scope;
}

bool
TypeReprAccessScopeChecker::walkToTypeReprPost(TypeRepr *TR) {
return Scope.hasValue();
}
TypeWalker::Action TypeDeclFinder::walkToTypePre(Type T) {
if (auto *TAT = dyn_cast<TypeAliasType>(T.getPointer()))
return visitTypeAliasType(TAT);

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

return Action::Continue;
}

TypeAccessScopeChecker::TypeAccessScopeChecker(const DeclContext *useDC,
bool treatUsableFromInlineAsPublic)
: AccessScopeChecker(useDC, treatUsableFromInlineAsPublic) {}
TypeWalker::Action
SimpleTypeDeclFinder::visitNominalType(const NominalType *ty) {
return Callback(ty->getDecl());
}

TypeWalker::Action
TypeAccessScopeChecker::walkToTypePre(Type T) {
ValueDecl *VD;
if (auto *BNAD = dyn_cast<TypeAliasType>(T.getPointer()))
VD = BNAD->getDecl();
else if (auto *NTD = T->getAnyNominal())
VD = NTD;
else
VD = nullptr;

if (!visitDecl(VD))
return Action::Stop;
SimpleTypeDeclFinder::visitBoundGenericType(const BoundGenericType *ty) {
return Callback(ty->getDecl());
}

return Action::Continue;
TypeWalker::Action
SimpleTypeDeclFinder::visitTypeAliasType(const TypeAliasType *ty) {
return Callback(ty->getDecl());
}


Optional<AccessScope>
TypeAccessScopeChecker::getAccessScope(Type T, const DeclContext *useDC,
bool treatUsableFromInlineAsPublic) {
TypeAccessScopeChecker checker(useDC, treatUsableFromInlineAsPublic);
T.walk(checker);
AccessScopeChecker::getAccessScope(Type T, const DeclContext *useDC,
bool treatUsableFromInlineAsPublic) {
AccessScopeChecker checker(useDC, treatUsableFromInlineAsPublic);
T.walk(SimpleTypeDeclFinder([&](const ValueDecl *VD) {
if (checker.visitDecl(VD))
return TypeWalker::Action::Continue;
return TypeWalker::Action::Stop;
}));
return checker.Scope;
}

0 comments on commit 0596283

Please sign in to comment.