Sema: Add simulation of buggy Swift 3 typealias accessibility checking

Basically if the underlying type of a typealias was dependent on
generic parameters from context, it wouldn't participate in
accessibility checking.

Turns out people were (accidentally) relying on this behavior, so
add a simulation of it in Swift 3 mode by ignoring such typealiases
entirely.

Fixes <rdar://problem/29549232>.
This commit is contained in:
Slava Pestov
2016-12-12 14:37:55 -08:00
parent 706099beaa
commit 9fba89bd7b
5 changed files with 98 additions and 40 deletions

View File

@@ -1139,6 +1139,7 @@ static void recordSelfContextType(AbstractFunctionDecl *func) {
namespace { namespace {
class AccessScopeChecker { class AccessScopeChecker {
ASTContext &Context;
const SourceFile *File; const SourceFile *File;
TypeChecker::TypeAccessScopeCacheMap &Cache; TypeChecker::TypeAccessScopeCacheMap &Cache;
@@ -1147,7 +1148,9 @@ protected:
AccessScopeChecker(const DeclContext *useDC, AccessScopeChecker(const DeclContext *useDC,
decltype(TypeChecker::TypeAccessScopeCache) &caches) decltype(TypeChecker::TypeAccessScopeCache) &caches)
: File(useDC->getParentSourceFile()), Cache(caches[File]), : Context(useDC->getASTContext()),
File(useDC->getParentSourceFile()),
Cache(caches[File]),
Scope(AccessScope::getPublic()) {} Scope(AccessScope::getPublic()) {}
bool visitDecl(ValueDecl *VD) { bool visitDecl(ValueDecl *VD) {
@@ -1161,6 +1164,12 @@ protected:
return true; return true;
} }
// Simulation for Swift 3 bug.
if (isa<TypeAliasDecl>(VD) &&
VD->getInterfaceType()->hasTypeParameter() &&
Context.isSwiftVersion3())
return true;
auto cached = Cache.find(VD); auto cached = Cache.find(VD);
if (cached != Cache.end()) { if (cached != Cache.end()) {
Scope = Scope->intersectWith(cached->second); Scope = Scope->intersectWith(cached->second);

View File

@@ -0,0 +1,42 @@
// RUN: %target-typecheck-verify-swift -swift-version 3
public protocol P {
associatedtype Element
func f() -> Element
}
struct S<T> : P {
func f() -> T { while true {} }
}
public struct G<T> {
typealias A = S<T>
public func foo<U : P>(u: U) where U.Element == A.Element {}
}
public final class ReplayableGenerator<S: Sequence> : IteratorProtocol {
typealias Sequence = S
public typealias Element = Sequence.Iterator.Element
public func next() -> Element? {
return nil
}
}
struct Generic<T> {
fileprivate typealias Dependent = T
}
var x: Generic<Int>.Dependent = 3
func internalFuncWithFileprivateAlias() -> Generic<Int>.Dependent {
return 3
}
private func privateFuncWithFileprivateAlias() -> Generic<Int>.Dependent {
return 3
}
var y = privateFuncWithFileprivateAlias()

View File

@@ -637,21 +637,3 @@ internal struct AssocTypeOuterProblem2 {
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}} 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}}
} }
} }
// This code was accepted in Swift 3
public protocol P {
associatedtype Element
func f() -> Element
}
struct S<T> : P {
func f() -> T { while true {} }
}
public struct G<T> {
typealias A = S<T> // expected-note {{type declared here}}
public func foo<U : P>(u: U) where U.Element == A.Element {}
// expected-error@-1 {{instance method cannot be declared public because its generic requirement uses an internal type}}
}

View File

@@ -210,24 +210,3 @@ fileprivate struct SR2579 {
private var outerProperty = Inner().innerProperty // expected-warning {{property should not be declared in this context because its type 'SR2579.Inner.InnerPrivateType' uses a private type}} private var outerProperty = Inner().innerProperty // expected-warning {{property should not be declared in this context because its type 'SR2579.Inner.InnerPrivateType' uses a private type}}
var outerProperty2 = Inner().innerProperty // expected-warning {{property should be declared private because its type 'SR2579.Inner.InnerPrivateType' uses a private type}} var outerProperty2 = Inner().innerProperty // expected-warning {{property should be declared private because its type 'SR2579.Inner.InnerPrivateType' uses a private type}}
} }
// FIXME: Dependent member lookup of typealiases is not subject
// to accessibility checking.
struct Generic<T> {
fileprivate typealias Dependent = T
}
var x: Generic<Int>.Dependent = 3
// expected-error@-1 {{variable must be declared private or fileprivate because its type uses a fileprivate type}}
func internalFuncWithFileprivateAlias() -> Generic<Int>.Dependent {
// expected-error@-1 {{function must be declared private or fileprivate because its result uses a fileprivate type}}
return 3
}
private func privateFuncWithFileprivateAlias() -> Generic<Int>.Dependent {
return 3
}
// FIXME: No error here
var y = privateFuncWithFileprivateAlias()

View File

@@ -0,0 +1,46 @@
// RUN: %target-typecheck-verify-swift -swift-version 4
public protocol P {
associatedtype Element
func f() -> Element
}
struct S<T> : P {
func f() -> T { while true {} }
}
public struct G<T> {
typealias A = S<T> // expected-note {{type declared here}}
public func foo<U : P>(u: U) where U.Element == A.Element {}
// expected-error@-1 {{instance method cannot be declared public because its generic requirement uses an internal type}}
}
public final class ReplayableGenerator<S: Sequence> : IteratorProtocol {
typealias Sequence = S // expected-note {{type declared here}}
public typealias Element = Sequence.Iterator.Element // expected-error {{type alias cannot be declared public because its underlying type uses an internal type}}
public func next() -> Element? {
return nil
}
}
// FIXME: Dependent member lookup of typealiases is not subject
// to accessibility checking.
struct Generic<T> {
fileprivate typealias Dependent = T
}
var x: Generic<Int>.Dependent = 3 // expected-error {{variable must be declared private or fileprivate because its type uses a fileprivate type}}
func internalFuncWithFileprivateAlias() -> Generic<Int>.Dependent { // expected-error {{function must be declared private or fileprivate because its result uses a fileprivate type}}
return 3
}
private func privateFuncWithFileprivateAlias() -> Generic<Int>.Dependent {
return 3
}
// FIXME: No error here
var y = privateFuncWithFileprivateAlias()