@@ -68,7 +68,7 @@ namespace {
68
68
unsigned &bestIdx,
69
69
bool &doNotDiagnoseMatches);
70
70
71
- bool checkWitnessAccessibility (Accessibility *requiredAccess ,
71
+ bool checkWitnessAccessibility (const DeclContext *&requiredAccessScope ,
72
72
ValueDecl *requirement,
73
73
ValueDecl *witness,
74
74
bool *isSetter);
@@ -77,7 +77,7 @@ namespace {
77
77
ValueDecl *witness,
78
78
AvailabilityContext *requirementInfo);
79
79
80
- RequirementCheck checkWitness (Accessibility requiredAccess ,
80
+ RequirementCheck checkWitness (const DeclContext *requiredAccessScope ,
81
81
ValueDecl *requirement,
82
82
RequirementMatch match);
83
83
};
@@ -392,24 +392,24 @@ namespace {
392
392
struct RequirementCheck {
393
393
CheckKind Kind;
394
394
395
- // / The required accessibility , if the check failed due to the
395
+ // / The required access scope , if the check failed due to the
396
396
// / witness being less accessible than the requirement.
397
- Accessibility RequiredAccess ;
397
+ const DeclContext *RequiredAccessScope ;
398
398
399
399
// / The required availability, if the check failed due to the
400
400
// / witness being less available than the requirement.
401
401
AvailabilityContext RequiredAvailability;
402
402
403
403
RequirementCheck (CheckKind kind)
404
- : Kind(kind), RequiredAccess(Accessibility::Public ),
404
+ : Kind(kind), RequiredAccessScope( nullptr ),
405
405
RequiredAvailability (AvailabilityContext::alwaysAvailable()) { }
406
406
407
- RequirementCheck (CheckKind kind, Accessibility requiredAccess )
408
- : Kind(kind), RequiredAccess(requiredAccess ),
407
+ RequirementCheck (CheckKind kind, const DeclContext *requiredAccessScope )
408
+ : Kind(kind), RequiredAccessScope(requiredAccessScope ),
409
409
RequiredAvailability(AvailabilityContext::alwaysAvailable()) { }
410
410
411
411
RequirementCheck (CheckKind kind, AvailabilityContext requiredAvailability)
412
- : Kind(kind), RequiredAccess(Accessibility::Public ),
412
+ : Kind(kind), RequiredAccessScope( nullptr ),
413
413
RequiredAvailability(requiredAvailability) { }
414
414
};
415
415
}
@@ -1218,48 +1218,35 @@ bool WitnessChecker::findBestWitness(ValueDecl *requirement,
1218
1218
}
1219
1219
1220
1220
bool WitnessChecker::
1221
- checkWitnessAccessibility (Accessibility *requiredAccess ,
1221
+ checkWitnessAccessibility (const DeclContext *&requiredAccessScope ,
1222
1222
ValueDecl *requirement,
1223
1223
ValueDecl *witness,
1224
1224
bool *isSetter) {
1225
1225
*isSetter = false ;
1226
1226
1227
- *requiredAccess = std::min (Proto->getFormalAccess (), *requiredAccess);
1228
- if (TC.getLangOpts ().EnableSwift3Private )
1229
- *requiredAccess = std::max (*requiredAccess, Accessibility::FilePrivate);
1227
+ const DeclContext *protoAccessScope = Proto->getFormalAccessScope (DC);
1230
1228
1231
- Accessibility witnessAccess = witness->getFormalAccess (DC);
1232
-
1233
- // Leave a hole for old-style top-level operators to be declared 'private' for
1234
- // a fileprivate conformance.
1235
- if (witnessAccess == Accessibility::Private &&
1236
- witness->getDeclContext ()->isModuleScopeContext ()) {
1237
- witnessAccess = Accessibility::FilePrivate;
1229
+ // FIXME: This is the same operation as TypeCheckDecl.cpp's
1230
+ // TypeAccessScopeChecker::intersectAccess.
1231
+ if (!requiredAccessScope) {
1232
+ requiredAccessScope = protoAccessScope;
1233
+ } else if (protoAccessScope) {
1234
+ if (protoAccessScope->isChildContextOf (requiredAccessScope)) {
1235
+ requiredAccessScope = protoAccessScope;
1236
+ } else {
1237
+ assert (requiredAccessScope == protoAccessScope ||
1238
+ requiredAccessScope->isChildContextOf (protoAccessScope));
1239
+ }
1238
1240
}
1239
1241
1240
- if (witnessAccess < *requiredAccess )
1242
+ if (!witness-> isAccessibleFrom (requiredAccessScope) )
1241
1243
return true ;
1242
1244
1243
1245
if (requirement->isSettable (DC)) {
1244
1246
*isSetter = true ;
1245
1247
1246
1248
auto ASD = cast<AbstractStorageDecl>(witness);
1247
- const DeclContext *accessDC;
1248
- switch (*requiredAccess) {
1249
- case Accessibility::Open:
1250
- case Accessibility::Public:
1251
- accessDC = nullptr ;
1252
- break ;
1253
- case Accessibility::Internal:
1254
- accessDC = DC->getParentModule ();
1255
- break ;
1256
- case Accessibility::FilePrivate:
1257
- case Accessibility::Private:
1258
- accessDC = DC->getModuleScopeContext ();
1259
- break ;
1260
- }
1261
-
1262
- if (!ASD->isSetterAccessibleFrom (accessDC))
1249
+ if (!ASD->isSetterAccessibleFrom (requiredAccessScope))
1263
1250
return true ;
1264
1251
}
1265
1252
@@ -1276,19 +1263,19 @@ checkWitnessAvailability(ValueDecl *requirement,
1276
1263
}
1277
1264
1278
1265
RequirementCheck WitnessChecker::
1279
- checkWitness (Accessibility requiredAccess ,
1266
+ checkWitness (const DeclContext *requiredAccessScope ,
1280
1267
ValueDecl *requirement,
1281
1268
RequirementMatch match) {
1282
1269
if (!match.OptionalAdjustments .empty ())
1283
1270
return CheckKind::OptionalityConflict;
1284
1271
1285
1272
bool isSetter = false ;
1286
- if (checkWitnessAccessibility (&requiredAccess , requirement,
1273
+ if (checkWitnessAccessibility (requiredAccessScope , requirement,
1287
1274
match.Witness , &isSetter)) {
1288
1275
CheckKind kind = (isSetter
1289
1276
? CheckKind::AccessibilityOfSetter
1290
1277
: CheckKind::Accessibility);
1291
- return RequirementCheck (kind, requiredAccess );
1278
+ return RequirementCheck (kind, requiredAccessScope );
1292
1279
}
1293
1280
1294
1281
auto requiredAvailability = AvailabilityContext::alwaysAvailable ();
@@ -1914,17 +1901,23 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
1914
1901
1915
1902
if (typeDecl) {
1916
1903
// Check access.
1917
- Accessibility requiredAccess = Adoptee->getAnyNominal ()->getFormalAccess ();
1904
+ const DeclContext *requiredAccessScope =
1905
+ Adoptee->getAnyNominal ()->getFormalAccessScope (DC);
1918
1906
bool isSetter = false ;
1919
- if (checkWitnessAccessibility (&requiredAccess , assocType, typeDecl,
1907
+ if (checkWitnessAccessibility (requiredAccessScope , assocType, typeDecl,
1920
1908
&isSetter)) {
1921
1909
assert (!isSetter);
1922
1910
1911
+ // Avoid relying on the lifetime of 'this'.
1912
+ const DeclContext *DC = this ->DC ;
1923
1913
diagnoseOrDefer (assocType, false ,
1924
- [typeDecl, requiredAccess , assocType](
1914
+ [DC, typeDecl, requiredAccessScope , assocType](
1925
1915
TypeChecker &tc, NormalProtocolConformance *conformance) {
1916
+ Accessibility requiredAccess =
1917
+ accessibilityFromScopeForDiagnostics (requiredAccessScope);
1926
1918
auto proto = conformance->getProtocol ();
1927
- bool protoForcesAccess = (requiredAccess == proto->getFormalAccess ());
1919
+ bool protoForcesAccess =
1920
+ (requiredAccessScope == proto->getFormalAccessScope (DC));
1928
1921
auto diagKind = protoForcesAccess
1929
1922
? diag::type_witness_not_accessible_proto
1930
1923
: diag::type_witness_not_accessible_type;
@@ -2014,6 +2007,8 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
2014
2007
static void diagnoseNoWitness (ValueDecl *Requirement, Type RequirementType,
2015
2008
NormalProtocolConformance *Conformance,
2016
2009
TypeChecker &TC) {
2010
+ // FIXME: Try an ignore-access lookup?
2011
+
2017
2012
SourceLoc FixitLocation;
2018
2013
SourceLoc TypeLoc;
2019
2014
if (auto Extension = dyn_cast<ExtensionDecl>(Conformance->getDeclContext ())) {
@@ -2162,21 +2157,27 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2162
2157
});
2163
2158
}
2164
2159
2165
- Accessibility requiredAccess = Adoptee->getAnyNominal ()->getFormalAccess ();
2166
- auto check = checkWitness (requiredAccess, requirement, best);
2160
+ const DeclContext *nominalAccessScope =
2161
+ Adoptee->getAnyNominal ()->getFormalAccessScope (DC);
2162
+ auto check = checkWitness (nominalAccessScope, requirement, best);
2167
2163
2168
2164
switch (check.Kind ) {
2169
2165
case CheckKind::Success:
2170
2166
break ;
2171
2167
2172
2168
case CheckKind::Accessibility:
2173
2169
case CheckKind::AccessibilityOfSetter: {
2170
+ // Avoid relying on the lifetime of 'this'.
2171
+ const DeclContext *DC = this ->DC ;
2174
2172
diagnoseOrDefer (requirement, false ,
2175
- [witness, check, requirement](
2173
+ [DC, witness, check, requirement](
2176
2174
TypeChecker &tc, NormalProtocolConformance *conformance) {
2175
+ Accessibility requiredAccess =
2176
+ accessibilityFromScopeForDiagnostics (check.RequiredAccessScope );
2177
+
2177
2178
auto proto = conformance->getProtocol ();
2178
2179
bool protoForcesAccess =
2179
- (check.RequiredAccess == proto->getFormalAccess ( ));
2180
+ (check.RequiredAccessScope == proto->getFormalAccessScope (DC ));
2180
2181
auto diagKind = protoForcesAccess
2181
2182
? diag::witness_not_accessible_proto
2182
2183
: diag::witness_not_accessible_type;
@@ -2186,9 +2187,9 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2186
2187
getRequirementKind (requirement),
2187
2188
witness->getFullName (),
2188
2189
isSetter,
2189
- check. RequiredAccess ,
2190
+ requiredAccess ,
2190
2191
proto->getName ());
2191
- fixItAccessibility (diag, witness, check. RequiredAccess , isSetter);
2192
+ fixItAccessibility (diag, witness, requiredAccess , isSetter);
2192
2193
});
2193
2194
break ;
2194
2195
}
@@ -4968,7 +4969,7 @@ DefaultWitnessChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
4968
4969
4969
4970
// Perform the same checks as conformance witness matching, but silently
4970
4971
// ignore the candidate instead of diagnosing anything.
4971
- auto check = checkWitness (Accessibility::Public , requirement, best);
4972
+ auto check = checkWitness (/* access: public */ nullptr , requirement, best);
4972
4973
if (check.Kind != CheckKind::Success)
4973
4974
return ResolveWitnessResult::ExplicitFailed;
4974
4975
0 commit comments