mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Fixes a problem related to presence of InOutType in function parameters which diagnostics related to generic parameter requirements didn't handle correctly, and improves diagnostics for unsatisfied generic requirements in operator applications, which we didn't attempt to diagnose at all. Resolves: rdar://problem/33477726
343 lines
12 KiB
Swift
343 lines
12 KiB
Swift
// RUN: %target-typecheck-verify-swift
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Deduction of generic arguments
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
func identity<T>(_ value: T) -> T { return value }
|
|
|
|
func identity2<T>(_ value: T) -> T { return value }
|
|
func identity2<T>(_ value: T) -> Int { return 0 }
|
|
|
|
struct X { }
|
|
struct Y { }
|
|
|
|
func useIdentity(_ x: Int, y: Float, i32: Int32) {
|
|
var x2 = identity(x)
|
|
var y2 = identity(y)
|
|
|
|
// Deduction that involves the result type
|
|
x2 = identity(17)
|
|
var i32_2 : Int32 = identity(17)
|
|
|
|
// Deduction where the result type and input type can get different results
|
|
var xx : X, yy : Y
|
|
xx = identity(yy) // expected-error{{cannot assign value of type 'Y' to type 'X'}}
|
|
xx = identity2(yy) // expected-error{{cannot convert value of type 'Y' to expected argument type 'X'}}
|
|
}
|
|
|
|
// FIXME: Crummy diagnostic!
|
|
func twoIdentical<T>(_ x: T, _ y: T) -> T {}
|
|
|
|
func useTwoIdentical(_ xi: Int, yi: Float) {
|
|
var x = xi, y = yi
|
|
x = twoIdentical(x, x)
|
|
y = twoIdentical(y, y)
|
|
x = twoIdentical(x, 1)
|
|
x = twoIdentical(1, x)
|
|
y = twoIdentical(1.0, y)
|
|
y = twoIdentical(y, 1.0)
|
|
|
|
twoIdentical(x, y) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}}
|
|
}
|
|
|
|
func mySwap<T>(_ x: inout T,
|
|
_ y: inout T) {
|
|
let tmp = x
|
|
x = y
|
|
y = tmp
|
|
}
|
|
|
|
func useSwap(_ xi: Int, yi: Float) {
|
|
var x = xi, y = yi
|
|
mySwap(&x, &x)
|
|
mySwap(&y, &y)
|
|
|
|
mySwap(x, x) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}} {{10-10=&}}
|
|
// expected-error @-1 {{passing value of type 'Int' to an inout parameter requires explicit '&'}} {{13-13=&}}
|
|
|
|
mySwap(&x, &y) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}}
|
|
}
|
|
|
|
func takeTuples<T, U>(_: (T, U), _: (U, T)) {
|
|
}
|
|
|
|
func useTuples(_ x: Int, y: Float, z: (Float, Int)) {
|
|
takeTuples((x, y), (y, x))
|
|
|
|
takeTuples((x, y), (x, y)) // expected-error{{cannot convert value of type 'Int' to expected argument type 'Float'}}
|
|
|
|
// FIXME: Use 'z', which requires us to fix our tuple-conversion
|
|
// representation.
|
|
}
|
|
|
|
func acceptFunction<T, U>(_ f: (T) -> U, _ t: T, _ u: U) {}
|
|
|
|
func passFunction(_ f: (Int) -> Float, x: Int, y: Float) {
|
|
acceptFunction(f, x, y)
|
|
acceptFunction(f, y, y) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}}
|
|
}
|
|
|
|
func returnTuple<T, U>(_: T) -> (T, U) { } // expected-note {{in call to function 'returnTuple'}}
|
|
|
|
func testReturnTuple(_ x: Int, y: Float) {
|
|
returnTuple(x) // expected-error{{generic parameter 'U' could not be inferred}}
|
|
|
|
var _ : (Int, Float) = returnTuple(x)
|
|
var _ : (Float, Float) = returnTuple(y)
|
|
|
|
// <rdar://problem/22333090> QoI: Propagate contextual information in a call to operands
|
|
var _ : (Int, Float) = returnTuple(y) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}}
|
|
}
|
|
|
|
|
|
func confusingArgAndParam<T, U>(_ f: (T) -> U, _ g: (U) -> T) {
|
|
confusingArgAndParam(g, f)
|
|
confusingArgAndParam(f, g)
|
|
}
|
|
|
|
func acceptUnaryFn<T, U>(_ f: (T) -> U) { }
|
|
func acceptUnaryFnSame<T>(_ f: (T) -> T) { }
|
|
|
|
func acceptUnaryFnRef<T, U>(_ f: inout (T) -> U) { }
|
|
func acceptUnaryFnSameRef<T>(_ f: inout (T) -> T) { }
|
|
|
|
func unaryFnIntInt(_: Int) -> Int {}
|
|
|
|
func unaryFnOvl(_: Int) -> Int {} // expected-note{{found this candidate}}
|
|
func unaryFnOvl(_: Float) -> Int {} // expected-note{{found this candidate}}
|
|
|
|
// Variable forms of the above functions
|
|
var unaryFnIntIntVar : (Int) -> Int = unaryFnIntInt
|
|
|
|
func passOverloadSet() {
|
|
// Passing a non-generic function to a generic function
|
|
acceptUnaryFn(unaryFnIntInt)
|
|
acceptUnaryFnSame(unaryFnIntInt)
|
|
|
|
// Passing an overloaded function set to a generic function
|
|
// FIXME: Yet more terrible diagnostics.
|
|
acceptUnaryFn(unaryFnOvl) // expected-error{{ambiguous use of 'unaryFnOvl'}}
|
|
acceptUnaryFnSame(unaryFnOvl)
|
|
|
|
// Passing a variable of function type to a generic function
|
|
acceptUnaryFn(unaryFnIntIntVar)
|
|
acceptUnaryFnSame(unaryFnIntIntVar)
|
|
|
|
// Passing a variable of function type to a generic function to an inout parameter
|
|
acceptUnaryFnRef(&unaryFnIntIntVar)
|
|
acceptUnaryFnSameRef(&unaryFnIntIntVar)
|
|
|
|
acceptUnaryFnRef(unaryFnIntIntVar) // expected-error{{passing value of type '(Int) -> Int' to an inout parameter requires explicit '&'}} {{20-20=&}}
|
|
}
|
|
|
|
func acceptFnFloatFloat(_ f: (Float) -> Float) {}
|
|
func acceptFnDoubleDouble(_ f: (Double) -> Double) {}
|
|
|
|
func passGeneric() {
|
|
acceptFnFloatFloat(identity)
|
|
acceptFnFloatFloat(identity2)
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Simple deduction for generic member functions
|
|
//===----------------------------------------------------------------------===//
|
|
struct SomeType {
|
|
func identity<T>(_ x: T) -> T { return x }
|
|
|
|
func identity2<T>(_ x: T) -> T { return x } // expected-note 2{{found this candidate}}
|
|
func identity2<T>(_ x: T) -> Float { } // expected-note 2{{found this candidate}}
|
|
|
|
func returnAs<T>() -> T {}
|
|
}
|
|
|
|
func testMemberDeduction(_ sti: SomeType, ii: Int, fi: Float) {
|
|
var st = sti, i = ii, f = fi
|
|
i = st.identity(i)
|
|
f = st.identity(f)
|
|
i = st.identity2(i)
|
|
f = st.identity2(f) // expected-error{{ambiguous use of 'identity2'}}
|
|
i = st.returnAs()
|
|
f = st.returnAs()
|
|
acceptFnFloatFloat(st.identity)
|
|
acceptFnFloatFloat(st.identity2) // expected-error{{ambiguous use of 'identity2'}}
|
|
acceptFnDoubleDouble(st.identity2)
|
|
}
|
|
|
|
struct StaticFuncs {
|
|
static func chameleon<T>() -> T {}
|
|
func chameleon2<T>() -> T {}
|
|
}
|
|
|
|
struct StaticFuncsGeneric<U> {
|
|
// FIXME: Nested generics are very broken
|
|
// static func chameleon<T>() -> T {}
|
|
}
|
|
|
|
func chameleon<T>() -> T {}
|
|
|
|
func testStatic(_ sf: StaticFuncs, sfi: StaticFuncsGeneric<Int>) {
|
|
var x: Int16
|
|
x = StaticFuncs.chameleon()
|
|
x = sf.chameleon2()
|
|
// FIXME: Nested generics are very broken
|
|
// x = sfi.chameleon()
|
|
// typealias SFI = StaticFuncsGeneric<Int>
|
|
// x = SFI.chameleon()
|
|
_ = x
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Deduction checking for constraints
|
|
//===----------------------------------------------------------------------===//
|
|
protocol IsBefore {
|
|
func isBefore(_ other: Self) -> Bool
|
|
}
|
|
|
|
func min2<T : IsBefore>(_ x: T, _ y: T) -> T {
|
|
if y.isBefore(x) { return y }
|
|
return x
|
|
}
|
|
|
|
extension Int : IsBefore {
|
|
func isBefore(_ other: Int) -> Bool { return self < other }
|
|
}
|
|
|
|
func callMin(_ x: Int, y: Int, a: Float, b: Float) {
|
|
_ = min2(x, y)
|
|
min2(a, b) // expected-error{{argument type 'Float' does not conform to expected type 'IsBefore'}}
|
|
}
|
|
|
|
func rangeOfIsBefore<R : IteratorProtocol>(_ range: R) where R.Element : IsBefore {}
|
|
|
|
func callRangeOfIsBefore(_ ia: [Int], da: [Double]) {
|
|
rangeOfIsBefore(ia.makeIterator())
|
|
rangeOfIsBefore(da.makeIterator()) // expected-error{{type 'Double' does not conform to protocol 'IsBefore'}}
|
|
}
|
|
|
|
func testEqualIterElementTypes<A: IteratorProtocol, B: IteratorProtocol>(_ a: A, _ b: B) where A.Element == B.Element {}
|
|
// expected-note@-1 {{candidate requires that the types 'Int' and 'Double' be equivalent (requirement specified as 'A.Element' == 'B.Element' [with A = IndexingIterator<[Int]>, B = IndexingIterator<[Double]>])}}
|
|
func compareIterators() {
|
|
var a: [Int] = []
|
|
var b: [Double] = []
|
|
testEqualIterElementTypes(a.makeIterator(), b.makeIterator())
|
|
// expected-error@-1 {{cannot invoke 'testEqualIterElementTypes(_:_:)' with an argument list of type '(IndexingIterator<[Int]>, IndexingIterator<[Double]>)'}}
|
|
}
|
|
|
|
protocol P_GI {
|
|
associatedtype Y
|
|
}
|
|
|
|
class C_GI : P_GI {
|
|
typealias Y = Double
|
|
}
|
|
|
|
class GI_Diff {}
|
|
func genericInheritsA<T>(_ x: T) where T : P_GI, T.Y : GI_Diff {}
|
|
// expected-note@-1 {{candidate requires that 'GI_Diff' inherit from 'T.Y' (requirement specified as 'T.Y' : 'GI_Diff' [with T = C_GI])}}
|
|
genericInheritsA(C_GI())
|
|
// expected-error@-1 {{cannot invoke 'genericInheritsA(_:)' with an argument list of type '(C_GI)'}}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Deduction for member operators
|
|
//===----------------------------------------------------------------------===//
|
|
protocol Addable {
|
|
static func +(x: Self, y: Self) -> Self
|
|
}
|
|
func addAddables<T : Addable, U>(_ x: T, y: T, u: U) -> T {
|
|
u + u // expected-error{{binary operator '+' cannot be applied to two 'U' operands}}
|
|
// expected-note @-1 {{overloads for '+' exist with these partially matching parameter lists: }}
|
|
return x+y
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Deduction for bound generic types
|
|
//===----------------------------------------------------------------------===//
|
|
struct MyVector<T> { func size() -> Int {} }
|
|
|
|
func getVectorSize<T>(_ v: MyVector<T>) -> Int {
|
|
return v.size()
|
|
}
|
|
|
|
func ovlVector<T>(_ v: MyVector<T>) -> X {}
|
|
func ovlVector<T>(_ v: MyVector<MyVector<T>>) -> Y {}
|
|
|
|
func testGetVectorSize(_ vi: MyVector<Int>, vf: MyVector<Float>) {
|
|
var i : Int
|
|
i = getVectorSize(vi)
|
|
i = getVectorSize(vf)
|
|
|
|
getVectorSize(i) // expected-error{{cannot convert value of type 'Int' to expected argument type 'MyVector<_>'}}
|
|
|
|
var x : X, y : Y
|
|
x = ovlVector(vi)
|
|
x = ovlVector(vf)
|
|
|
|
var vvi : MyVector<MyVector<Int>>
|
|
y = ovlVector(vvi)
|
|
|
|
var yy = ovlVector(vvi)
|
|
yy = y
|
|
y = yy
|
|
}
|
|
|
|
// <rdar://problem/15104554>
|
|
postfix operator <*>
|
|
|
|
protocol MetaFunction {
|
|
associatedtype Result
|
|
static postfix func <*> (_: Self) -> Result?
|
|
}
|
|
|
|
protocol Bool_ {}
|
|
struct False : Bool_ {}
|
|
struct True : Bool_ {}
|
|
|
|
postfix func <*> <B>(_: Test<B>) -> Int? { return .none }
|
|
postfix func <*> (_: Test<True>) -> String? { return .none }
|
|
|
|
class Test<C: Bool_> : MetaFunction {
|
|
typealias Result = Int
|
|
} // picks first <*>
|
|
typealias Inty = Test<True>.Result
|
|
var iy : Inty = 5 // okay, because we picked the first <*>
|
|
var iy2 : Inty = "hello" // expected-error{{cannot convert value of type 'String' to specified type 'Inty' (aka 'Int')}}
|
|
|
|
// rdar://problem/20577950
|
|
class DeducePropertyParams {
|
|
let badSet: Set = ["Hello"]
|
|
}
|
|
|
|
// SR-69
|
|
struct A {}
|
|
func foo() {
|
|
for i in min(1,2) { // expected-error{{type 'Int' does not conform to protocol 'Sequence'}}
|
|
}
|
|
let j = min(Int(3), Float(2.5)) // expected-error{{cannot convert value of type 'Float' to expected argument type 'Int'}}
|
|
let k = min(A(), A()) // expected-error{{argument type 'A' does not conform to expected type 'Comparable'}}
|
|
let oi : Int? = 5
|
|
let l = min(3, oi) // expected-error{{value of optional type 'Int?' not unwrapped; did you mean to use '!' or '?'?}}
|
|
}
|
|
|
|
infix operator +&
|
|
func +&<R, S>(lhs: inout R, rhs: S) where R : RangeReplaceableCollection, S : Sequence, R.Element == S.Element {}
|
|
// expected-note@-1 {{candidate requires that the types 'String' and 'String.Element' (aka 'Character') be equivalent (requirement specified as 'R.Element' == 'S.Element' [with R = [String], S = String])}}
|
|
|
|
func rdar33477726_1() {
|
|
var arr: [String] = []
|
|
arr +& "hello"
|
|
// expected-error@-1 {{binary operator '+&(_:_:)' cannot be applied to operands of type '[String]' and 'String'}}
|
|
}
|
|
|
|
func rdar33477726_2<R, S>(_: R, _: S) where R: Sequence, S == R.Element {}
|
|
// expected-note@-1 {{candidate requires that the types 'Int' and 'String.Element' (aka 'Character') be equivalent (requirement specified as 'S' == 'R.Element' [with R = String, S = Int])}}
|
|
rdar33477726_2("answer", 42)
|
|
// expected-error@-1 {{cannot invoke 'rdar33477726_2(_:_:)' with an argument list of type '(String, Int)'}}
|
|
|
|
prefix operator +-
|
|
prefix func +-<T>(_: T) where T: Sequence, T.Element == Int {}
|
|
// expected-note@-1 {{candidate requires that the types 'String.Element' (aka 'Character') and 'Int' be equivalent (requirement specified as 'T.Element' == 'Int' [with T = String])}}
|
|
|
|
+-"hello"
|
|
// expected-error@-1 {{unary operator '+-(_:)' cannot be applied to an operand of type 'String'}}
|