15
15
// ===----------------------------------------------------------------------===//
16
16
17
17
#include " TypeChecker.h"
18
+ #include " TypeCheckAvailability.h"
19
+ #include " swift/AST/AccessScopeChecker.h"
18
20
#include " swift/AST/Attr.h"
19
21
#include " swift/AST/Decl.h"
20
- #include " swift/AST/Initializer.h"
21
22
#include " swift/AST/DeclContext.h"
23
+ #include " swift/AST/Initializer.h"
24
+ #include " swift/AST/ProtocolConformance.h"
22
25
23
26
using namespace swift ;
24
27
using FragileFunctionKind = TypeChecker::FragileFunctionKind;
@@ -99,16 +102,13 @@ enum class DowngradeToWarning: bool {
99
102
};
100
103
101
104
bool TypeChecker::diagnoseInlinableDeclRef (SourceLoc loc,
102
- const ValueDecl *D ,
105
+ ConcreteDeclRef declRef ,
103
106
const DeclContext *DC,
104
107
FragileFunctionKind Kind,
105
108
bool TreatUsableFromInlineAsPublic) {
109
+ const ValueDecl *D = declRef.getDecl ();
106
110
// Do some important fast-path checks that apply to all cases.
107
111
108
- // Local declarations are OK.
109
- if (D->getDeclContext ()->isLocalContext ())
110
- return false ;
111
-
112
112
// Type parameters are OK.
113
113
if (isa<AbstractTypeParamDecl>(D))
114
114
return false ;
@@ -119,7 +119,7 @@ bool TypeChecker::diagnoseInlinableDeclRef(SourceLoc loc,
119
119
return true ;
120
120
121
121
// Check whether the declaration comes from a publically-imported module.
122
- if (diagnoseDeclRefExportability (loc, D , DC))
122
+ if (diagnoseDeclRefExportability (loc, declRef , DC))
123
123
return true ;
124
124
125
125
return false ;
@@ -130,6 +130,10 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
130
130
const DeclContext *DC,
131
131
FragileFunctionKind Kind,
132
132
bool TreatUsableFromInlineAsPublic) {
133
+ // Local declarations are OK.
134
+ if (D->getDeclContext ()->isLocalContext ())
135
+ return false ;
136
+
133
137
// Public declarations are OK.
134
138
if (D->getFormalAccessScope (/* useDC=*/ nullptr ,
135
139
TreatUsableFromInlineAsPublic).isPublic ())
@@ -203,8 +207,89 @@ bool TypeChecker::diagnoseInlinableDeclRefAccess(SourceLoc loc,
203
207
return (downgradeToWarning == DowngradeToWarning::No);
204
208
}
205
209
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
+
206
291
bool TypeChecker::diagnoseDeclRefExportability (SourceLoc loc,
207
- const ValueDecl *D ,
292
+ ConcreteDeclRef declRef ,
208
293
const DeclContext *DC) {
209
294
// We're only interested in diagnosing uses from source files.
210
295
auto userSF = DC->getParentSourceFile ();
@@ -219,22 +304,12 @@ bool TypeChecker::diagnoseDeclRefExportability(SourceLoc loc,
219
304
if (!userSF->hasImplementationOnlyImports ())
220
305
return false ;
221
306
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 ;
240
315
}
0 commit comments