Files
swift-mirror/test/decl/operators.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

172 lines
6.3 KiB
Swift

// RUN: %swift -parse %s -verify
infix operator %%% {}
infix operator %%%% {}
func %%%() {} // expected-error {{operators must have one or two arguments}}
func %%%%(a: Int, b: Int, c: Int) {} // expected-error {{operators must have one or two arguments}}
struct X {}
struct Y {}
func +(lhs: X, rhs: X) -> X {} // okay
func +++(lhs: X, rhs: X) -> X {} // expected-error {{operator implementation without matching operator declaration}}
infix operator ++++ {
precedence 195
associativity left
}
infix func fn_binary(lhs: Int, rhs: Int) {} // expected-error {{'infix' requires a function with an operator identifier}}
func ++++(lhs: X, rhs: X) -> X {}
func ++++(lhs: Y, rhs: Y) -> Y {} // okay
func useInt(x: Int) {}
func test() {
var x : Int
var y : Int = 42
// Produce a diagnostic for using the result of an assignment as a value.
// rdar://12961094
useInt(x = y) // expected-error{{cannot invoke 'useInt' with an argument list of type '()'}} expected-note{{expected an argument list of type 'Int'}}
}
prefix operator ~~ {}
postfix operator ~~ {}
infix operator ~~ {}
postfix func foo(x: Int) {} // expected-error {{'postfix' requires a function with an operator identifier}}
postfix func ~~(x: Int) -> Float { return Float(x) }
postfix func ~~(x: Int, y: Int) {} // expected-error {{'postfix' requires a function with one argument}}
prefix func ~~(x: Float) {}
func test_postfix(x: Int) {
~~x~~
}
prefix operator ~~~ {} // expected-note 2{{prefix operator found here}}
// Unary operators require a prefix or postfix attribute
func ~~~(x: Float) {} // expected-error{{prefix unary operator missing 'prefix' modifier}}{{1-1=prefix }}
protocol P {
func ~~~(x: Self) // expected-error{{prefix unary operator missing 'prefix' modifier}}{{3-3=prefix }}
}
prefix func +// this should be a comment, not an operator
(arg: Int) -> Int { return arg }
prefix func -/* this also should be a comment, not an operator */
(arg: Int) -> Int { return arg }
func +*/ () {} // expected-error {{expected identifier in function declaration}} expected-error {{unexpected end of block comment}} expected-error {{braced block of statements is an unused closure}} expected-error{{begin with a closure}} expected-note{{discard the result}} expected-error{{type of expression is ambiguous without more context}}
func errors() {
*/ // expected-error {{unexpected end of block comment}}
// rdar://12962712 - reject */ in an operator as it should end a block comment.
*/+ // expected-error {{unexpected end of block comment}}
}
prefix operator ... {}
prefix func ... (arg: Int) -> Int { return arg }
func resyncParser() {}
// Operator decl refs (<op>)
infix operator +-+ {}
prefix operator +-+ {}
prefix operator -+- {}
postfix operator -+- {}
infix operator +-+= {}
infix func +-+ (x: Int, y: Int) -> Int {} // expected-error {{'infix' modifier is not required or allowed on func declarations}}
prefix func +-+ (x: Int) -> Int {}
prefix func -+- (inout y: Int) -> Int {} // expected-note 2{{found this candidate}}
postfix func -+- (inout x: Int) -> Int {} // expected-note 2{{found this candidate}}
infix func +-+= (inout x: Int, y: Int) -> Int {} // expected-error {{'infix' modifier is not required or allowed on func declarations}}
var n = 0
// Infix by context
(+-+)(1, 2)
// Prefix by context
(+-+)(1)
// Ambiguous -- could be prefix or postfix
(-+-)(&n) // expected-error{{ambiguous use of operator '-+-'}}
// Assignment operator refs become inout functions
(+-+=)(&n, 12)
(+-+=)(n, 12) // expected-error {{passing value of type 'Int' to an inout parameter requires explicit '&'}}
var f1 : (Int, Int) -> Int = (+-+)
var f2 : (Int) -> Int = (+-+)
var f3 : (inout Int) -> Int = (-+-) // expected-error{{ambiguous use of operator '-+-'}}
var f4 : (inout Int, Int) -> Int = (+-+=)
var r5 : (a : (Int, Int) -> Int, b : (Int, Int) -> Int) = (+, -)
var r6 : (a : (Int, Int) -> Int, b : (Int, Int) -> Int) = (b : +, a : -)
struct f6_S {
subscript(op : (Int, Int) -> Int) -> Int {
return 42
}
}
var f6_s : f6_S
var junk = f6_s[+]
// Unicode operator names
infix operator {}
infix operator {} // Operators can contain (but not start with) combining characters
func (x: Int, y: Int) -> Bool { return x == y }
func (x: Int, y: Int) -> Bool { return x != y }
var x, y : Int
xy
xy
// rdar://14705150 - crash on invalid
func test_14705150() {
var a = 4
var b! = a // expected-error {{consecutive statements on a line must be separated by ';'}} \
// expected-error {{expected expression}} \
// expected-error {{type annotation missing in pattern}}
}
prefix postfix func ++(x: Int) {} // expected-error {{attribute 'prefix' cannot be combined with this attribute}}
postfix prefix func ++(x: Int) {} // expected-error {{attribute 'postfix' cannot be combined with this attribute}}
// Don't allow one to define a postfix '!'; it's built into the
// language.
postfix operator! {} // expected-error {{cannot declare a custom postfix '!' operator}}
prefix operator & {} // expected-error {{cannot declare a custom prefix '&' operator}}
// <rdar://problem/14607026> Restrict use of '<' and '>' as prefix/postfix operator names
postfix operator > {} // expected-error {{cannot declare a custom postfix '>' operator}}
prefix operator < {} // expected-error {{cannot declare a custom prefix '<' operator}}
postfix func !(x: Int) { } // expected-error{{cannot declare a custom postfix '!' operator}}
postfix func!(x: Int8) { } // expected-error{{cannot declare a custom postfix '!' operator}}
prefix func & (x: Int) {} // expected-error {{cannot declare a custom prefix '&' operator}}
// Only allow operators at global scope:
func operator_in_func_bad () {
prefix func + (input: String) -> String { return "+" + input } // expected-error {{operators are only allowed at global scope}} expected-error{{type of expression is ambiguous without more context}} \
// expected-error {{braced block of statements is an unused closure}}
}
infix operator ? {} // expected-error {{expected operator name in operator declaration}} expected-error {{braced block of statements is an unused closure}} expected-error{{begin with a closure}} expected-note{{discard the result}} expected-error{{type of expression is ambiguous without more context}}
infix operator ??= {}
func ??= <T>(inout result : T?, rhs : Int) { // ok
}