@@ -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
}
@@ -1214,48 +1214,35 @@ bool WitnessChecker::findBestWitness(ValueDecl *requirement,
1214
1214
}
1215
1215
1216
1216
bool WitnessChecker::
1217
- checkWitnessAccessibility (Accessibility *requiredAccess ,
1217
+ checkWitnessAccessibility (const DeclContext *&requiredAccessScope ,
1218
1218
ValueDecl *requirement,
1219
1219
ValueDecl *witness,
1220
1220
bool *isSetter) {
1221
1221
*isSetter = false ;
1222
1222
1223
- *requiredAccess = std::min (Proto->getFormalAccess (), *requiredAccess);
1224
- if (TC.getLangOpts ().EnableSwift3Private )
1225
- *requiredAccess = std::max (*requiredAccess, Accessibility::FilePrivate);
1223
+ const DeclContext *protoAccessScope = Proto->getFormalAccessScope (DC);
1226
1224
1227
- Accessibility witnessAccess = witness->getFormalAccess (DC);
1228
-
1229
- // Leave a hole for old-style top-level operators to be declared 'private' for
1230
- // a fileprivate conformance.
1231
- if (witnessAccess == Accessibility::Private &&
1232
- witness->getDeclContext ()->isModuleScopeContext ()) {
1233
- witnessAccess = Accessibility::FilePrivate;
1225
+ // FIXME: This is the same operation as TypeCheckDecl.cpp's
1226
+ // TypeAccessScopeChecker::intersectAccess.
1227
+ if (!requiredAccessScope) {
1228
+ requiredAccessScope = protoAccessScope;
1229
+ } else if (protoAccessScope) {
1230
+ if (protoAccessScope->isChildContextOf (requiredAccessScope)) {
1231
+ requiredAccessScope = protoAccessScope;
1232
+ } else {
1233
+ assert (requiredAccessScope == protoAccessScope ||
1234
+ requiredAccessScope->isChildContextOf (protoAccessScope));
1235
+ }
1234
1236
}
1235
1237
1236
- if (witnessAccess < *requiredAccess )
1238
+ if (!witness-> isAccessibleFrom (requiredAccessScope) )
1237
1239
return true ;
1238
1240
1239
1241
if (requirement->isSettable (DC)) {
1240
1242
*isSetter = true ;
1241
1243
1242
1244
auto ASD = cast<AbstractStorageDecl>(witness);
1243
- const DeclContext *accessDC;
1244
- switch (*requiredAccess) {
1245
- case Accessibility::Open:
1246
- case Accessibility::Public:
1247
- accessDC = nullptr ;
1248
- break ;
1249
- case Accessibility::Internal:
1250
- accessDC = DC->getParentModule ();
1251
- break ;
1252
- case Accessibility::FilePrivate:
1253
- case Accessibility::Private:
1254
- accessDC = DC->getModuleScopeContext ();
1255
- break ;
1256
- }
1257
-
1258
- if (!ASD->isSetterAccessibleFrom (accessDC))
1245
+ if (!ASD->isSetterAccessibleFrom (requiredAccessScope))
1259
1246
return true ;
1260
1247
}
1261
1248
@@ -1272,19 +1259,19 @@ checkWitnessAvailability(ValueDecl *requirement,
1272
1259
}
1273
1260
1274
1261
RequirementCheck WitnessChecker::
1275
- checkWitness (Accessibility requiredAccess ,
1262
+ checkWitness (const DeclContext *requiredAccessScope ,
1276
1263
ValueDecl *requirement,
1277
1264
RequirementMatch match) {
1278
1265
if (!match.OptionalAdjustments .empty ())
1279
1266
return CheckKind::OptionalityConflict;
1280
1267
1281
1268
bool isSetter = false ;
1282
- if (checkWitnessAccessibility (&requiredAccess , requirement,
1269
+ if (checkWitnessAccessibility (requiredAccessScope , requirement,
1283
1270
match.Witness , &isSetter)) {
1284
1271
CheckKind kind = (isSetter
1285
1272
? CheckKind::AccessibilityOfSetter
1286
1273
: CheckKind::Accessibility);
1287
- return RequirementCheck (kind, requiredAccess );
1274
+ return RequirementCheck (kind, requiredAccessScope );
1288
1275
}
1289
1276
1290
1277
auto requiredAvailability = AvailabilityContext::alwaysAvailable ();
@@ -1910,17 +1897,23 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
1910
1897
1911
1898
if (typeDecl) {
1912
1899
// Check access.
1913
- Accessibility requiredAccess = Adoptee->getAnyNominal ()->getFormalAccess ();
1900
+ const DeclContext *requiredAccessScope =
1901
+ Adoptee->getAnyNominal ()->getFormalAccessScope (DC);
1914
1902
bool isSetter = false ;
1915
- if (checkWitnessAccessibility (&requiredAccess , assocType, typeDecl,
1903
+ if (checkWitnessAccessibility (requiredAccessScope , assocType, typeDecl,
1916
1904
&isSetter)) {
1917
1905
assert (!isSetter);
1918
1906
1907
+ // Avoid relying on the lifetime of 'this'.
1908
+ const DeclContext *DC = this ->DC ;
1919
1909
diagnoseOrDefer (assocType, false ,
1920
- [typeDecl, requiredAccess , assocType](
1910
+ [DC, typeDecl, requiredAccessScope , assocType](
1921
1911
TypeChecker &tc, NormalProtocolConformance *conformance) {
1912
+ Accessibility requiredAccess =
1913
+ accessibilityFromScopeForDiagnostics (requiredAccessScope);
1922
1914
auto proto = conformance->getProtocol ();
1923
- bool protoForcesAccess = (requiredAccess == proto->getFormalAccess ());
1915
+ bool protoForcesAccess =
1916
+ (requiredAccessScope == proto->getFormalAccessScope (DC));
1924
1917
auto diagKind = protoForcesAccess
1925
1918
? diag::type_witness_not_accessible_proto
1926
1919
: diag::type_witness_not_accessible_type;
@@ -2010,6 +2003,8 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
2010
2003
static void diagnoseNoWitness (ValueDecl *Requirement, Type RequirementType,
2011
2004
NormalProtocolConformance *Conformance,
2012
2005
TypeChecker &TC) {
2006
+ // FIXME: Try an ignore-access lookup?
2007
+
2013
2008
SourceLoc FixitLocation;
2014
2009
SourceLoc TypeLoc;
2015
2010
if (auto Extension = dyn_cast<ExtensionDecl>(Conformance->getDeclContext ())) {
@@ -2158,21 +2153,27 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2158
2153
});
2159
2154
}
2160
2155
2161
- Accessibility requiredAccess = Adoptee->getAnyNominal ()->getFormalAccess ();
2162
- auto check = checkWitness (requiredAccess, requirement, best);
2156
+ const DeclContext *nominalAccessScope =
2157
+ Adoptee->getAnyNominal ()->getFormalAccessScope (DC);
2158
+ auto check = checkWitness (nominalAccessScope, requirement, best);
2163
2159
2164
2160
switch (check.Kind ) {
2165
2161
case CheckKind::Success:
2166
2162
break ;
2167
2163
2168
2164
case CheckKind::Accessibility:
2169
2165
case CheckKind::AccessibilityOfSetter: {
2166
+ // Avoid relying on the lifetime of 'this'.
2167
+ const DeclContext *DC = this ->DC ;
2170
2168
diagnoseOrDefer (requirement, false ,
2171
- [witness, check, requirement](
2169
+ [DC, witness, check, requirement](
2172
2170
TypeChecker &tc, NormalProtocolConformance *conformance) {
2171
+ Accessibility requiredAccess =
2172
+ accessibilityFromScopeForDiagnostics (check.RequiredAccessScope );
2173
+
2173
2174
auto proto = conformance->getProtocol ();
2174
2175
bool protoForcesAccess =
2175
- (check.RequiredAccess == proto->getFormalAccess ( ));
2176
+ (check.RequiredAccessScope == proto->getFormalAccessScope (DC ));
2176
2177
auto diagKind = protoForcesAccess
2177
2178
? diag::witness_not_accessible_proto
2178
2179
: diag::witness_not_accessible_type;
@@ -2182,9 +2183,9 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
2182
2183
getRequirementKind (requirement),
2183
2184
witness->getFullName (),
2184
2185
isSetter,
2185
- check. RequiredAccess ,
2186
+ requiredAccess ,
2186
2187
proto->getName ());
2187
- fixItAccessibility (diag, witness, check. RequiredAccess , isSetter);
2188
+ fixItAccessibility (diag, witness, requiredAccess , isSetter);
2188
2189
});
2189
2190
break ;
2190
2191
}
@@ -4978,7 +4979,7 @@ DefaultWitnessChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
4978
4979
4979
4980
// Perform the same checks as conformance witness matching, but silently
4980
4981
// ignore the candidate instead of diagnosing anything.
4981
- auto check = checkWitness (Accessibility::Public , requirement, best);
4982
+ auto check = checkWitness (/* access: public */ nullptr , requirement, best);
4982
4983
if (check.Kind != CheckKind::Success)
4983
4984
return ResolveWitnessResult::ExplicitFailed;
4984
4985
0 commit comments