This inconsistency is not limited to situations in which a tuple is a
non-temporary value:
class C {}
let _ = (C(), 3 as Int) as (Any, Int?) // WORKS FINE
let _ = (C(), 3) as (C, Int) as (Any, Int?) // TYPE ERROR
let _ = ((C(), 3), true).0 as (Any, Int?) // TYPE ERROR
It can even cause the compiler to crash during type-checking on expressions
like the one below (which ought to be considered well-typed):
let _ = "a".isEmpty ? (C(), 3) as (C, Int) : (C(), 3) as (Any, Int?)
And it leads to some rather amusing output if you compile and run this code:
if (C(), 3 as Int) is (Any, Int?) {
print("test is true")
} else {
print("test is false")
}
The outcome will look something like this:
*test.swift:88:20: warning: 'is' test is always trueif (C(), 3 as Int) is
(Any, Int?) { ^test is false*
My bug report contains versions of all of those examples:
I used type casts above in order to make the origin of the problem as clear
as possible; however, it's also worth adding one more example to illustrate
that this problem is not limited to code that is contrived or uses tuples
in ways that are stylistically discouraged:
func returnPair() -> (C, Int) { return (C(), 3) }
var x: Int? = nil
x = returnPair().1 // WORKS FINE
(_, x) = returnPair() // TYPE ERROR
- Aaron
···
On Wed, Jul 6, 2016 at 8:57 AM, Shane S <electro_alchemy@hotmail.com> wrote:
The section you are referencing is regarding ‘assignment’; however, in the
example below we aren’t talking about assignment, this is
'constant-declaration', which is different than a ‘parenthesized
expression’.
But overall I get it, and I think I’m trending toward the same conclusion
you reached re: checking the full type of the identifier -vs- comparing the
types of the constituent elements - interesting stuff!
Shane
On Jul 6, 2016, at 7:34 AM, Neil Faiman <neil.swift@faiman.org> wrote:
The language reference says that “Assignment is performed from each part
of the *value* to the corresponding part of the *expression*. A *String* value
can be assigned to a *String*, and a *() -> Int* value can be assigned to
a *() throws -> Int*, so one would reasonably expect that both tuple
assignments would work.
My hunch would be that the compiler has two different code paths for an
assignment whose RHS is an *identifier* and an assignment whose RHS is a
*parenthesized-expression*; that in the first case starts about by asking
whether the RHS type is the same or a subtype of the LHS type, and
reporting an error when it isn’t, but that in the second case, it starts
with an element-by-element type comparison, which succeeds.
Regards,
Neil
On Jul 6, 2016, at 9:55 AM, Shane S via swift-users <swift-users@swift.org> > wrote:
Aaron this works for me in both Swift 2.2 and Swift 3 provided that you
remove the ‘throws’ keyword.
What seems odd to me is not the first assignment, but rather the second
that _allows_ the use of ‘throws’ when t.1 (i.e. f) does not throw - is
your concern the same?
Shane
On Jul 5, 2016, at 10:48 PM, Aaron Bohannon via swift-users < > swift-users@swift.org> wrote:
Yesterday, it was pointed out that a variable name referring to a tuple
cannot be used as a pattern. I have noticed another sort of inconsistency
in how tuples are treated when they are referenced by name:
func f() -> Int { return 5 }
let t = ("a", f)
let _: (String, () throws -> Int) = t // type error
let _: (String, () throws -> Int) = (t.0, t.1) // OK
This situation leads to a different sort of type error; however, the error
seems equally unwarranted. I can't see any good reason for a well-typed
program to become ill-typed when `(t.0, t.1)` is replaced with `t`
(assuming `t` is a pair).
Should I file a separate bug for the specific example above?
- Aaron
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users
_______________________________________________
swift-users mailing list
swift-users@swift.org
https://lists.swift.org/mailman/listinfo/swift-users