18
18
#include " ConstraintSystem.h"
19
19
#include " DerivedConformances.h"
20
20
#include " MiscDiagnostics.h"
21
- #include " TypeChecker.h"
22
21
#include " TypeCheckAvailability.h"
23
22
#include " swift/Basic/SourceManager.h"
24
23
#include " swift/Basic/StringExtras.h"
@@ -1233,23 +1232,51 @@ bool WitnessChecker::findBestWitness(
1233
1232
return isReallyBest;
1234
1233
}
1235
1234
1236
- bool WitnessChecker::checkWitnessAccess (AccessScope &requiredAccessScope,
1237
- ValueDecl *requirement,
1235
+ AccessScope WitnessChecker::getRequiredAccessScope () {
1236
+ if (RequiredAccessScopeAndUsableFromInline.hasValue ())
1237
+ return RequiredAccessScopeAndUsableFromInline.getValue ().first ;
1238
+
1239
+ AccessScope result = Proto->getFormalAccessScope (DC);
1240
+
1241
+ bool witnessesMustBeUsableFromInline = false ;
1242
+ if (Adoptee) {
1243
+ const NominalTypeDecl *adoptingNominal = Adoptee->getAnyNominal ();
1244
+
1245
+ // Compute the intersection of the conforming type's access scope
1246
+ // and the protocol's access scope.
1247
+ auto scopeIntersection =
1248
+ result.intersectWith (adoptingNominal->getFormalAccessScope (DC));
1249
+ assert (scopeIntersection.hasValue ());
1250
+ result = scopeIntersection.getValue ();
1251
+
1252
+ if (!result.isPublic ()) {
1253
+ witnessesMustBeUsableFromInline =
1254
+ Proto->getFormalAccessScope (
1255
+ DC, /* usableFromInlineAsPublic*/ true ).isPublic () &&
1256
+ adoptingNominal->getFormalAccessScope (
1257
+ DC, /* usableFromInlineAsPublic*/ true ).isPublic ();
1258
+ }
1259
+ } else {
1260
+ if (!result.isPublic ()) {
1261
+ witnessesMustBeUsableFromInline =
1262
+ Proto->getFormalAccessScope (
1263
+ DC, /* usableFromInlineAsPublic*/ true ).isPublic ();
1264
+ }
1265
+ }
1266
+
1267
+ RequiredAccessScopeAndUsableFromInline =
1268
+ std::make_pair (result, witnessesMustBeUsableFromInline);
1269
+ return result;
1270
+ }
1271
+
1272
+ bool WitnessChecker::checkWitnessAccess (ValueDecl *requirement,
1238
1273
ValueDecl *witness,
1239
1274
bool *isSetter) {
1240
1275
*isSetter = false ;
1241
1276
if (!TC.getLangOpts ().EnableAccessControl )
1242
1277
return false ;
1243
1278
1244
- // Compute the intersection of the conforming type's access scope
1245
- // and the protocol's access scope.
1246
- auto scopeIntersection =
1247
- requiredAccessScope.intersectWith (Proto->getFormalAccessScope (DC));
1248
- assert (scopeIntersection.hasValue ());
1249
-
1250
- requiredAccessScope = *scopeIntersection;
1251
-
1252
- AccessScope actualScopeToCheck = requiredAccessScope;
1279
+ AccessScope actualScopeToCheck = getRequiredAccessScope ();
1253
1280
1254
1281
// Setting the 'forConformance' flag means that we admit witnesses in
1255
1282
// protocol extensions that we can see, but are not necessarily as
@@ -1270,7 +1297,7 @@ bool WitnessChecker::checkWitnessAccess(AccessScope &requiredAccessScope,
1270
1297
}
1271
1298
}
1272
1299
1273
- if (actualScopeToCheck.hasEqualDeclContextWith (requiredAccessScope ))
1300
+ if (actualScopeToCheck.hasEqualDeclContextWith (getRequiredAccessScope () ))
1274
1301
return true ;
1275
1302
}
1276
1303
@@ -1297,20 +1324,17 @@ checkWitnessAvailability(ValueDecl *requirement,
1297
1324
DC, *requiredAvailability));
1298
1325
}
1299
1326
1300
- RequirementCheck WitnessChecker::
1301
- checkWitness (AccessScope requiredAccessScope,
1302
- ValueDecl *requirement,
1303
- const RequirementMatch &match) {
1327
+ RequirementCheck WitnessChecker::checkWitness (ValueDecl *requirement,
1328
+ const RequirementMatch &match) {
1304
1329
if (!match.OptionalAdjustments .empty ())
1305
1330
return CheckKind::OptionalityConflict;
1306
1331
1307
1332
bool isSetter = false ;
1308
- if (checkWitnessAccess (requiredAccessScope, requirement, match.Witness ,
1309
- &isSetter)) {
1333
+ if (checkWitnessAccess (requirement, match.Witness , &isSetter)) {
1310
1334
CheckKind kind = (isSetter
1311
1335
? CheckKind::AccessOfSetter
1312
1336
: CheckKind::Access);
1313
- return RequirementCheck (kind, requiredAccessScope );
1337
+ return RequirementCheck (kind, getRequiredAccessScope () );
1314
1338
}
1315
1339
1316
1340
auto requiredAvailability = AvailabilityContext::alwaysAvailable ();
@@ -2340,6 +2364,36 @@ bool ConformanceChecker::checkObjCTypeErasedGenerics(
2340
2364
return true ;
2341
2365
}
2342
2366
2367
+ namespace {
2368
+ // / Helper class for use with ConformanceChecker::diagnoseOrDefer when a witness
2369
+ // / needs to be marked as '\@usableFromInline'.
2370
+ class DiagnoseUsableFromInline {
2371
+ const ValueDecl *witness;
2372
+
2373
+ public:
2374
+ explicit DiagnoseUsableFromInline (const ValueDecl *witness)
2375
+ : witness(witness) {
2376
+ assert (witness);
2377
+ }
2378
+
2379
+ void operator ()(const NormalProtocolConformance *conformance) {
2380
+ auto proto = conformance->getProtocol ();
2381
+ ASTContext &ctx = proto->getASTContext ();
2382
+
2383
+ auto diagID = diag::witness_not_usable_from_inline;
2384
+ if (!ctx.isSwiftVersionAtLeast (5 ))
2385
+ diagID = diag::witness_not_usable_from_inline_warn;
2386
+
2387
+ SourceLoc diagLoc = getLocForDiagnosingWitness (conformance, witness);
2388
+ ctx.Diags .diagnose (diagLoc, diagID,
2389
+ witness->getDescriptiveKind (),
2390
+ witness->getFullName (),
2391
+ proto->getName ());
2392
+ emitDeclaredHereIfNeeded (ctx.Diags , diagLoc, witness);
2393
+ }
2394
+ };
2395
+ }
2396
+
2343
2397
void ConformanceChecker::recordTypeWitness (AssociatedTypeDecl *assocType,
2344
2398
Type type,
2345
2399
TypeDecl *typeDecl) {
@@ -2357,24 +2411,20 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
2357
2411
2358
2412
if (typeDecl) {
2359
2413
// Check access.
2360
- AccessScope requiredAccessScope =
2361
- Adoptee->getAnyNominal ()->getFormalAccessScope (DC);
2362
2414
bool isSetter = false ;
2363
- if (checkWitnessAccess (requiredAccessScope, assocType, typeDecl,
2364
- &isSetter)) {
2415
+ if (checkWitnessAccess (assocType, typeDecl, &isSetter)) {
2365
2416
assert (!isSetter);
2366
2417
2367
2418
// Avoid relying on the lifetime of 'this'.
2368
2419
const DeclContext *DC = this ->DC ;
2369
2420
diagnoseOrDefer (assocType, false ,
2370
- [DC, typeDecl, requiredAccessScope](
2371
- NormalProtocolConformance *conformance) {
2421
+ [this , DC, typeDecl](NormalProtocolConformance *conformance) {
2372
2422
AccessLevel requiredAccess =
2373
- requiredAccessScope .requiredAccessForDiagnostics ();
2423
+ getRequiredAccessScope () .requiredAccessForDiagnostics ();
2374
2424
auto proto = conformance->getProtocol ();
2375
2425
auto protoAccessScope = proto->getFormalAccessScope (DC);
2376
2426
bool protoForcesAccess =
2377
- requiredAccessScope .hasEqualDeclContextWith (protoAccessScope);
2427
+ getRequiredAccessScope () .hasEqualDeclContextWith (protoAccessScope);
2378
2428
auto diagKind = protoForcesAccess
2379
2429
? diag::type_witness_not_accessible_proto
2380
2430
: diag::type_witness_not_accessible_type;
@@ -2391,6 +2441,13 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
2391
2441
fixItAccess (fixItDiag, typeDecl, requiredAccess);
2392
2442
});
2393
2443
}
2444
+
2445
+ if (isUsableFromInlineRequired ()) {
2446
+ bool witnessIsUsableFromInline = typeDecl->getFormalAccessScope (
2447
+ DC, /* usableFromInlineAsPublic*/ true ).isPublic ();
2448
+ if (!witnessIsUsableFromInline)
2449
+ diagnoseOrDefer (assocType, false , DiagnoseUsableFromInline (typeDecl));
2450
+ }
2394
2451
} else {
2395
2452
// If there was no type declaration, synthesize one.
2396
2453
auto aliasDecl = new (TC.Context ) TypeAliasDecl (SourceLoc (),
@@ -2939,8 +2996,7 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2939
2996
});
2940
2997
}
2941
2998
2942
- auto nominalAccessScope = nominal->getFormalAccessScope (DC);
2943
- auto check = checkWitness (nominalAccessScope, requirement, best);
2999
+ auto check = checkWitness (requirement, best);
2944
3000
2945
3001
switch (check.Kind ) {
2946
3002
case CheckKind::Success:
@@ -5422,7 +5478,7 @@ DefaultWitnessChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
5422
5478
5423
5479
// Perform the same checks as conformance witness matching, but silently
5424
5480
// ignore the candidate instead of diagnosing anything.
5425
- auto check = checkWitness (AccessScope::getPublic (), requirement, best);
5481
+ auto check = checkWitness (requirement, best);
5426
5482
if (check.Kind != CheckKind::Success)
5427
5483
return ResolveWitnessResult::ExplicitFailed;
5428
5484
0 commit comments