mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
Resolving only a structural type meant we weren't checking generic constraints, allowing invalid extensions to get past the type-checker. Change to resolve an interface type.
254 lines
5.3 KiB
Swift
254 lines
5.3 KiB
Swift
// RUN: %target-typecheck-verify-swift
|
|
|
|
protocol P1 { associatedtype AssocType }
|
|
protocol P2 : P1 { }
|
|
protocol P3 { }
|
|
|
|
struct X<T : P1, U : P2, V> {
|
|
struct Inner<A, B : P3> { }
|
|
|
|
struct NonGenericInner { }
|
|
}
|
|
|
|
extension Int : P1 {
|
|
typealias AssocType = Int
|
|
}
|
|
|
|
extension Double : P2 {
|
|
typealias AssocType = Double
|
|
}
|
|
|
|
extension X<Int, Double, String> {
|
|
let x = 0
|
|
// expected-error@-1 {{extensions must not contain stored properties}}
|
|
static let x = 0
|
|
func f() -> Int {}
|
|
class C<W> {}
|
|
}
|
|
|
|
typealias GGG = X<Int, Double, String>
|
|
|
|
extension GGG { } // okay through a typealias
|
|
|
|
// Lvalue check when the archetypes are not the same.
|
|
struct LValueCheck<T> {
|
|
let x = 0
|
|
}
|
|
|
|
extension LValueCheck {
|
|
init(newY: Int) {
|
|
x = 42
|
|
}
|
|
}
|
|
|
|
// Member type references into another extension.
|
|
struct MemberTypeCheckA<T> { }
|
|
|
|
protocol MemberTypeProto {
|
|
associatedtype AssocType
|
|
|
|
func foo(_ a: AssocType)
|
|
init(_ assoc: MemberTypeCheckA<AssocType>)
|
|
}
|
|
|
|
struct MemberTypeCheckB<T> : MemberTypeProto {
|
|
func foo(_ a: T) {}
|
|
|
|
typealias Element = T
|
|
var t1: T
|
|
}
|
|
|
|
extension MemberTypeCheckB {
|
|
typealias Underlying = MemberTypeCheckA<T>
|
|
}
|
|
|
|
extension MemberTypeCheckB {
|
|
init(_ x: Underlying) { }
|
|
}
|
|
|
|
extension MemberTypeCheckB {
|
|
var t2: Element { return t1 }
|
|
}
|
|
|
|
// rdar://problem/19795284
|
|
extension Array {
|
|
var pairs: [(Element, Element)] {
|
|
get {
|
|
return []
|
|
}
|
|
}
|
|
}
|
|
|
|
// rdar://problem/21001937
|
|
struct GenericOverloads<T, U> {
|
|
var t: T
|
|
var u: U
|
|
|
|
init(t: T, u: U) { self.t = t; self.u = u }
|
|
|
|
func foo() { }
|
|
|
|
var prop: Int { return 0 }
|
|
|
|
subscript (i: Int) -> Int { return i }
|
|
}
|
|
|
|
extension GenericOverloads where T : P1, U : P2 {
|
|
init(t: T, u: U) { self.t = t; self.u = u }
|
|
|
|
func foo() { }
|
|
|
|
var prop: Int { return 1 }
|
|
|
|
subscript (i: Int) -> Int { return i }
|
|
}
|
|
|
|
extension Array where Element : Hashable { // expected-note {{where 'Element' = 'T'}}
|
|
var worseHashEver: Int {
|
|
var result = 0
|
|
for elt in self {
|
|
result = (result << 1) ^ elt.hashValue
|
|
}
|
|
return result
|
|
}
|
|
}
|
|
|
|
func notHashableArray<T>(_ x: [T]) {
|
|
x.worseHashEver // expected-error{{property 'worseHashEver' requires that 'T' conform to 'Hashable'}}
|
|
}
|
|
|
|
func hashableArray<T : Hashable>(_ x: [T]) {
|
|
// expected-warning @+1 {{unused}}
|
|
x.worseHashEver // okay
|
|
}
|
|
|
|
func intArray(_ x: [Int]) {
|
|
// expected-warning @+1 {{unused}}
|
|
x.worseHashEver
|
|
}
|
|
|
|
class GenericClass<T> { }
|
|
|
|
extension GenericClass where T : Equatable { // expected-note {{where 'T' = 'T'}}
|
|
func foo(_ x: T, y: T) -> Bool { return x == y }
|
|
}
|
|
|
|
func genericClassEquatable<T : Equatable>(_ gc: GenericClass<T>, x: T, y: T) {
|
|
_ = gc.foo(x, y: y)
|
|
}
|
|
|
|
func genericClassNotEquatable<T>(_ gc: GenericClass<T>, x: T, y: T) {
|
|
gc.foo(x, y: y) // expected-error{{referencing instance method 'foo(_:y:)' on 'GenericClass' requires that 'T' conform to 'Equatable'}}
|
|
}
|
|
|
|
|
|
extension Array where Element == String { }
|
|
|
|
extension GenericClass : P3 where T : P3 { }
|
|
|
|
extension GenericClass where Self : P3 { }
|
|
// expected-error@-1{{covariant 'Self' or 'Self?' can only appear as the type of a property, subscript or method result; did you mean 'GenericClass'?}} {{30-34=GenericClass}}
|
|
|
|
protocol P4 {
|
|
associatedtype T
|
|
init(_: T)
|
|
}
|
|
|
|
protocol P5 { }
|
|
|
|
struct S4<Q>: P4 {
|
|
init(_: Q) { }
|
|
}
|
|
|
|
extension S4 where T : P5 {}
|
|
|
|
struct S5<Q> {
|
|
init(_: Q) { }
|
|
}
|
|
|
|
extension S5 : P4 {}
|
|
|
|
// rdar://problem/21607421
|
|
public typealias Array2 = Array
|
|
extension Array2 where QQQ : VVV {}
|
|
// expected-error@-1 {{cannot find type 'QQQ' in scope}}
|
|
// expected-error@-2 {{cannot find type 'VVV' in scope}}
|
|
|
|
// https://github.com/apple/swift/issues/51512
|
|
func foo() {
|
|
extension Array where Element : P1 {
|
|
// expected-error@-1 {{declaration is only valid at file scope}}
|
|
func foo() -> Element.AssocType {}
|
|
}
|
|
}
|
|
|
|
// Deeply nested
|
|
protocol P6 {
|
|
associatedtype Assoc1
|
|
associatedtype Assoc2
|
|
}
|
|
|
|
struct A<T, U, V> {
|
|
struct B<W, X, Y> {
|
|
struct C<Z: P6> {
|
|
}
|
|
}
|
|
}
|
|
|
|
extension A.B.C where T == V, X == Z.Assoc2 {
|
|
func f() { }
|
|
}
|
|
|
|
// Extensions of nested non-generics within generics.
|
|
extension A.B {
|
|
struct D { }
|
|
}
|
|
|
|
extension A.B.D {
|
|
func g() { }
|
|
}
|
|
|
|
// rdar://problem/43955962
|
|
struct OldGeneric<T> {}
|
|
typealias NewGeneric<T> = OldGeneric<T>
|
|
|
|
extension NewGeneric {
|
|
static func oldMember() -> OldGeneric {
|
|
return OldGeneric()
|
|
}
|
|
|
|
static func newMember() -> NewGeneric {
|
|
return NewGeneric()
|
|
}
|
|
}
|
|
extension (NewGeneric) {
|
|
static func oldMember2() -> OldGeneric {
|
|
return OldGeneric()
|
|
}
|
|
|
|
static func newMember2() -> NewGeneric {
|
|
return NewGeneric()
|
|
}
|
|
}
|
|
|
|
protocol P7 {}
|
|
extension Float: P7 {}
|
|
|
|
protocol Q1 {
|
|
associatedtype X
|
|
func foo(_ x: X)
|
|
}
|
|
struct S7<T: P7>: Q1 {
|
|
func foo(_ x: T) {}
|
|
}
|
|
|
|
// Make sure we reject these extensions.
|
|
extension S7<Int> {} // expected-error {{type 'Int' does not conform to protocol 'P7'}}
|
|
extension [S7<Int>] {} // expected-error {{type 'Int' does not conform to protocol 'P7'}}
|
|
extension Array<S7<Int>> {} // expected-error {{type 'Int' does not conform to protocol 'P7'}}
|
|
extension S7<Int>? {} // expected-error {{type 'Int' does not conform to protocol 'P7'}}
|
|
extension S7<Int>.X {} // expected-error {{type 'Int' does not conform to protocol 'P7'}}
|
|
extension S7<Float>.X {} // expected-error {{extension of type 'S7<Float>.X' (aka 'Float') must be declared as an extension of 'Float'}}
|
|
// expected-note@-1 {{did you mean to extend 'Float' instead?}}
|
|
extension S7<T> {} // expected-error {{cannot find type 'T' in scope}}
|