Check protocol witnesses using access scopes. (#4176)

...rather than relying on the access-as-spelled, which may be greater
than the effective access due to parent scopes.

(Some of this will get cleaned up with SR-2209.)

rdar://problem/27663492
This commit is contained in:
Jordan Rose
2016-08-11 14:30:09 -07:00
committed by GitHub
parent 84d4685ad4
commit f65ad810df
6 changed files with 155 additions and 78 deletions

View File

@@ -3606,6 +3606,20 @@ void swift::performStmtDiagnostics(TypeChecker &TC, const Stmt *S) {
// Utility functions // Utility functions
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
Accessibility
swift::accessibilityFromScopeForDiagnostics(const DeclContext *accessScope) {
if (!accessScope)
return Accessibility::Public;
if (isa<ModuleDecl>(accessScope))
return Accessibility::Internal;
if (accessScope->isModuleScopeContext() &&
accessScope->getASTContext().LangOpts.EnableSwift3Private) {
return Accessibility::FilePrivate;
}
return Accessibility::Private;
}
void swift::fixItAccessibility(InFlightDiagnostic &diag, ValueDecl *VD, void swift::fixItAccessibility(InFlightDiagnostic &diag, ValueDecl *VD,
Accessibility desiredAccess, bool isForSetter) { Accessibility desiredAccess, bool isForSetter) {
StringRef fixItString; StringRef fixItString;
@@ -3618,7 +3632,7 @@ void swift::fixItAccessibility(InFlightDiagnostic &diag, ValueDecl *VD,
} }
DeclAttributes &attrs = VD->getAttrs(); DeclAttributes &attrs = VD->getAttrs();
DeclAttribute *attr; AbstractAccessibilityAttr *attr;
if (isForSetter) { if (isForSetter) {
attr = attrs.getAttribute<SetterAccessibilityAttr>(); attr = attrs.getAttribute<SetterAccessibilityAttr>();
cast<AbstractStorageDecl>(VD)->overwriteSetterAccessibility(desiredAccess); cast<AbstractStorageDecl>(VD)->overwriteSetterAccessibility(desiredAccess);
@@ -3646,10 +3660,18 @@ void swift::fixItAccessibility(InFlightDiagnostic &diag, ValueDecl *VD,
diag.fixItRemove(attr->Range); diag.fixItRemove(attr->Range);
} else if (attr) { } else if (attr) {
// If the formal access already matches the desired access, the problem
// must be in a parent scope. Don't emit a fix-it.
// FIXME: It's also possible for access to already be /broader/ than what's
// desired, in which case the problem is also in a parent scope. However,
// this function is sometimes called to make access narrower, so assuming
// that a broader scope is acceptable breaks some diagnostics.
if (attr->getAccess() != desiredAccess) {
// This uses getLocation() instead of getRange() because we don't want to // This uses getLocation() instead of getRange() because we don't want to
// replace the "(set)" part of a setter attribute. // replace the "(set)" part of a setter attribute.
diag.fixItReplace(attr->getLocation(), fixItString.drop_back()); diag.fixItReplace(attr->getLocation(), fixItString.drop_back());
attr->setInvalid(); attr->setInvalid();
}
} else if (auto var = dyn_cast<VarDecl>(VD)) { } else if (auto var = dyn_cast<VarDecl>(VD)) {
if (auto PBD = var->getParentPatternBinding()) if (auto PBD = var->getParentPatternBinding())

View File

@@ -31,6 +31,13 @@ namespace swift {
class TypeChecker; class TypeChecker;
class ValueDecl; class ValueDecl;
/// Returns the access level associated with \p accessScope, for diagnostic
/// purposes.
///
/// \sa ValueDecl::getFormalAccessScope
Accessibility
accessibilityFromScopeForDiagnostics(const DeclContext *accessScope);
/// \brief Emit diagnostics for syntactic restrictions on a given expression. /// \brief Emit diagnostics for syntactic restrictions on a given expression.
void performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E, void performSyntacticExprDiagnostics(TypeChecker &TC, const Expr *E,
const DeclContext *DC, const DeclContext *DC,

View File

@@ -1538,23 +1538,6 @@ static void highlightOffendingType(TypeChecker &TC, InFlightDiagnostic &diag,
} }
} }
/// Returns the access level associated with \p accessScope, for diagnostic
/// purposes.
///
/// \sa ValueDecl::getFormalAccessScope
static Accessibility
accessibilityFromScopeForDiagnostics(const DeclContext *accessScope) {
if (!accessScope)
return Accessibility::Public;
if (isa<ModuleDecl>(accessScope))
return Accessibility::Internal;
if (accessScope->isModuleScopeContext() &&
accessScope->getASTContext().LangOpts.EnableSwift3Private) {
return Accessibility::FilePrivate;
}
return Accessibility::Private;
}
static void checkGenericParamAccessibility(TypeChecker &TC, static void checkGenericParamAccessibility(TypeChecker &TC,
const GenericParamList *params, const GenericParamList *params,
const Decl *owner, const Decl *owner,

View File

@@ -68,7 +68,7 @@ namespace {
unsigned &bestIdx, unsigned &bestIdx,
bool &doNotDiagnoseMatches); bool &doNotDiagnoseMatches);
bool checkWitnessAccessibility(Accessibility *requiredAccess, bool checkWitnessAccessibility(const DeclContext *&requiredAccessScope,
ValueDecl *requirement, ValueDecl *requirement,
ValueDecl *witness, ValueDecl *witness,
bool *isSetter); bool *isSetter);
@@ -77,7 +77,7 @@ namespace {
ValueDecl *witness, ValueDecl *witness,
AvailabilityContext *requirementInfo); AvailabilityContext *requirementInfo);
RequirementCheck checkWitness(Accessibility requiredAccess, RequirementCheck checkWitness(const DeclContext *requiredAccessScope,
ValueDecl *requirement, ValueDecl *requirement,
RequirementMatch match); RequirementMatch match);
}; };
@@ -392,24 +392,24 @@ namespace {
struct RequirementCheck { struct RequirementCheck {
CheckKind Kind; CheckKind Kind;
/// The required accessibility, if the check failed due to the /// The required access scope, if the check failed due to the
/// witness being less accessible than the requirement. /// witness being less accessible than the requirement.
Accessibility RequiredAccess; const DeclContext *RequiredAccessScope;
/// The required availability, if the check failed due to the /// The required availability, if the check failed due to the
/// witness being less available than the requirement. /// witness being less available than the requirement.
AvailabilityContext RequiredAvailability; AvailabilityContext RequiredAvailability;
RequirementCheck(CheckKind kind) RequirementCheck(CheckKind kind)
: Kind(kind), RequiredAccess(Accessibility::Public), : Kind(kind), RequiredAccessScope(nullptr),
RequiredAvailability(AvailabilityContext::alwaysAvailable()) { } RequiredAvailability(AvailabilityContext::alwaysAvailable()) { }
RequirementCheck(CheckKind kind, Accessibility requiredAccess) RequirementCheck(CheckKind kind, const DeclContext *requiredAccessScope)
: Kind(kind), RequiredAccess(requiredAccess), : Kind(kind), RequiredAccessScope(requiredAccessScope),
RequiredAvailability(AvailabilityContext::alwaysAvailable()) { } RequiredAvailability(AvailabilityContext::alwaysAvailable()) { }
RequirementCheck(CheckKind kind, AvailabilityContext requiredAvailability) RequirementCheck(CheckKind kind, AvailabilityContext requiredAvailability)
: Kind(kind), RequiredAccess(Accessibility::Public), : Kind(kind), RequiredAccessScope(nullptr),
RequiredAvailability(requiredAvailability) { } RequiredAvailability(requiredAvailability) { }
}; };
} }
@@ -1218,48 +1218,35 @@ bool WitnessChecker::findBestWitness(ValueDecl *requirement,
} }
bool WitnessChecker:: bool WitnessChecker::
checkWitnessAccessibility(Accessibility *requiredAccess, checkWitnessAccessibility(const DeclContext *&requiredAccessScope,
ValueDecl *requirement, ValueDecl *requirement,
ValueDecl *witness, ValueDecl *witness,
bool *isSetter) { bool *isSetter) {
*isSetter = false; *isSetter = false;
*requiredAccess = std::min(Proto->getFormalAccess(), *requiredAccess); const DeclContext *protoAccessScope = Proto->getFormalAccessScope(DC);
if (TC.getLangOpts().EnableSwift3Private)
*requiredAccess = std::max(*requiredAccess, Accessibility::FilePrivate);
Accessibility witnessAccess = witness->getFormalAccess(DC); // FIXME: This is the same operation as TypeCheckDecl.cpp's
// TypeAccessScopeChecker::intersectAccess.
// Leave a hole for old-style top-level operators to be declared 'private' for if (!requiredAccessScope) {
// a fileprivate conformance. requiredAccessScope = protoAccessScope;
if (witnessAccess == Accessibility::Private && } else if (protoAccessScope) {
witness->getDeclContext()->isModuleScopeContext()) { if (protoAccessScope->isChildContextOf(requiredAccessScope)) {
witnessAccess = Accessibility::FilePrivate; requiredAccessScope = protoAccessScope;
} else {
assert(requiredAccessScope == protoAccessScope ||
requiredAccessScope->isChildContextOf(protoAccessScope));
}
} }
if (witnessAccess < *requiredAccess) if (!witness->isAccessibleFrom(requiredAccessScope))
return true; return true;
if (requirement->isSettable(DC)) { if (requirement->isSettable(DC)) {
*isSetter = true; *isSetter = true;
auto ASD = cast<AbstractStorageDecl>(witness); auto ASD = cast<AbstractStorageDecl>(witness);
const DeclContext *accessDC; if (!ASD->isSetterAccessibleFrom(requiredAccessScope))
switch (*requiredAccess) {
case Accessibility::Open:
case Accessibility::Public:
accessDC = nullptr;
break;
case Accessibility::Internal:
accessDC = DC->getParentModule();
break;
case Accessibility::FilePrivate:
case Accessibility::Private:
accessDC = DC->getModuleScopeContext();
break;
}
if (!ASD->isSetterAccessibleFrom(accessDC))
return true; return true;
} }
@@ -1276,19 +1263,19 @@ checkWitnessAvailability(ValueDecl *requirement,
} }
RequirementCheck WitnessChecker:: RequirementCheck WitnessChecker::
checkWitness(Accessibility requiredAccess, checkWitness(const DeclContext *requiredAccessScope,
ValueDecl *requirement, ValueDecl *requirement,
RequirementMatch match) { RequirementMatch match) {
if (!match.OptionalAdjustments.empty()) if (!match.OptionalAdjustments.empty())
return CheckKind::OptionalityConflict; return CheckKind::OptionalityConflict;
bool isSetter = false; bool isSetter = false;
if (checkWitnessAccessibility(&requiredAccess, requirement, if (checkWitnessAccessibility(requiredAccessScope, requirement,
match.Witness, &isSetter)) { match.Witness, &isSetter)) {
CheckKind kind = (isSetter CheckKind kind = (isSetter
? CheckKind::AccessibilityOfSetter ? CheckKind::AccessibilityOfSetter
: CheckKind::Accessibility); : CheckKind::Accessibility);
return RequirementCheck(kind, requiredAccess); return RequirementCheck(kind, requiredAccessScope);
} }
auto requiredAvailability = AvailabilityContext::alwaysAvailable(); auto requiredAvailability = AvailabilityContext::alwaysAvailable();
@@ -1914,17 +1901,23 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
if (typeDecl) { if (typeDecl) {
// Check access. // Check access.
Accessibility requiredAccess = Adoptee->getAnyNominal()->getFormalAccess(); const DeclContext *requiredAccessScope =
Adoptee->getAnyNominal()->getFormalAccessScope(DC);
bool isSetter = false; bool isSetter = false;
if (checkWitnessAccessibility(&requiredAccess, assocType, typeDecl, if (checkWitnessAccessibility(requiredAccessScope, assocType, typeDecl,
&isSetter)) { &isSetter)) {
assert(!isSetter); assert(!isSetter);
// Avoid relying on the lifetime of 'this'.
const DeclContext *DC = this->DC;
diagnoseOrDefer(assocType, false, diagnoseOrDefer(assocType, false,
[typeDecl, requiredAccess, assocType]( [DC, typeDecl, requiredAccessScope, assocType](
TypeChecker &tc, NormalProtocolConformance *conformance) { TypeChecker &tc, NormalProtocolConformance *conformance) {
Accessibility requiredAccess =
accessibilityFromScopeForDiagnostics(requiredAccessScope);
auto proto = conformance->getProtocol(); auto proto = conformance->getProtocol();
bool protoForcesAccess = (requiredAccess == proto->getFormalAccess()); bool protoForcesAccess =
(requiredAccessScope == proto->getFormalAccessScope(DC));
auto diagKind = protoForcesAccess auto diagKind = protoForcesAccess
? diag::type_witness_not_accessible_proto ? diag::type_witness_not_accessible_proto
: diag::type_witness_not_accessible_type; : diag::type_witness_not_accessible_type;
@@ -2014,6 +2007,8 @@ void ConformanceChecker::recordTypeWitness(AssociatedTypeDecl *assocType,
static void diagnoseNoWitness(ValueDecl *Requirement, Type RequirementType, static void diagnoseNoWitness(ValueDecl *Requirement, Type RequirementType,
NormalProtocolConformance *Conformance, NormalProtocolConformance *Conformance,
TypeChecker &TC) { TypeChecker &TC) {
// FIXME: Try an ignore-access lookup?
SourceLoc FixitLocation; SourceLoc FixitLocation;
SourceLoc TypeLoc; SourceLoc TypeLoc;
if (auto Extension = dyn_cast<ExtensionDecl>(Conformance->getDeclContext())) { if (auto Extension = dyn_cast<ExtensionDecl>(Conformance->getDeclContext())) {
@@ -2162,8 +2157,9 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
}); });
} }
Accessibility requiredAccess = Adoptee->getAnyNominal()->getFormalAccess(); const DeclContext *nominalAccessScope =
auto check = checkWitness(requiredAccess, requirement, best); Adoptee->getAnyNominal()->getFormalAccessScope(DC);
auto check = checkWitness(nominalAccessScope, requirement, best);
switch (check.Kind) { switch (check.Kind) {
case CheckKind::Success: case CheckKind::Success:
@@ -2171,12 +2167,17 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
case CheckKind::Accessibility: case CheckKind::Accessibility:
case CheckKind::AccessibilityOfSetter: { case CheckKind::AccessibilityOfSetter: {
// Avoid relying on the lifetime of 'this'.
const DeclContext *DC = this->DC;
diagnoseOrDefer(requirement, false, diagnoseOrDefer(requirement, false,
[witness, check, requirement]( [DC, witness, check, requirement](
TypeChecker &tc, NormalProtocolConformance *conformance) { TypeChecker &tc, NormalProtocolConformance *conformance) {
Accessibility requiredAccess =
accessibilityFromScopeForDiagnostics(check.RequiredAccessScope);
auto proto = conformance->getProtocol(); auto proto = conformance->getProtocol();
bool protoForcesAccess = bool protoForcesAccess =
(check.RequiredAccess == proto->getFormalAccess()); (check.RequiredAccessScope == proto->getFormalAccessScope(DC));
auto diagKind = protoForcesAccess auto diagKind = protoForcesAccess
? diag::witness_not_accessible_proto ? diag::witness_not_accessible_proto
: diag::witness_not_accessible_type; : diag::witness_not_accessible_type;
@@ -2186,9 +2187,9 @@ ConformanceChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
getRequirementKind(requirement), getRequirementKind(requirement),
witness->getFullName(), witness->getFullName(),
isSetter, isSetter,
check.RequiredAccess, requiredAccess,
proto->getName()); proto->getName());
fixItAccessibility(diag, witness, check.RequiredAccess, isSetter); fixItAccessibility(diag, witness, requiredAccess, isSetter);
}); });
break; break;
} }
@@ -4968,7 +4969,7 @@ DefaultWitnessChecker::resolveWitnessViaLookup(ValueDecl *requirement) {
// Perform the same checks as conformance witness matching, but silently // Perform the same checks as conformance witness matching, but silently
// ignore the candidate instead of diagnosing anything. // ignore the candidate instead of diagnosing anything.
auto check = checkWitness(Accessibility::Public, requirement, best); auto check = checkWitness(/*access: public*/nullptr, requirement, best);
if (check.Kind != CheckKind::Success) if (check.Kind != CheckKind::Success)
return ResolveWitnessResult::ExplicitFailed; return ResolveWitnessResult::ExplicitFailed;

View File

@@ -96,9 +96,10 @@ protocol MethodProto {
} }
extension OriginallyEmpty : MethodProto {} extension OriginallyEmpty : MethodProto {}
extension HiddenMethod : MethodProto {} // expected-error {{type 'HiddenMethod' does not conform to protocol 'MethodProto'}}
// TESTABLE-NOT: :[[@LINE-1]]:{{[^:]+}}: // TESTABLE-NOT: :[[@LINE-1]]:{{[^:]+}}:
#if !ACCESS_DISABLED #if !ACCESS_DISABLED
extension HiddenMethod : MethodProto {} // expected-error {{type 'HiddenMethod' does not conform to protocol 'MethodProto'}}
extension Foo : MethodProto {} // expected-error {{type 'Foo' does not conform to protocol 'MethodProto'}} extension Foo : MethodProto {} // expected-error {{type 'Foo' does not conform to protocol 'MethodProto'}}
#endif #endif
@@ -108,9 +109,10 @@ protocol TypeProto {
} }
extension OriginallyEmpty {} extension OriginallyEmpty {}
#if !ACCESS_DISABLED
extension HiddenType : TypeProto {} // expected-error {{type 'HiddenType' does not conform to protocol 'TypeProto'}} extension HiddenType : TypeProto {} // expected-error {{type 'HiddenType' does not conform to protocol 'TypeProto'}}
// TESTABLE-NOT: :[[@LINE-1]]:{{[^:]+}}: // TESTABLE-NOT: :[[@LINE-1]]:{{[^:]+}}:
#if !ACCESS_DISABLED
extension Foo : TypeProto {} // expected-error {{type 'Foo' does not conform to protocol 'TypeProto'}} extension Foo : TypeProto {} // expected-error {{type 'Foo' does not conform to protocol 'TypeProto'}}
#endif #endif

View File

@@ -22,7 +22,7 @@ public struct PublicStruct: PublicProto, InternalProto, FilePrivateProto, Privat
private func publicReq() {} // expected-error {{method 'publicReq()' must be declared public because it matches a requirement in public protocol 'PublicProto'}} {{3-10=public}} private func publicReq() {} // expected-error {{method 'publicReq()' must be declared public because it matches a requirement in public protocol 'PublicProto'}} {{3-10=public}}
private func internalReq() {} // expected-error {{method 'internalReq()' must be declared internal because it matches a requirement in internal protocol 'InternalProto'}} {{3-10=internal}} private func internalReq() {} // expected-error {{method 'internalReq()' must be declared internal because it matches a requirement in internal protocol 'InternalProto'}} {{3-10=internal}}
private func filePrivateReq() {} // expected-error {{method 'filePrivateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'FilePrivateProto'}} {{3-10=fileprivate}} private func filePrivateReq() {} // expected-error {{method 'filePrivateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'FilePrivateProto'}} {{3-10=fileprivate}}
private func privateReq() {} // expected-error {{method 'privateReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PrivateProto'}} {{3-10=fileprivate}} private func privateReq() {} // expected-error {{method 'privateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'PrivateProto'}} {{3-10=fileprivate}}
public var publicVar = 0 public var publicVar = 0
} }
@@ -32,7 +32,7 @@ internal struct InternalStruct: PublicProto, InternalProto, FilePrivateProto, Pr
private func publicReq() {} // expected-error {{method 'publicReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PublicProto'}} {{3-10=internal}} private func publicReq() {} // expected-error {{method 'publicReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PublicProto'}} {{3-10=internal}}
private func internalReq() {} // expected-error {{method 'internalReq()' must be declared internal because it matches a requirement in internal protocol 'InternalProto'}} {{3-10=internal}} private func internalReq() {} // expected-error {{method 'internalReq()' must be declared internal because it matches a requirement in internal protocol 'InternalProto'}} {{3-10=internal}}
private func filePrivateReq() {} // expected-error {{method 'filePrivateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'FilePrivateProto'}} {{3-10=fileprivate}} private func filePrivateReq() {} // expected-error {{method 'filePrivateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'FilePrivateProto'}} {{3-10=fileprivate}}
private func privateReq() {} // expected-error {{method 'privateReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PrivateProto'}} {{3-10=fileprivate}} private func privateReq() {} // expected-error {{method 'privateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'PrivateProto'}} {{3-10=fileprivate}}
public var publicVar = 0 public var publicVar = 0
} }
@@ -42,7 +42,7 @@ fileprivate struct FilePrivateStruct: PublicProto, InternalProto, FilePrivatePro
private func publicReq() {} // expected-error {{method 'publicReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PublicProto'}} {{3-10=fileprivate}} private func publicReq() {} // expected-error {{method 'publicReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PublicProto'}} {{3-10=fileprivate}}
private func internalReq() {} // expected-error {{method 'internalReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'InternalProto'}} {{3-10=fileprivate}} private func internalReq() {} // expected-error {{method 'internalReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'InternalProto'}} {{3-10=fileprivate}}
private func filePrivateReq() {} // expected-error {{method 'filePrivateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'FilePrivateProto'}} {{3-10=fileprivate}} private func filePrivateReq() {} // expected-error {{method 'filePrivateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'FilePrivateProto'}} {{3-10=fileprivate}}
private func privateReq() {} // expected-error {{method 'privateReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PrivateProto'}} {{3-10=fileprivate}} private func privateReq() {} // expected-error {{method 'privateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'PrivateProto'}} {{3-10=fileprivate}}
public var publicVar = 0 public var publicVar = 0
} }
@@ -52,7 +52,7 @@ private struct PrivateStruct: PublicProto, InternalProto, FilePrivateProto, Priv
private func publicReq() {} // expected-error {{method 'publicReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PublicProto'}} {{3-10=fileprivate}} private func publicReq() {} // expected-error {{method 'publicReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PublicProto'}} {{3-10=fileprivate}}
private func internalReq() {} // expected-error {{method 'internalReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'InternalProto'}} {{3-10=fileprivate}} private func internalReq() {} // expected-error {{method 'internalReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'InternalProto'}} {{3-10=fileprivate}}
private func filePrivateReq() {} // expected-error {{method 'filePrivateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'FilePrivateProto'}} {{3-10=fileprivate}} private func filePrivateReq() {} // expected-error {{method 'filePrivateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'FilePrivateProto'}} {{3-10=fileprivate}}
private func privateReq() {} // expected-error {{method 'privateReq()' must be as accessible as its enclosing type because it matches a requirement in protocol 'PrivateProto'}} {{3-10=fileprivate}} private func privateReq() {} // expected-error {{method 'privateReq()' must be declared fileprivate because it matches a requirement in fileprivate protocol 'PrivateProto'}} {{3-10=fileprivate}}
public var publicVar = 0 public var publicVar = 0
} }
@@ -389,6 +389,7 @@ enum DefaultEnumPublic {
case A(PublicStruct) // no-warning case A(PublicStruct) // no-warning
} }
struct DefaultGeneric<T> {} struct DefaultGeneric<T> {}
// FIXME: These types are actually private; they're just being reported as // FIXME: These types are actually private; they're just being reported as
// fileprivate because they're top-level. // fileprivate because they're top-level.
@@ -536,3 +537,64 @@ private prefix func !(input: PrivateOperatorAdopter) -> PrivateOperatorAdopter {
private prefix func !(input: PrivateOperatorAdopter.Inner) -> PrivateOperatorAdopter.Inner { private prefix func !(input: PrivateOperatorAdopter.Inner) -> PrivateOperatorAdopter.Inner {
return input return input
} }
public protocol Equatablish {
static func ==(lhs: Self, rhs: Self) /* -> bool */ // expected-note {{protocol requires function '=='}}
}
fileprivate struct EquatablishOuter {
internal struct Inner : Equatablish {}
}
private func ==(lhs: EquatablishOuter.Inner, rhs: EquatablishOuter.Inner) {}
// expected-note@-1 {{candidate has non-matching type}}
fileprivate struct EquatablishOuter2 {
internal struct Inner : Equatablish {
fileprivate static func ==(lhs: Inner, rhs: Inner) {}
// expected-note@-1 {{candidate has non-matching type}}
}
}
fileprivate struct EquatablishOuterProblem {
internal struct Inner : Equatablish { // expected-error {{type 'EquatablishOuterProblem.Inner' does not conform to protocol 'Equatablish'}}
private static func ==(lhs: Inner, rhs: Inner) {}
}
}
internal struct EquatablishOuterProblem2 {
public struct Inner : Equatablish {
fileprivate static func ==(lhs: Inner, rhs: Inner) {} // expected-error {{method '==' must be as accessible as its enclosing type because it matches a requirement in protocol 'Equatablish'}} {{5-16=internal}}
// expected-note@-1 {{candidate has non-matching type}}
}
}
internal struct EquatablishOuterProblem3 {
public struct Inner : Equatablish {
}
}
private func ==(lhs: EquatablishOuterProblem3.Inner, rhs: EquatablishOuterProblem3.Inner) {} // expected-error {{method '==' must be as accessible as its enclosing type because it matches a requirement in protocol 'Equatablish'}} {{1-8=internal}}
// expected-note@-1 {{candidate has non-matching type}}
public protocol AssocTypeProto {
associatedtype Assoc
}
fileprivate struct AssocTypeOuter {
internal struct Inner : AssocTypeProto {
fileprivate typealias Assoc = Int
}
}
fileprivate struct AssocTypeOuterProblem {
internal struct Inner : AssocTypeProto {
private typealias Assoc = Int // expected-error {{type alias 'Assoc' must be as accessible as its enclosing type because it matches a requirement in protocol 'AssocTypeProto'}} {{5-12=fileprivate}}
}
}
internal struct AssocTypeOuterProblem2 {
public struct Inner : AssocTypeProto {
fileprivate typealias Assoc = Int // expected-error {{type alias 'Assoc' must be as accessible as its enclosing type because it matches a requirement in protocol 'AssocTypeProto'}} {{5-16=internal}}
}
}