Skip to content

Commit c08deca

Browse files
authored
Merge pull request #23949 from jrose-apple/5.1-conformance-conformance
[5.1] Implementation-only import checking for conformances
2 parents a2d1b4d + 6f9c0bf commit c08deca

14 files changed

+757
-121
lines changed

include/swift/AST/AccessScopeChecker.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -54,13 +54,13 @@ class TypeDeclFinder : public TypeWalker {
5454
Action walkToTypePre(Type T) override;
5555

5656
public:
57-
virtual Action visitNominalType(const NominalType *ty) {
57+
virtual Action visitNominalType(NominalType *ty) {
5858
return Action::Continue;
5959
}
60-
virtual Action visitBoundGenericType(const BoundGenericType *ty) {
60+
virtual Action visitBoundGenericType(BoundGenericType *ty) {
6161
return Action::Continue;
6262
}
63-
virtual Action visitTypeAliasType(const TypeAliasType *ty) {
63+
virtual Action visitTypeAliasType(TypeAliasType *ty) {
6464
return Action::Continue;
6565
}
6666
};
@@ -72,9 +72,9 @@ class SimpleTypeDeclFinder : public TypeDeclFinder {
7272
/// The function to call when a ComponentIdentTypeRepr is seen.
7373
llvm::function_ref<Action(const TypeDecl *)> Callback;
7474

75-
Action visitNominalType(const NominalType *ty) override;
76-
Action visitBoundGenericType(const BoundGenericType *ty) override;
77-
Action visitTypeAliasType(const TypeAliasType *ty) override;
75+
Action visitNominalType(NominalType *ty) override;
76+
Action visitBoundGenericType(BoundGenericType *ty) override;
77+
Action visitTypeAliasType(TypeAliasType *ty) override;
7878

7979
public:
8080
explicit SimpleTypeDeclFinder(

include/swift/AST/DiagnosticsSema.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2396,6 +2396,14 @@ ERROR(decl_from_implementation_only_module,none,
23962396
"cannot use %0 here; %1 has been imported as "
23972397
"'@_implementationOnly'",
23982398
(DeclName, Identifier))
2399+
ERROR(conformance_from_implementation_only_module,none,
2400+
"cannot use conformance of %0 to %1 here; %2 has been imported as "
2401+
"'@_implementationOnly'",
2402+
(Type, DeclName, Identifier))
2403+
ERROR(assoc_conformance_from_implementation_only_module,none,
2404+
"cannot use conformance of %0 to %1 in associated type %3 (inferred as "
2405+
"%4); %2 has been imported as '@_implementationOnly'",
2406+
(Type, DeclName, Identifier, Type, Type))
23992407

24002408
// Derived conformances
24012409
ERROR(cannot_synthesize_init_in_extension_of_nonfinal,none,

lib/AST/AccessScopeChecker.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,17 +71,17 @@ TypeWalker::Action TypeDeclFinder::walkToTypePre(Type T) {
7171
}
7272

7373
TypeWalker::Action
74-
SimpleTypeDeclFinder::visitNominalType(const NominalType *ty) {
74+
SimpleTypeDeclFinder::visitNominalType(NominalType *ty) {
7575
return Callback(ty->getDecl());
7676
}
7777

7878
TypeWalker::Action
79-
SimpleTypeDeclFinder::visitBoundGenericType(const BoundGenericType *ty) {
79+
SimpleTypeDeclFinder::visitBoundGenericType(BoundGenericType *ty) {
8080
return Callback(ty->getDecl());
8181
}
8282

8383
TypeWalker::Action
84-
SimpleTypeDeclFinder::visitTypeAliasType(const TypeAliasType *ty) {
84+
SimpleTypeDeclFinder::visitTypeAliasType(TypeAliasType *ty) {
8585
return Callback(ty->getDecl());
8686
}
8787

lib/Sema/ResilienceDiagnostics.cpp

Lines changed: 101 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,13 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "TypeChecker.h"
18+
#include "TypeCheckAvailability.h"
19+
#include "swift/AST/AccessScopeChecker.h"
1820
#include "swift/AST/Attr.h"
1921
#include "swift/AST/Decl.h"
20-
#include "swift/AST/Initializer.h"
2122
#include "swift/AST/DeclContext.h"
23+
#include "swift/AST/Initializer.h"
24+
#include "swift/AST/ProtocolConformance.h"
2225

2326
using namespace swift;
2427
using FragileFunctionKind = TypeChecker::FragileFunctionKind;
@@ -99,16 +102,13 @@ enum class DowngradeToWarning: bool {
99102
};
100103

101104
bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
102-
const ValueDecl *D,
105+
ConcreteDeclRef declRef,
103106
const DeclContext *DC,
104107
FragileFunctionKind Kind,
105108
bool TreatUsableFromInlineAsPublic) {
109+
const ValueDecl *D = declRef.getDecl();
106110
// Do some important fast-path checks that apply to all cases.
107111

108-
// Local declarations are OK.
109-
if (D->getDeclContext()->isLocalContext())
110-
return false;
111-
112112
// Type parameters are OK.
113113
if (isa<AbstractTypeParamDecl>(D))
114114
return false;
@@ -119,7 +119,7 @@ bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
119119
return true;
120120

121121
// Check whether the declaration comes from a publically-imported module.
122-
if (diagnoseDeclRefExportability(loc, D, DC))
122+
if (diagnoseDeclRefExportability(loc, declRef, DC))
123123
return true;
124124

125125
return false;
@@ -130,6 +130,10 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
130130
const DeclContext *DC,
131131
FragileFunctionKind Kind,
132132
bool TreatUsableFromInlineAsPublic) {
133+
// Local declarations are OK.
134+
if (D->getDeclContext()->isLocalContext())
135+
return false;
136+
133137
// Public declarations are OK.
134138
if (D->getFormalAccessScope(/*useDC=*/nullptr,
135139
TreatUsableFromInlineAsPublic).isPublic())
@@ -203,8 +207,89 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
203207
return (downgradeToWarning == DowngradeToWarning::No);
204208
}
205209

210+
static bool diagnoseDeclExportability(SourceLoc loc, const ValueDecl *D,
211+
const SourceFile &userSF) {
212+
auto definingModule = D->getModuleContext();
213+
if (!userSF.isImportedImplementationOnly(definingModule))
214+
return false;
215+
216+
// TODO: different diagnostics
217+
ASTContext &ctx = definingModule->getASTContext();
218+
ctx.Diags.diagnose(loc, diag::inlinable_decl_ref_implementation_only,
219+
D->getDescriptiveKind(), D->getFullName());
220+
return true;
221+
}
222+
223+
static bool
224+
diagnoseGenericArgumentsExportability(SourceLoc loc,
225+
const SubstitutionMap &subs,
226+
const SourceFile &userSF) {
227+
bool hadAnyIssues = false;
228+
for (ProtocolConformanceRef conformance : subs.getConformances()) {
229+
if (!conformance.isConcrete())
230+
continue;
231+
const ProtocolConformance *concreteConf = conformance.getConcrete();
232+
233+
SubstitutionMap subConformanceSubs =
234+
concreteConf->getSubstitutions(userSF.getParentModule());
235+
diagnoseGenericArgumentsExportability(loc, subConformanceSubs, userSF);
236+
237+
const RootProtocolConformance *rootConf =
238+
concreteConf->getRootConformance();
239+
ModuleDecl *M = rootConf->getDeclContext()->getParentModule();
240+
if (!userSF.isImportedImplementationOnly(M))
241+
continue;
242+
243+
ASTContext &ctx = M->getASTContext();
244+
ctx.Diags.diagnose(loc, diag::conformance_from_implementation_only_module,
245+
rootConf->getType(),
246+
rootConf->getProtocol()->getFullName(), M->getName());
247+
hadAnyIssues = true;
248+
}
249+
return hadAnyIssues;
250+
}
251+
252+
void TypeChecker::diagnoseGenericTypeExportability(const TypeLoc &TL,
253+
const DeclContext *DC) {
254+
class GenericTypeFinder : public TypeDeclFinder {
255+
using Callback = llvm::function_ref<void(SubstitutionMap)>;
256+
257+
const SourceFile &SF;
258+
Callback callback;
259+
public:
260+
GenericTypeFinder(const SourceFile &SF, Callback callback)
261+
: SF(SF), callback(callback) {}
262+
263+
Action visitBoundGenericType(BoundGenericType *ty) override {
264+
ModuleDecl *useModule = SF.getParentModule();
265+
SubstitutionMap subs = ty->getContextSubstitutionMap(useModule,
266+
ty->getDecl());
267+
callback(subs);
268+
return Action::Continue;
269+
}
270+
271+
Action visitTypeAliasType(TypeAliasType *ty) override {
272+
callback(ty->getSubstitutionMap());
273+
return Action::Continue;
274+
}
275+
};
276+
277+
assert(TL.getType() && "type not validated yet");
278+
279+
const SourceFile *SF = DC->getParentSourceFile();
280+
if (!SF)
281+
return;
282+
283+
TL.getType().walk(GenericTypeFinder(*SF, [&](SubstitutionMap subs) {
284+
// FIXME: It would be nice to highlight just the part of the type that's
285+
// problematic, but unfortunately the TypeRepr doesn't have the
286+
// information we need and the Type doesn't easily map back to it.
287+
(void)diagnoseGenericArgumentsExportability(TL.getLoc(), subs, *SF);
288+
}));
289+
}
290+
206291
bool TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
207-
const ValueDecl *D,
292+
ConcreteDeclRef declRef,
208293
const DeclContext *DC) {
209294
// We're only interested in diagnosing uses from source files.
210295
auto userSF = DC->getParentSourceFile();
@@ -219,22 +304,12 @@ bool TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
219304
if (!userSF->hasImplementationOnlyImports())
220305
return false;
221306

222-
auto userModule = userSF->getParentModule();
223-
auto definingModule = D->getModuleContext();
224-
225-
// Nothing to diagnose in the very common case of the same module.
226-
if (userModule == definingModule)
227-
return false;
228-
229-
// Nothing to diagnose in the very common case that the module is
230-
// imported for use in signatures.
231-
if (!userSF->isImportedImplementationOnly(definingModule))
232-
return false;
233-
234-
// TODO: different diagnostics
235-
diagnose(loc, diag::inlinable_decl_ref_implementation_only,
236-
D->getDescriptiveKind(), D->getFullName());
237-
238-
// TODO: notes explaining why
239-
return true;
307+
const ValueDecl *D = declRef.getDecl();
308+
if (diagnoseDeclExportability(loc, D, *userSF))
309+
return true;
310+
if (diagnoseGenericArgumentsExportability(loc, declRef.getSubstitutions(),
311+
*userSF)) {
312+
return true;
313+
}
314+
return false;
240315
}

0 commit comments

Comments
 (0)