Files
swift-mirror/test/decl/subscript/subscripting.swift
Chris Lattner ede0c50856 Revamp how value & type member constraint failures are diagnosed, eliminating the
"unavoidable failure" path, along with Failure::DoesNotHaveNonMutatingMember and
just doing some basic disambiguation in CSDiags.

This provides some benefits:
 - Allows us to plug in much more specific diagnostics for the existing "only has 
   mutating members" diagnostic, including producing notes for why the base expr
   isn't mutable (see e.g. test/Sema/immutability.swift diffs).
 - Corrects issues where we'd drop full decl name info for selector references.
 - Wordsmiths diagnostics to not complain about "values of type Foo.Type" instead 
   complaining about "type Foo"
 - Where before we would diagnose all failures with "has no member named", we now
   distinguish between when there is no member, and when you can't use it.  When you
   can't use it, you get a vauge "cannot use it" diagnostic, but...
 - This provides an infrastructure for diagnosing other kinds of problems (e.g. 
   trying to use a private member or a static member from an instance).
 - Improves a number of cases where failed type member constraints would produce uglier
   diagnostics than a different constraint failure would.
 - Resolves a number of rdars, e.g. (and probably others):
   <rdar://problem/20294245> QoI: Error message mentions value rather than key for subscript



Swift SVN r30715
2015-07-28 07:04:22 +00:00

252 lines
6.3 KiB
Swift

// RUN: %target-parse-verify-swift
struct X { }
// Simple examples
struct X1 {
var stored : Int
subscript (i : Int) -> Int {
get {
return stored
}
mutating
set {
stored = newValue
}
}
}
struct X2 {
var stored : Int
subscript (i : Int) -> Int {
get {
return stored + i
}
set(v) {
stored = v - i
}
}
}
struct X3 {
var stored : Int
subscript (_ : Int) -> Int {
get {
return stored
}
set(v) {
stored = v
}
}
}
struct X4 {
var stored : Int
subscript (i : Int, j : Int) -> Int {
get {
return stored + i + j
}
set(v) {
stored = v + i - j
}
}
}
// Semantic errors
struct Y1 {
var x : X
subscript(i: Int) -> Int {
get {
return x // expected-error{{cannot convert return expression of type 'X' to return type 'Int'}}
}
set {
x = newValue // expected-error{{cannot assign a value of type 'Int' to a value of type 'X'}}
}
}
}
protocol ProtocolGetSet0 {
subscript(i: Int) -> Int {} // expected-error {{subscript declarations must have a getter}}
}
protocol ProtocolGetSet1 {
subscript(i: Int) -> Int { get }
}
protocol ProtocolGetSet2 {
subscript(i: Int) -> Int { set } // expected-error {{subscript declarations must have a getter}}
}
protocol ProtocolGetSet3 {
subscript(i: Int) -> Int { get set }
}
protocol ProtocolGetSet4 {
subscript(i: Int) -> Int { set get }
}
protocol ProtocolWillSetDidSet1 {
subscript(i: Int) -> Int { willSet } // expected-error {{expected get or set in a protocol property}}
}
protocol ProtocolWillSetDidSet2 {
subscript(i: Int) -> Int { didSet } // expected-error {{expected get or set in a protocol property}}
}
protocol ProtocolWillSetDidSet3 {
subscript(i: Int) -> Int { willSet didSet } // expected-error {{expected get or set in a protocol property}}
}
protocol ProtocolWillSetDidSet4 {
subscript(i: Int) -> Int { didSet willSet } // expected-error {{expected get or set in a protocol property}}
}
class DidSetInSubscript {
subscript(_: Int) -> Int {
didSet { // expected-error {{didSet is not allowed in subscripts}}
print("eek")
}
get {}
}
}
class WillSetInSubscript {
subscript(_: Int) -> Int {
willSet { // expected-error {{willSet is not allowed in subscripts}}
print("eek")
}
get {}
}
}
subscript(i: Int) -> Int { // expected-error{{'subscript' functions may only be declared within a type}}
get {}
}
func f() {
subscript (i: Int) -> Int { // expected-error{{'subscript' functions may only be declared within a type}}
get {}
}
}
struct NoSubscript { }
struct OverloadedSubscript {
subscript(i: Int) -> Int {
get {
return i
}
set {}
}
subscript(i: Int, j: Int) -> Int {
get { return i }
set {}
}
}
struct RetOverloadedSubscript {
subscript(i: Int) -> Int {
get { return i }
set {}
}
subscript(i: Int) -> Float {
get { return Float(i) }
set {}
}
}
struct MissingGetterSubscript1 {
subscript (i : Int) -> Int {
} // expected-error {{computed property must have accessors specified}}
}
struct MissingGetterSubscript2 {
subscript (i : Int, j : Int) -> Int { // expected-error{{subscript declarations must have a getter}}
set {}
}
}
func test_subscript(inout x2: X2, i: Int, j: Int, inout value: Int, no: NoSubscript,
inout ovl: OverloadedSubscript, inout ret: RetOverloadedSubscript) {
no[i] = value // expected-error{{cannot subscript a value of type 'NoSubscript' with an index of type 'Int'}}
value = x2[i]
x2[i] = value
value = ovl[i]
ovl[i] = value
value = ovl[(i, j)]
ovl[(i, j)] = value
value = ovl[(i, j, i)] // expected-error{{cannot subscript a value of type 'OverloadedSubscript' with an index of type '(Int, Int, Int)'}}
// expected-note @-1 {{overloads for 'subscript' exist with these partially matching parameter lists: (Int), (Int, Int)}}
ret[i] // expected-error{{multiple candidates fail to match based on result type}}
// expected-note @-1 {{expected an argument list of type '(Int)'}}
value = ret[i]
ret[i] = value
}
func subscript_rvalue_materialize(inout i: Int) {
i = X1(stored: 0)[i]
}
func subscript_coerce(fn: ([UnicodeScalar], [UnicodeScalar]) -> Bool) {}
func test_subscript_coerce() {
subscript_coerce({ $0[$0.count-1] < $1[$1.count-1] })
}
struct no_index {
subscript () -> Int { return 42 }
func test() -> Int {
return self[]
}
}
struct tuple_index {
subscript (x : Int, y : Int) -> (Int, Int) { return (x, y) }
func test() -> (Int, Int) {
return self[123, 456]
}
}
struct SubscriptTest1 {
subscript(keyword:String) -> Bool { return true }
subscript(keyword:String) -> String? {return nil }
}
func testSubscript1(s1 : SubscriptTest1) {
// FIXME: This is an overload ambiguity, Bool is just one choice.
let _ : Int = s1["hello"] // expected-error {{multiple candidates fail to match based on result type}}
// expected-note @-1 {{expected an argument list of type '(String)'}}
// FIXME: This is a bug, it should not be ambiguous. rdar://18741539
if s1["hello"] {} // expected-error {{multiple candidates fail to match based on result type}}
// expected-note @-1 {{expected an argument list of type '(String)'}}
let _ = s1["hello"] // expected-error {{multiple candidates fail to match based on result type}}
// expected-note @-1 {{expected an argument list of type '(String)'}}
}
struct SubscriptTest2 {
subscript(a : String, b : Int) -> Int { return 0 }
subscript(a : String, b : String) -> Int { return 0 }
}
func testSubscript1(s2 : SubscriptTest2) {
_ = s2["foo"] // expected-error {{cannot subscript a value of type 'SubscriptTest2' with an index of type 'String'}}
// expected-note @-1 {{overloads for 'subscript' exist with these partially matching parameter lists: (String, Int), (String, String)}}
let a = s2["foo", 1.0] // expected-error {{cannot subscript a value of type 'SubscriptTest2' with an index of type '(String, Double)'}}
// expected-note @-1 {{overloads for 'subscript' exist with these partially matching parameter lists: (String, Int), (String, String)}}
let b = s2[1, "foo"] // expected-error {{cannot subscript a value of type 'SubscriptTest2' with an index of type '(Int, String)'}}
// expected-note @-1 {{expected an argument list of type '(String, String)'}}
}