Files
swift-mirror/test/Generics/function_defs.swift
Joe Pamer 2912159776 Improve diagnostics for expression typecheck errors
These changes make the following improvements to how we generate diagnostics for expression typecheck failure:
- Customizing a diagnostic for a specific expression kind is as easy as adding a new method to the FailureDiagnosis class,
  and does not require intimate knowledge of the constraint solver’s inner workings.
    - As part of this patch, I’ve introduced specialized diagnostics for call, binop, unop, subscript, assignment and inout
      expressions, but we can go pretty far with this.
    - This also opens up the possibility to customize diagnostics not just for the expression kind, but for the specific types
      involved as well.
- For the purpose of presenting accurate type info, partially-specialized subexpressions are individually re-typechecked
  free of any contextual types. This allows us to:
    - Properly surface subexpression errors.
    - Almost completely avoid any type variables in our diagnostics. In cases where they could not be eliminated, we now
      substitute in "_".
    - More accurately indicate the sources of errors.
- We do a much better job of diagnosing disjunction failures. (So no more nonsensical ‘UInt8’ error messages.)
- We now present reasonable error messages for overload resolution failures, informing the user of partially-matching
  parameter lists when possible.

At the very least, these changes address the following bugs:

<rdar://problem/15863738> More information needed in type-checking error messages
<rdar://problem/16306600> QoI: passing a 'let' value as an inout results in an unfriendly diagnostic
<rdar://problem/16449805> Wrong error for struct-to-protocol downcast
<rdar://problem/16699932> improve type checker diagnostic when passing Double to function taking a Float
<rdar://problem/16707914> fatal error: Can't unwrap Optional.None…Optional.swift, line 75 running Master-Detail Swift app built from template
<rdar://problem/16785829> Inout parameter fixit
<rdar://problem/16900438> We shouldn't leak the internal type placeholder
<rdar://problem/16909379> confusing type check diagnostics
<rdar://problem/16951521> Extra arguments to functions result in an unhelpful error
<rdar://problem/16971025> Two Terrible Diagnostics
<rdar://problem/17007804> $T2 in compiler error string
<rdar://problem/17027483> Terrible diagnostic
<rdar://problem/17083239> Mysterious error using find() with Foundation types
<rdar://problem/17149771> Diagnostic for closure with no inferred return value leaks type variables
<rdar://problem/17212371> Swift poorly-worded error message when overload resolution fails on return type
<rdar://problem/17236976> QoI: Swift error for incorrectly typed parameter is confusing/misleading
<rdar://problem/17304200> Wrong error for non-self-conforming protocols
<rdar://problem/17321369> better error message for inout protocols
<rdar://problem/17539380> Swift error seems wrong
<rdar://problem/17559593> Bogus locationless "treating a forced downcast to 'NSData' as optional will never produce 'nil'" warning
<rdar://problem/17567973> 32-bit error message is really far from the mark: error: missing argument for parameter 'withFont' in call
<rdar://problem/17671058> Wrong error message: "Missing argument for parameter 'completion' in call"
<rdar://problem/17704609> Float is not convertible to UInt8
<rdar://problem/17705424> Poor error reporting for passing Doubles to NSColor: extra argument 'red' in call
<rdar://problem/17743603> Swift compiler gives misleading error message in "NSLayoutConstraint.constraintsWithVisualFormat("x", options: 123, metrics: nil, views: views)"
<rdar://problem/17784167> application of operator to generic type results in odd diagnostic
<rdar://problem/17801696> Awful diagnostic trying to construct an Int when .Int is around
<rdar://problem/17863882> cannot convert the expression's type '()' to type 'Seq'
<rdar://problem/17865869> "has different argument names" diagnostic when parameter defaulted-ness differs
<rdar://problem/17937593> Unclear error message for empty array literal without type context
<rdar://problem/17943023> QoI: compiler displays wrong error when a float is provided to a Int16 parameter in init method
<rdar://problem/17951148> Improve error messages for expressions inside if statements by pre-evaluating outside the 'if'
<rdar://problem/18057815> Unhelpful Swift error message
<rdar://problem/18077468> Incorrect argument label for insertSubview(...)
<rdar://problem/18079213> 'T1' is not identical to 'T2' lacks directionality
<rdar://problem/18086470> Confusing Swift error message: error: 'T' is not convertible to 'MirrorDisposition'
<rdar://problem/18098995> QoI: Unhelpful compiler error when leaving off an & on an inout parameter
<rdar://problem/18104379> Terrible error message
<rdar://problem/18121897> unexpected low-level error on assignment to immutable value through array writeback
<rdar://problem/18123596> unexpected error on self. capture inside class method
<rdar://problem/18152074> QoI: Improve diagnostic for type mismatch in dictionary subscripting
<rdar://problem/18242160> There could be a better error message when using [] instead of [:]
<rdar://problem/18242812> 6A1021a : Type variable leaked
<rdar://problem/18331819> Unclear error message when trying to set an element of an array constant (Swift)
<rdar://problem/18414834> Bad diagnostics example
<rdar://problem/18422468> Calculation of constant value yields unexplainable error
<rdar://problem/18427217> Misleading error message makes debugging difficult
<rdar://problem/18439742> Misleading error: "cannot invoke" mentions completely unrelated types as arguments
<rdar://problem/18535804> Wrong compiler error from swift compiler
<rdar://problem/18567914> Xcode 6.1. GM, Swift, assignment from Int64 to NSNumber. Warning shown as problem with UInt8
<rdar://problem/18784027> Negating Int? Yields Float
<rdar://problem/17691565> attempt to modify a 'let' variable with ++ results in typecheck error about @lvalue Float
<rdar://problem/17164001> "++" on let value could give a better error message

Swift SVN r23782
2014-12-08 21:56:47 +00:00

306 lines
11 KiB
Swift

// RUN: %swift -parse %s -verify
//===----------------------------------------------------------------------===//
// Type-check function definitions
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Basic type checking
//===----------------------------------------------------------------------===//
protocol EqualComparable {
func isEqual(other: Self) -> Bool
}
func doCompare<T : EqualComparable, U : EqualComparable>(t1: T, t2: T, u: U) -> Bool {
var b1 = t1.isEqual(t2)
if b1 {
return true;
}
return t1.isEqual(u) // expected-error{{cannot invoke 'isEqual' with an argument list of type 'U'}}
}
protocol MethodLessComparable {
func isLess(other: Self) -> Bool
}
func min<T : MethodLessComparable>(x: T, y: T) -> T {
if (y.isLess(x)) { return y }
return x
}
//===----------------------------------------------------------------------===//
// Interaction with existential types
//===----------------------------------------------------------------------===//
func existential<T : EqualComparable, U : EqualComparable>(t1: T, t2: T, u: U) {
var eqComp : EqualComparable = t1 // expected-error{{protocol 'EqualComparable' can only be used as a generic constraint}}
eqComp = u
if t1.isEqual(eqComp) {} // expected-error{{cannot invoke 'isEqual' with an argument list of type 'EqualComparable'}}
if eqComp.isEqual(t2) {} // expected-error{{'EqualComparable' does not have a member named 'isEqual'}}
}
protocol OtherEqualComparable {
func isEqual(other: Self) -> Bool
}
func otherExistential<T : EqualComparable>(t1: T) {
var otherEqComp : OtherEqualComparable = t1 // expected-error{{type 'T' does not conform to protocol 'OtherEqualComparable'}} expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}}
otherEqComp = t1 // expected-error{{cannot assign a value of type 'T' to a value of type 'OtherEqualComparable'}}
var otherEqComp2 : OtherEqualComparable // expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}}
otherEqComp2 = t1 // expected-error{{cannot assign a value of type 'T' to a value of type 'OtherEqualComparable'}}
var everyEq : protocol<EqualComparable, OtherEqualComparable> = t1 // expected-error{{type 'T' does not conform to protocol 'OtherEqualComparable'}} expected-error{{protocol 'OtherEqualComparable' can only be used as a generic constraint}} expected-error{{protocol 'EqualComparable' can only be used as a generic constraint}}
}
protocol Runcible {
func runce<A>(x: A)
func spoon(x: Self)
}
func testRuncible(x: Runcible) { // expected-error{{protocol 'Runcible' can only be used as a generic constraint}}
x.runce(5)
}
//===----------------------------------------------------------------------===//
// Overloading
//===----------------------------------------------------------------------===//
protocol Overload {
typealias A
typealias B
func getA() -> A
func getB() -> B
func f1(_: A) -> A
func f1(_: B) -> B
func f2(_: Int) -> A // expected-note{{found this candidate}}
func f2(_: Int) -> B // expected-note{{found this candidate}}
func f3(_: Int) -> Int
func f3(_: Float) -> Float
func f3(_: Self) -> Self
var prop : Self { get }
}
func testOverload<Ovl : Overload, OtherOvl : Overload>(ovl: Ovl, ovl2: Ovl,
other: OtherOvl) {
var a = ovl.getA()
var b = ovl.getB()
// Overloading based on arguments
ovl.f1(a)
a = ovl.f1(a)
ovl.f1(b)
b = ovl.f1(b)
// Overloading based on return type
a = ovl.f2(17)
b = ovl.f2(17)
ovl.f2(17) // expected-error{{ambiguous use of 'f2'}}
// Check associated types from different objects/different types.
a = ovl2.f2(17)
a = ovl2.f1(a)
other.f1(a) // expected-error{{cannot invoke 'f1' with an argument list of type 'Ovl.A'}}
// Overloading based on context
var f3i : (Int) -> Int = ovl.f3 // expected-error{{partial application of generic method is not allowed}}
var f3f : (Float) -> Float = ovl.f3 // expected-error{{partial application of generic method is not allowed}}
var f3ovl_1 : (Ovl) -> Ovl = ovl.f3 // expected-error{{partial application of generic method is not allowed}}
var f3ovl_2 : (Ovl) -> Ovl = ovl2.f3 // expected-error{{partial application of generic method is not allowed}}
var f3ovl_3 : (Ovl) -> Ovl = other.f3 // expected-error{{could not find an overload for 'f3' that accepts the supplied arguments}}
// FIXME: Should not be inout. <rdar://problem/15821762>
var f3i_unbound : (inout Ovl) -> (Int) -> Int = Ovl.f3 // expected-error{{partial application of generic method is not allowed}}
var f3f_unbound : (inout Ovl) -> (Float) -> Float = Ovl.f3 // expected-error{{partial application of generic method is not allowed}}
var f3f_unbound2 : (inout OtherOvl) -> (Float) -> Float = OtherOvl.f3 // expected-error{{partial application of generic method is not allowed}}
var f3ovl_unbound_1 : (inout Ovl) -> (Ovl) -> Ovl = Ovl.f3 // expected-error{{partial application of generic method is not allowed}}
var f3ovl_unbound_2 : (inout OtherOvl) -> (OtherOvl) -> OtherOvl = OtherOvl.f3 // expected-error{{partial application of generic method is not allowed}}
}
//===----------------------------------------------------------------------===//
// Subscripting
//===----------------------------------------------------------------------===//
protocol Subscriptable {
typealias Index
typealias Value
func getIndex() -> Index
func getValue() -> Value
subscript (index : Index) -> Value { get set }
}
protocol IntSubscriptable {
typealias ElementType
func getElement() -> ElementType
subscript (index : Int) -> ElementType { get }
}
func subscripting<T : protocol<Subscriptable, IntSubscriptable>>(t: T) {
var index = t.getIndex()
var value = t.getValue()
var element = t.getElement()
value = t[index]
// FIXME: bogus error
t[index] = value // expected-error{{cannot assign a value of invariant archetype type 'T.Value' to another value of the same type}}
element = t[17]
// FIXME: bogus error
t[42] = element // expected-error{{cannot assign a value of invariant archetype type 'T.ElementType' to another value of the same type}}
t[value] = 17 // expected-error{{cannot subscript a value of type 'T' with an index of type 'T.Value'}}
}
//===----------------------------------------------------------------------===//
// Static functions
//===----------------------------------------------------------------------===//
protocol StaticEq {
class func isEqual(x: Self, y: Self) -> Bool
}
func staticEqCheck<T : StaticEq, U : StaticEq>(t: T, u: U) {
if t.isEqual(t, t) { return } // expected-error{{'T' does not have a member named 'isEqual'}}
if T.isEqual(t, y: t) { return }
if U.isEqual(u, y: u) { return }
T.isEqual(t, y: u) // expected-error{{cannot invoke 'isEqual' with an argument list of type 'T, U'}}
}
//===----------------------------------------------------------------------===//
// Operators
//===----------------------------------------------------------------------===//
protocol Ordered {
func <(lhs: Self, rhs: Self) -> Bool
}
func testOrdered<T : Ordered>(x: T, y: Int) {
if y < 100 || 500 < y { return }
if x < x { return }
}
//===----------------------------------------------------------------------===//
// Requires clauses
//===----------------------------------------------------------------------===//
func conformanceViaRequires<T
where T : EqualComparable, T : MethodLessComparable
>(t1: T, t2: T) -> Bool {
var b1 = t1.isEqual(t2)
if b1 || t1.isLess(t2) {
return true;
}
}
protocol GeneratesAnElement {
typealias Element : EqualComparable
func generate() -> Element
}
protocol AcceptsAnElement {
typealias Element : MethodLessComparable
func accept(e : Element)
}
func impliedSameType<T : GeneratesAnElement where T : AcceptsAnElement>(t: T) {
t.accept(t.generate())
var e = t.generate(), e2 = t.generate()
if e.isEqual(e2) || e.isLess(e2) {
return
}
}
protocol GeneratesAssoc1 {
typealias Assoc1 : EqualComparable
func get() -> Assoc1
}
protocol GeneratesAssoc2 {
typealias Assoc2 : MethodLessComparable
func get() -> Assoc2
}
func simpleSameType
<T : GeneratesAssoc1, U : GeneratesAssoc2 where T.Assoc1 == U.Assoc2>
(t: T, u: U) -> Bool
{
return t.get().isEqual(u.get()) || u.get().isLess(t.get())
}
protocol GeneratesMetaAssoc1 {
typealias MetaAssoc1 : GeneratesAnElement
func get() -> MetaAssoc1
}
protocol GeneratesMetaAssoc2 {
typealias MetaAssoc2 : AcceptsAnElement
func get() -> MetaAssoc2
}
func recursiveSameType
<T : GeneratesMetaAssoc1, U : GeneratesMetaAssoc2, V : GeneratesAssoc1
where T.MetaAssoc1 == V.Assoc1, V.Assoc1 == U.MetaAssoc2>
(t: T, u: U)
{
t.get().accept(t.get().generate())
var e = t.get().generate(), e2 = t.get().generate()
if e.isEqual(e2) || e.isLess(e2) {
return
}
}
// <rdar://problem/13985164>
protocol P1 {
typealias Element
}
protocol P2 {
typealias AssocP1 : P1
func getAssocP1() -> AssocP1
}
func beginsWith2<
E0: P1, E1: P1
where
E0.Element == E1.Element,
E0.Element : EqualComparable
>(e0: E0, e1: E1) -> Bool
{
}
func beginsWith3<
S0: P2, S1: P2
where
S0.AssocP1.Element == S1.AssocP1.Element,
S1.AssocP1.Element : EqualComparable
>(seq1: S0, seq2: S1) -> Bool
{
return beginsWith2(seq1.getAssocP1(), seq2.getAssocP1())
}
// FIXME: Test same-type constraints that try to equate things we
// don't want to equate, e.g., T == U.
//===----------------------------------------------------------------------===//
// Bogus requirements
//===----------------------------------------------------------------------===//
func nonTypeReq<T where T : Wibble>(_: T) {} // expected-error{{use of undeclared type 'Wibble'}}
func badProtocolReq<T where T : Int>(_: T) {} // expected-error{{type 'T' constrained to non-protocol type 'Int'}}
func nonTypeSameType<T where T == Wibble>(_: T) {} // expected-error{{use of undeclared type 'Wibble'}}
func nonTypeSameType2<T where Wibble == T>(_: T) {} // expected-error{{use of undeclared type 'Wibble'}}
func sameTypeEq<T where T = T>(_: T) {} // expected-error{{use '==' for same-type requirements rather than '='}} {{27-28===}}
func badTypeConformance1<T where Int : EqualComparable>() {} // expected-error{{type 'Int' in conformance requirement does not refer to a generic parameter or associated type}}
func badTypeConformance2<T where T.Blarg : EqualComparable>() { } // expected-error{{'Blarg' is not a member type of 'T'}}
func badSameType<T, U : GeneratesAnElement, V
where T == U.Element,
U.Element == V // expected-error{{same-type requirement makes generic parameters 'T' and 'V' equivalent}}
>() {}