blob: b0d0d2a491a0f2378a9882610aaca923ce421bf4 [file] [log] [blame]
// RUN: %target-typecheck-verify-swift
protocol P1 {
typealias DependentInConcreteConformance = Self
}
class Base<T> : P1 {
typealias DependentClass = T
required init(classInit: ()) {}
func classSelfReturn() -> Self {}
}
protocol P2 {
typealias FullyConcrete = Int
typealias DependentProtocol = Self
init(protocolInit: ())
func protocolSelfReturn() -> Self
}
typealias BaseAndP2<T> = Base<T> & P2
typealias BaseIntAndP2 = BaseAndP2<Int>
class Derived : Base<Int>, P2 {
required init(protocolInit: ()) {
super.init(classInit: ())
}
required init(classInit: ()) {
super.init(classInit: ())
}
func protocolSelfReturn() -> Self {}
}
class Other : Base<Int> {}
typealias OtherAndP2 = Other & P2
protocol P3 : class {}
struct Unrelated {}
//
// If a class conforms to a protocol concretely, the resulting protocol
// composition type should be equivalent to the class type.
//
// FIXME: Not implemented yet.
//
func alreadyConforms<T>(_: Base<T>) {} // expected-note {{'alreadyConforms' previously declared here}}
func alreadyConforms<T>(_: Base<T> & P1) {} // expected-note {{'alreadyConforms' previously declared here}}
func alreadyConforms<T>(_: Base<T> & AnyObject) {} // expected-error {{invalid redeclaration of 'alreadyConforms'}}
func alreadyConforms<T>(_: Base<T> & P1 & AnyObject) {} // expected-error {{invalid redeclaration of 'alreadyConforms'}}
func alreadyConforms(_: P3) {}
func alreadyConforms(_: P3 & AnyObject) {}
// SE-0156 stipulates that a composition can contain multiple classes, as long
// as they are all the same.
func basicDiagnostics(
_: Base<Int> & Base<Int>,
_: Base<Int> & Derived, // expected-error{{protocol-constrained type cannot contain class 'Derived' because it already contains class 'Base<Int>'}}
// Invalid typealias case
_: Derived & OtherAndP2, // expected-error{{protocol-constrained type cannot contain class 'Other' because it already contains class 'Derived'}}
// Valid typealias case
_: OtherAndP2 & P3) {}
// A composition containing only a single class is actually identical to
// the class type itself.
struct Box<T : Base<Int>> {}
func takesBox(_: Box<Base<Int>>) {}
func passesBox(_ b: Box<Base<Int> & Base<Int>>) {
takesBox(b)
}
// Test that subtyping behaves as you would expect.
func basicSubtyping(
base: Base<Int>,
baseAndP1: Base<Int> & P1,
baseAndP2: Base<Int> & P2,
baseAndP2AndAnyObject: Base<Int> & P2 & AnyObject,
baseAndAnyObject: Base<Int> & AnyObject,
derived: Derived,
derivedAndP2: Derived & P2,
derivedAndP3: Derived & P3,
derivedAndAnyObject: Derived & AnyObject,
p1AndAnyObject: P1 & AnyObject,
p2AndAnyObject: P2 & AnyObject,
anyObject: AnyObject) {
// Errors
let _: Base & P2 = base // expected-error {{value of type 'Base<Int>' does not conform to specified type 'Base & P2'}}
let _: Base<Int> & P2 = base // expected-error {{value of type 'Base<Int>' does not conform to specified type 'Base<Int> & P2'}}
let _: P3 = baseAndP1 // expected-error {{value of type 'Base<Int> & P1' does not conform to specified type 'P3'}}
let _: P3 = baseAndP2 // expected-error {{value of type 'Base<Int> & P2' does not conform to specified type 'P3'}}
let _: Derived = baseAndP1 // expected-error {{cannot convert value of type 'Base<Int> & P1' to specified type 'Derived'}}
let _: Derived = baseAndP2 // expected-error {{cannot convert value of type 'Base<Int> & P2' to specified type 'Derived'}}
let _: Derived & P2 = baseAndP2 // expected-error {{value of type 'Base<Int> & P2' does not conform to specified type 'Derived & P2'}}
let _ = Unrelated() as Derived & P2 // expected-error {{value of type 'Unrelated' does not conform to 'Derived & P2' in coercion}}
let _ = Unrelated() as? Derived & P2 // expected-warning {{always fails}}
let _ = baseAndP2 as Unrelated // expected-error {{cannot convert value of type 'Base<Int> & P2' to type 'Unrelated' in coercion}}
let _ = baseAndP2 as? Unrelated // expected-warning {{always fails}}
// Different behavior on Linux vs Darwin because of id-as-Any.
// let _ = Unrelated() as AnyObject
// let _ = Unrelated() as? AnyObject
let _ = anyObject as Unrelated // expected-error {{'AnyObject' is not convertible to 'Unrelated'; did you mean to use 'as!' to force downcast?}}
let _ = anyObject as? Unrelated
// No-ops
let _: Base & P1 = base
let _: Base<Int> & P1 = base
let _: Base & AnyObject = base
let _: Base<Int> & AnyObject = base
let _: Derived & AnyObject = derived
let _ = base as Base<Int> & P1
let _ = base as Base<Int> & AnyObject
let _ = derived as Derived & AnyObject
let _ = base as? Base<Int> & P1 // expected-warning {{always succeeds}}
let _ = base as? Base<Int> & AnyObject // expected-warning {{always succeeds}}
let _ = derived as? Derived & AnyObject // expected-warning {{always succeeds}}
// Erasing superclass constraint
let _: P1 = baseAndP1
let _: P1 & AnyObject = baseAndP1
let _: P1 = derived
let _: P1 & AnyObject = derived
let _: AnyObject = baseAndP1
let _: AnyObject = baseAndP2
let _: AnyObject = derived
let _: AnyObject = derivedAndP2
let _: AnyObject = derivedAndP3
let _: AnyObject = derivedAndAnyObject
let _ = baseAndP1 as P1
let _ = baseAndP1 as P1 & AnyObject
let _ = derived as P1
let _ = derived as P1 & AnyObject
let _ = baseAndP1 as AnyObject
let _ = derivedAndAnyObject as AnyObject
let _ = baseAndP1 as? P1 // expected-warning {{always succeeds}}
let _ = baseAndP1 as? P1 & AnyObject // expected-warning {{always succeeds}}
let _ = derived as? P1 // expected-warning {{always succeeds}}
let _ = derived as? P1 & AnyObject // expected-warning {{always succeeds}}
let _ = baseAndP1 as? AnyObject // expected-warning {{always succeeds}}
let _ = derivedAndAnyObject as? AnyObject // expected-warning {{always succeeds}}
// Erasing conformance constraint
let _: Base = baseAndP1
let _: Base<Int> = baseAndP1
let _: Base = derivedAndP3
let _: Base<Int> = derivedAndP3
let _: Derived = derivedAndP2
let _: Derived = derivedAndAnyObject
let _ = baseAndP1 as Base<Int>
let _ = derivedAndP3 as Base<Int>
let _ = derivedAndP2 as Derived
let _ = derivedAndAnyObject as Derived
let _ = baseAndP1 as? Base<Int> // expected-warning {{always succeeds}}
let _ = derivedAndP3 as? Base<Int> // expected-warning {{always succeeds}}
let _ = derivedAndP2 as? Derived // expected-warning {{always succeeds}}
let _ = derivedAndAnyObject as? Derived // expected-warning {{always succeeds}}
// Upcasts
let _: Base & P2 = derived
let _: Base<Int> & P2 = derived
let _: Base & P2 & AnyObject = derived
let _: Base<Int> & P2 & AnyObject = derived
let _: Base & P3 = derivedAndP3
let _: Base<Int> & P3 = derivedAndP3
let _ = derived as Base<Int> & P2
let _ = derived as Base<Int> & P2 & AnyObject
let _ = derivedAndP3 as Base<Int> & P3
let _ = derived as? Base<Int> & P2 // expected-warning {{always succeeds}}
let _ = derived as? Base<Int> & P2 & AnyObject // expected-warning {{always succeeds}}
let _ = derivedAndP3 as? Base<Int> & P3 // expected-warning {{always succeeds}}
// Calling methods with Self return
let _: Base & P2 = baseAndP2.classSelfReturn()
let _: Base<Int> & P2 = baseAndP2.classSelfReturn()
let _: Base & P2 = baseAndP2.protocolSelfReturn()
let _: Base<Int> & P2 = baseAndP2.protocolSelfReturn()
// Downcasts
let _ = baseAndP2 as Derived // expected-error {{did you mean to use 'as!' to force downcast?}}
let _ = baseAndP2 as? Derived
let _ = baseAndP2 as Derived & P3 // expected-error {{did you mean to use 'as!' to force downcast?}}
let _ = baseAndP2 as? Derived & P3
let _ = base as Derived & P2 // expected-error {{did you mean to use 'as!' to force downcast?}}
let _ = base as? Derived & P2
// Invalid cases
let _ = derived as Other & P2 // expected-error {{value of type 'Derived' does not conform to 'Other & P2' in coercion}}
let _ = derived as? Other & P2 // expected-warning {{always fails}}
let _ = derivedAndP3 as Other // expected-error {{cannot convert value of type 'Derived & P3' to type 'Other' in coercion}}
let _ = derivedAndP3 as? Other // expected-warning {{always fails}}
let _ = derivedAndP3 as Other & P3 // expected-error {{value of type 'Derived & P3' does not conform to 'Other & P3' in coercion}}
let _ = derivedAndP3 as? Other & P3 // expected-warning {{always fails}}
let _ = derived as Other // expected-error {{cannot convert value of type 'Derived' to type 'Other' in coercion}}
let _ = derived as? Other // expected-warning {{always fails}}
}
// Test conversions in return statements
func eraseProtocolInReturn(baseAndP2: Base<Int> & P2) -> Base<Int> {
return baseAndP2
}
func eraseProtocolInReturn(baseAndP2: (Base<Int> & P2)!) -> Base<Int> {
return baseAndP2
}
func eraseProtocolInReturn(baseAndP2: Base<Int> & P2) -> Base<Int>? {
return baseAndP2
}
func eraseClassInReturn(baseAndP2: Base<Int> & P2) -> P2 {
return baseAndP2
}
func eraseClassInReturn(baseAndP2: (Base<Int> & P2)!) -> P2 {
return baseAndP2
}
func eraseClassInReturn(baseAndP2: Base<Int> & P2) -> P2? {
return baseAndP2
}
func upcastToExistentialInReturn(derived: Derived) -> Base<Int> & P2 {
return derived
}
func upcastToExistentialInReturn(derived: Derived!) -> Base<Int> & P2 {
return derived
}
func upcastToExistentialInReturn(derived: Derived) -> (Base<Int> & P2)? {
return derived
}
func takesBase<T>(_: Base<T>) {}
func takesP2(_: P2) {}
func takesBaseMetatype<T>(_: Base<T>.Type) {}
func takesP2Metatype(_: P2.Type) {}
func takesBaseIntAndP2(_ x: Base<Int> & P2) {
takesBase(x)
takesP2(x)
}
func takesBaseIntAndP2Metatype(_ x: (Base<Int> & P2).Type) {
takesBaseMetatype(x)
takesP2Metatype(x)
}
func takesDerived(x: Derived) {
takesBaseIntAndP2(x)
}
func takesDerivedMetatype(x: Derived.Type) {
takesBaseIntAndP2Metatype(x)
}
//
// Looking up member types of subclass existentials.
//
func dependentMemberTypes<T : BaseIntAndP2>(
_: T.DependentInConcreteConformance,
_: T.DependentProtocol,
_: T.DependentClass,
_: T.FullyConcrete,
_: BaseIntAndP2.DependentInConcreteConformance, // FIXME expected-error {{}}
_: BaseIntAndP2.DependentProtocol, // expected-error {{type alias 'DependentProtocol' can only be used with a concrete type or generic parameter base}}
_: BaseIntAndP2.DependentClass,
_: BaseIntAndP2.FullyConcrete) {}
func conformsToAnyObject<T : AnyObject>(_: T) {}
func conformsToP1<T : P1>(_: T) {}
func conformsToP2<T : P2>(_: T) {}
func conformsToBaseIntAndP2<T : Base<Int> & P2>(_: T) {}
// expected-note@-1 2 {{where 'T' = 'Base<String>'}}
// expected-note@-2 {{where 'T' = 'Base<Int>'}}
func conformsToBaseIntAndP2WithWhereClause<T>(_: T) where T : Base<Int> & P2 {}
// expected-note@-1 {{where 'T' = 'Base<String>'}}
// expected-note@-2 {{where 'T' = 'Base<Int>'}}
class FakeDerived : Base<String>, P2 {
required init(classInit: ()) {
super.init(classInit: ())
}
required init(protocolInit: ()) {
super.init(classInit: ())
}
func protocolSelfReturn() -> Self { return self }
}
//
// Metatype subtyping.
//
func metatypeSubtyping(
base: Base<Int>.Type,
derived: Derived.Type,
derivedAndAnyObject: (Derived & AnyObject).Type,
baseIntAndP2: (Base<Int> & P2).Type,
baseIntAndP2AndAnyObject: (Base<Int> & P2 & AnyObject).Type) {
// Erasing conformance constraint
let _: Base<Int>.Type = baseIntAndP2
let _: Base<Int>.Type = baseIntAndP2AndAnyObject
let _: Derived.Type = derivedAndAnyObject
let _: BaseAndP2<Int>.Type = baseIntAndP2AndAnyObject
let _ = baseIntAndP2 as Base<Int>.Type
let _ = baseIntAndP2AndAnyObject as Base<Int>.Type
let _ = derivedAndAnyObject as Derived.Type
let _ = baseIntAndP2AndAnyObject as BaseAndP2<Int>.Type
let _ = baseIntAndP2 as? Base<Int>.Type // expected-warning {{always succeeds}}
let _ = baseIntAndP2AndAnyObject as? Base<Int>.Type // expected-warning {{always succeeds}}
let _ = derivedAndAnyObject as? Derived.Type // expected-warning {{always succeeds}}
let _ = baseIntAndP2AndAnyObject as? BaseAndP2<Int>.Type // expected-warning {{always succeeds}}
// Upcast
let _: BaseAndP2<Int>.Type = derived
let _: BaseAndP2<Int>.Type = derivedAndAnyObject
let _ = derived as BaseAndP2<Int>.Type
let _ = derivedAndAnyObject as BaseAndP2<Int>.Type
let _ = derived as? BaseAndP2<Int>.Type // expected-warning {{always succeeds}}
let _ = derivedAndAnyObject as? BaseAndP2<Int>.Type // expected-warning {{always succeeds}}
// Erasing superclass constraint
let _: P2.Type = baseIntAndP2
let _: P2.Type = derived
let _: P2.Type = derivedAndAnyObject
let _: (P2 & AnyObject).Type = derived
let _: (P2 & AnyObject).Type = derivedAndAnyObject
let _ = baseIntAndP2 as P2.Type
let _ = derived as P2.Type
let _ = derivedAndAnyObject as P2.Type
let _ = derived as (P2 & AnyObject).Type
let _ = derivedAndAnyObject as (P2 & AnyObject).Type
let _ = baseIntAndP2 as? P2.Type // expected-warning {{always succeeds}}
let _ = derived as? P2.Type // expected-warning {{always succeeds}}
let _ = derivedAndAnyObject as? P2.Type // expected-warning {{always succeeds}}
let _ = derived as? (P2 & AnyObject).Type // expected-warning {{always succeeds}}
let _ = derivedAndAnyObject as? (P2 & AnyObject).Type // expected-warning {{always succeeds}}
// Initializers
let _: Base<Int> & P2 = baseIntAndP2.init(classInit: ())
let _: Base<Int> & P2 = baseIntAndP2.init(protocolInit: ())
let _: Base<Int> & P2 & AnyObject = baseIntAndP2AndAnyObject.init(classInit: ())
let _: Base<Int> & P2 & AnyObject = baseIntAndP2AndAnyObject.init(protocolInit: ())
let _: Derived = derived.init(classInit: ())
let _: Derived = derived.init(protocolInit: ())
let _: Derived & AnyObject = derivedAndAnyObject.init(classInit: ())
let _: Derived & AnyObject = derivedAndAnyObject.init(protocolInit: ())
}
//
// Conformance relation.
//
func conformsTo<T1 : P2, T2 : Base<Int> & P2>(
anyObject: AnyObject,
p1: P1,
p2: P2,
p3: P3,
base: Base<Int>,
badBase: Base<String>,
derived: Derived,
fakeDerived: FakeDerived,
p2Archetype: T1,
baseAndP2Archetype: T2) {
// FIXME: Uninformative diagnostics
// Errors
conformsToAnyObject(p1)
// expected-error@-1 {{cannot invoke 'conformsToAnyObject' with an argument list of type '(P1)'}}
// expected-note@-2 {{expected an argument list of type '(T)'}}
conformsToP1(p1)
// expected-error@-1 {{protocol type 'P1' cannot conform to 'P1' because only concrete types can conform to protocols}}
// FIXME: Following diagnostics are not great because when
// `conformsTo*` methods are re-typechecked, they loose information
// about `& P2` in generic parameter.
conformsToBaseIntAndP2(base)
// expected-error@-1 {{argument type 'Base<Int>' does not conform to expected type 'P2'}}
conformsToBaseIntAndP2(badBase)
// expected-error@-1 {{global function 'conformsToBaseIntAndP2' requires that 'Base<String>' inherit from 'Base<Int>'}}
// expected-error@-2 {{argument type 'Base<String>' does not conform to expected type 'P2'}}
conformsToBaseIntAndP2(fakeDerived)
// expected-error@-1 {{global function 'conformsToBaseIntAndP2' requires that 'Base<String>' inherit from 'Base<Int>'}}
conformsToBaseIntAndP2WithWhereClause(fakeDerived)
// expected-error@-1 {{global function 'conformsToBaseIntAndP2WithWhereClause' requires that 'Base<String>' inherit from 'Base<Int>'}}
conformsToBaseIntAndP2(p2Archetype)
// expected-error@-1 {{global function 'conformsToBaseIntAndP2' requires that 'Base<Int>' conform to 'P2'}}
conformsToBaseIntAndP2WithWhereClause(p2Archetype)
// expected-error@-1 {{global function 'conformsToBaseIntAndP2WithWhereClause' requires that 'Base<Int>' conform to 'P2'}}
// Good
conformsToAnyObject(anyObject)
conformsToAnyObject(baseAndP2Archetype)
conformsToP1(derived)
conformsToP1(baseAndP2Archetype)
conformsToP2(derived)
conformsToP2(baseAndP2Archetype)
conformsToBaseIntAndP2(derived)
conformsToBaseIntAndP2(baseAndP2Archetype)
conformsToBaseIntAndP2WithWhereClause(derived)
conformsToBaseIntAndP2WithWhereClause(baseAndP2Archetype)
}
// Subclass existentials inside inheritance clauses
class CompositionInClassInheritanceClauseAlias : BaseIntAndP2 {
required init(classInit: ()) {
super.init(classInit: ())
}
required init(protocolInit: ()) {
super.init(classInit: ())
}
func protocolSelfReturn() -> Self { return self }
func asBase() -> Base<Int> { return self }
}
class CompositionInClassInheritanceClauseDirect : Base<Int> & P2 {
required init(classInit: ()) {
super.init(classInit: ())
}
required init(protocolInit: ()) {
super.init(classInit: ())
}
func protocolSelfReturn() -> Self { return self }
func asBase() -> Base<Int> { return self }
}
protocol CompositionInAssociatedTypeInheritanceClause {
associatedtype A : BaseIntAndP2
}
// Members of metatypes and existential metatypes
protocol ProtocolWithStaticMember {
static func staticProtocolMember()
func instanceProtocolMember()
}
class ClassWithStaticMember {
static func staticClassMember() {}
func instanceClassMember() {}
}
func staticMembers(
m1: (ProtocolWithStaticMember & ClassWithStaticMember).Protocol,
m2: (ProtocolWithStaticMember & ClassWithStaticMember).Type) {
_ = m1.staticProtocolMember() // expected-error {{static member 'staticProtocolMember' cannot be used on protocol metatype '(ClassWithStaticMember & ProtocolWithStaticMember).Protocol'}}
_ = m1.staticProtocolMember // expected-error {{static member 'staticProtocolMember' cannot be used on protocol metatype '(ClassWithStaticMember & ProtocolWithStaticMember).Protocol'}}
_ = m1.staticClassMember() // expected-error {{static member 'staticClassMember' cannot be used on protocol metatype '(ClassWithStaticMember & ProtocolWithStaticMember).Protocol'}}
_ = m1.staticClassMember // expected-error {{static member 'staticClassMember' cannot be used on protocol metatype '(ClassWithStaticMember & ProtocolWithStaticMember).Protocol'}}
_ = m1.instanceProtocolMember
_ = m1.instanceClassMember
_ = m2.staticProtocolMember()
_ = m2.staticProtocolMember
_ = m2.staticClassMember()
_ = m2.staticClassMember
_ = m2.instanceProtocolMember // expected-error {{instance member 'instanceProtocolMember' cannot be used on type 'ClassWithStaticMember & ProtocolWithStaticMember'}}
_ = m2.instanceClassMember // expected-error {{instance member 'instanceClassMember' cannot be used on type 'ClassWithStaticMember & ProtocolWithStaticMember'}}
}
// Make sure we correctly form subclass existentials in expression context.
func takesBaseIntAndPArray(_: [Base<Int> & P2]) {}
func passesBaseIntAndPArray() {
takesBaseIntAndPArray([Base<Int> & P2]())
}
//
// Superclass constrained generic parameters
//
struct DerivedBox<T : Derived> {}
// expected-note@-1 {{requirement specified as 'T' : 'Derived' [with T = Derived & P3]}}
func takesBoxWithP3(_: DerivedBox<Derived & P3>) {}
// expected-error@-1 {{'DerivedBox' requires that 'Derived & P3' inherit from 'Derived'}}