@@ -68,7 +68,7 @@ namespace {
6868 unsigned &bestIdx,
6969 bool &doNotDiagnoseMatches);
7070
71- bool checkWitnessAccessibility (Accessibility *requiredAccess ,
71+ bool checkWitnessAccessibility (const DeclContext *&requiredAccessScope ,
7272 ValueDecl *requirement,
7373 ValueDecl *witness,
7474 bool *isSetter);
@@ -77,7 +77,7 @@ namespace {
7777 ValueDecl *witness,
7878 AvailabilityContext *requirementInfo);
7979
80- RequirementCheck checkWitness (Accessibility requiredAccess ,
80+ RequirementCheck checkWitness (const DeclContext *requiredAccessScope ,
8181 ValueDecl *requirement,
8282 RequirementMatch match);
8383 };
@@ -392,24 +392,24 @@ namespace {
392392 struct RequirementCheck {
393393 CheckKind Kind;
394394
395- // / The required accessibility , if the check failed due to the
395+ // / The required access scope , if the check failed due to the
396396 // / witness being less accessible than the requirement.
397- Accessibility RequiredAccess ;
397+ const DeclContext *RequiredAccessScope ;
398398
399399 // / The required availability, if the check failed due to the
400400 // / witness being less available than the requirement.
401401 AvailabilityContext RequiredAvailability;
402402
403403 RequirementCheck (CheckKind kind)
404- : Kind(kind), RequiredAccess(Accessibility::Public ),
404+ : Kind(kind), RequiredAccessScope( nullptr ),
405405 RequiredAvailability (AvailabilityContext::alwaysAvailable()) { }
406406
407- RequirementCheck (CheckKind kind, Accessibility requiredAccess )
408- : Kind(kind), RequiredAccess(requiredAccess ),
407+ RequirementCheck (CheckKind kind, const DeclContext *requiredAccessScope )
408+ : Kind(kind), RequiredAccessScope(requiredAccessScope ),
409409 RequiredAvailability(AvailabilityContext::alwaysAvailable()) { }
410410
411411 RequirementCheck (CheckKind kind, AvailabilityContext requiredAvailability)
412- : Kind(kind), RequiredAccess(Accessibility::Public ),
412+ : Kind(kind), RequiredAccessScope( nullptr ),
413413 RequiredAvailability(requiredAvailability) { }
414414 };
415415}
@@ -1214,48 +1214,35 @@ bool WitnessChecker::findBestWitness(ValueDecl *requirement,
12141214}
12151215
12161216bool WitnessChecker::
1217- checkWitnessAccessibility (Accessibility *requiredAccess ,
1217+ checkWitnessAccessibility (const DeclContext *&requiredAccessScope ,
12181218 ValueDecl *requirement,
12191219 ValueDecl *witness,
12201220 bool *isSetter) {
12211221 *isSetter = false ;
12221222
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);
12261224
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+ }
12341236 }
12351237
1236- if (witnessAccess < *requiredAccess )
1238+ if (!witness-> isAccessibleFrom (requiredAccessScope) )
12371239 return true ;
12381240
12391241 if (requirement->isSettable (DC)) {
12401242 *isSetter = true ;
12411243
12421244 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))
12591246 return true ;
12601247 }
12611248
@@ -1272,19 +1259,19 @@ checkWitnessAvailability(ValueDecl *requirement,
12721259}
12731260
12741261RequirementCheck WitnessChecker::
1275- checkWitness (Accessibility requiredAccess ,
1262+ checkWitness (const DeclContext *requiredAccessScope ,
12761263 ValueDecl *requirement,
12771264 RequirementMatch match) {
12781265 if (!match.OptionalAdjustments .empty ())
12791266 return CheckKind::OptionalityConflict;
12801267
12811268 bool isSetter = false ;
1282- if (checkWitnessAccessibility (&requiredAccess , requirement,
1269+ if (checkWitnessAccessibility (requiredAccessScope , requirement,
12831270 match.Witness , &isSetter)) {
12841271 CheckKind kind = (isSetter
12851272 ? CheckKind::AccessibilityOfSetter
12861273 : CheckKind::Accessibility);
1287- return RequirementCheck (kind, requiredAccess );
1274+ return RequirementCheck (kind, requiredAccessScope );
12881275 }
12891276
12901277 auto requiredAvailability = AvailabilityContext::alwaysAvailable ();
@@ -1910,17 +1897,23 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
19101897
19111898 if (typeDecl) {
19121899 // Check access.
1913- Accessibility requiredAccess = Adoptee->getAnyNominal ()->getFormalAccess ();
1900+ const DeclContext *requiredAccessScope =
1901+ Adoptee->getAnyNominal ()->getFormalAccessScope (DC);
19141902 bool isSetter = false ;
1915- if (checkWitnessAccessibility (&requiredAccess , assocType, typeDecl,
1903+ if (checkWitnessAccessibility (requiredAccessScope , assocType, typeDecl,
19161904 &isSetter)) {
19171905 assert (!isSetter);
19181906
1907+ // Avoid relying on the lifetime of 'this'.
1908+ const DeclContext *DC = this ->DC ;
19191909 diagnoseOrDefer (assocType, false ,
1920- [typeDecl, requiredAccess , assocType](
1910+ [DC, typeDecl, requiredAccessScope , assocType](
19211911 TypeChecker &tc, NormalProtocolConformance *conformance) {
1912+ Accessibility requiredAccess =
1913+ accessibilityFromScopeForDiagnostics (requiredAccessScope);
19221914 auto proto = conformance->getProtocol ();
1923- bool protoForcesAccess = (requiredAccess == proto->getFormalAccess ());
1915+ bool protoForcesAccess =
1916+ (requiredAccessScope == proto->getFormalAccessScope (DC));
19241917 auto diagKind = protoForcesAccess
19251918 ? diag::type_witness_not_accessible_proto
19261919 : diag::type_witness_not_accessible_type;
@@ -2010,6 +2003,8 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
20102003static void diagnoseNoWitness (ValueDecl *Requirement, Type RequirementType,
20112004 NormalProtocolConformance *Conformance,
20122005 TypeChecker &TC) {
2006+ // FIXME: Try an ignore-access lookup?
2007+
20132008 SourceLoc FixitLocation;
20142009 SourceLoc TypeLoc;
20152010 if (auto Extension = dyn_cast<ExtensionDecl>(Conformance->getDeclContext ())) {
@@ -2158,21 +2153,27 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
21582153 });
21592154 }
21602155
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);
21632159
21642160 switch (check.Kind ) {
21652161 case CheckKind::Success:
21662162 break ;
21672163
21682164 case CheckKind::Accessibility:
21692165 case CheckKind::AccessibilityOfSetter: {
2166+ // Avoid relying on the lifetime of 'this'.
2167+ const DeclContext *DC = this ->DC ;
21702168 diagnoseOrDefer (requirement, false ,
2171- [witness, check, requirement](
2169+ [DC, witness, check, requirement](
21722170 TypeChecker &tc, NormalProtocolConformance *conformance) {
2171+ Accessibility requiredAccess =
2172+ accessibilityFromScopeForDiagnostics (check.RequiredAccessScope );
2173+
21732174 auto proto = conformance->getProtocol ();
21742175 bool protoForcesAccess =
2175- (check.RequiredAccess == proto->getFormalAccess ( ));
2176+ (check.RequiredAccessScope == proto->getFormalAccessScope (DC ));
21762177 auto diagKind = protoForcesAccess
21772178 ? diag::witness_not_accessible_proto
21782179 : diag::witness_not_accessible_type;
@@ -2182,9 +2183,9 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
21822183 getRequirementKind (requirement),
21832184 witness->getFullName (),
21842185 isSetter,
2185- check. RequiredAccess ,
2186+ requiredAccess ,
21862187 proto->getName ());
2187- fixItAccessibility (diag, witness, check. RequiredAccess , isSetter);
2188+ fixItAccessibility (diag, witness, requiredAccess , isSetter);
21882189 });
21892190 break ;
21902191 }
@@ -4978,7 +4979,7 @@ DefaultWitnessChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
49784979
49794980 // Perform the same checks as conformance witness matching, but silently
49804981 // ignore the candidate instead of diagnosing anything.
4981- auto check = checkWitness (Accessibility::Public , requirement, best);
4982+ auto check = checkWitness (/* access: public */ nullptr , requirement, best);
49824983 if (check.Kind != CheckKind::Success)
49834984 return ResolveWitnessResult::ExplicitFailed;
49844985
0 commit comments