Great. I'd like to see something like this. Couple of comments:<div><br></div><div>You don't explicitly address overload selection. Do you intend it to be affected?<div><br></div><div>Impact on existing code section <span></span>could be more descriptive.<br><br>On Thursday, November 3, 2016, Haravikk via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word">To avoid hijacking the guard let x = x thread entirely I've decided to try to write up a proposal on type narrowing in Swift.<div>Please give your feedback on the functionality proposed, as well as the clarity of the proposal/examples themselves; I've tried to keep it straightforward, but I do tend towards being overly verbose, I've always tried to have the examples build upon one another to show how it all stacks up.<div><br></div><div><br></div><div><br></div><div><h1 style="margin-right:0px;margin-bottom:16px;margin-left:0px;line-height:1.25;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255);margin-top:0px!important">Type Narrowing</h1><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><li>Proposal: <a href="https://github.com/Haravikk/swift-evolution/blob/master/proposals/NNNN-type-narrowing.md" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">SE-NNNN</a></li><li style="margin-top:0.25em">Author: <a href="https://github.com/haravikk" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">Haravikk</a></li><li style="margin-top:0.25em">Status: <span style="font-weight:600">Awaiting review</span></li><li style="margin-top:0.25em">Review manager: TBD</li></ul><h2 style="margin-top:24px;margin-bottom:16px;line-height:1.25;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#introduction" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Introduction</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">This proposal is to introduce type-narrowing to Swift, enabling the type-checker to automatically infer a narrower type from context such as conditionals.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Swift-evolution thread: <a href="http://news.gmane.org/gmane.comp.lang.swift.evolution" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">Discussion thread topic for that proposal</a></p><h2 style="margin-top:24px;margin-bottom:16px;line-height:1.25;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#motivation" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Motivation</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Currently in Swift there are various pieces of boilerplate required in order to manually narrow types. The most obvious is in the case of polymorphism:</p><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:16px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">let foo:A = B() // B extends A
if foo is B {
(foo as B).someMethodSpecificToB()
}
</code></pre><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">But also in the case of unwrapping of optionals:</p><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:16px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">var foo:A? = A()
if var foo = foo { // foo is now unwrapped and shadowed
foo.someMethod()
foo!.someMutatingMethod() // Can't be done
}
</code></pre><h2 style="margin-top:24px;margin-bottom:16px;line-height:1.25;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#proposed-solution" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Proposed solution</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">The proposed solution to the boiler-plate is to introduce type-narrowing, essentially a finer grained knowledge of type based upon context. Thus as any contextual clue indicating a more or less specific type are encountered, the type of the variable will reflect this from that point onwards.</p><h2 style="margin-top:24px;margin-bottom:16px;line-height:1.25;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#detailed-design" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Detailed design</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">The concept of type-narrowing would essentially treat all variables as having not just a single type, but instead as having a stack of increasingly specific (narrow) types.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Whenever a contextual clue such as a conditional is encountered, the type checker will infer whether this narrows the type, and add the new narrow type to the stack from that point onwards. Whenever the type widens again narrower types are popped from the stack.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Here are the above examples re-written to take advantage of type-narrowing:</p><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:16px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">let foo:A = B() // B extends A
if foo is B { // B is added to foo's type stack
foo.someMethodSpecificToB()
}
// B is popped from foo's type stack
</code></pre><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:16px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">var foo:A? = A()
if foo != nil { // Optional<A>.some is added to foo's type stack
foo.someMethod()
foo.someMutatingMethod() // Can modify mutable original
}
// Optional<A>.some is popped from foo's type stack
</code></pre><h3 style="margin-top:24px;margin-bottom:16px;font-size:1.25em;line-height:1.25;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#enum-types" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Enum Types</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">As seen in the simple optional example, to implement optional support each <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">case</code> in an <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">enum</code> is considered be a unique sub-type of the enum itself, thus allowing narrowing to <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">nil</code> (<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">.none</code>) and non-<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">nil</code> (<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">.some</code>) types.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">This behaviour actually enables some other useful behaviours, specifically, if a value is known to be either <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">nil</code> or non-<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">nil</code> then the need to unwrap or force unwrap the value can be eliminated entirely, with the compiler able to produce errors if these are used incorrectly, for example:</p><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:16px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">var foo:A? = A()
foo.someMethod() // A is non-nil, no operators required!
foo = nil
foo!.someMethod() // Error: foo is always nil at this point
</code></pre><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">However, unwrapping of the value is only possible if the case contains either no value at all, or contains a single value able to satisfy the variable's original type requirements. In other words, the value stored in <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">Optional<A>.some</code> satisfies the type requirements of <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">var foo:A?</code>, thus it is implicitly unwrapped for use. For general enums this likely means no cases are implicitly unwrapped unless using a type of <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">Any</code>.</p><h3 style="margin-top:24px;margin-bottom:16px;font-size:1.25em;line-height:1.25;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#type-widening" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Type Widening</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">In some cases a type may be narrowed, only to be used in a way that makes no sense for the narrowed type. In cases such as these the operation is tested against each type in the stack to determine whether the type must instead be widened. If a widened type is found it is selected (with re-narrowing where possible) otherwise an error is produced as normal.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">For example:</p><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:16px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">let foo:A? = A()
if (foo != nil) { // Type of foo is Optional<A>.some
foo.someMethod()
foo = nil // Type of foo is widened to Optional<A>, then re-narrowed to Optional<A>.none
} // Type of foo is Optional<A>.none
foo.someMethod() // Error: foo is always nil at this point
</code></pre><h3 style="margin-top:24px;margin-bottom:16px;font-size:1.25em;line-height:1.25;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#multiple-conditions-and-branching" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Multiple Conditions and Branching</h3><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">When dealing with complex conditionals or branches, all paths must agree on a common type for narrowing to occur. For example:</p><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:16px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;color:rgb(51,51,51)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">let foo:A? = B() // B extends A
let bar:C = C() // C extends B
if (foo != nil) || (foo == bar) { // Optional<A>.some is added to foo's type stack
if foo is B { // Optional<B>.some is added to foo's type stack
foo.someMethodSpecificToB()
} // Optional<B>.some is popped from foo's type stack
foo = nil // Type of foo is re-narrowed as Optional<A>.none
} // Type of foo is Optional<A>.none in all branches
foo.someMethod() // Error: foo is always nil at this point
</code></pre><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Here we can see that the extra condition <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">(foo == bar)</code> does not prevent type-narrowing, as the variable <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">bar</code> cannot be <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">nil</code> so both conditions require a type of <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">Optional<A>.some</code> as a minimum.</p><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">In this example <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">foo</code> is also <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">nil</code> at the end of both branches, thus its type can remain narrowed past this point.</p><h3 style="margin-top:24px;margin-bottom:16px;font-size:1.25em;line-height:1.25;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#context-triggers" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Context Triggers</h3><table style="border-spacing:0px;border-collapse:collapse;margin-top:0px;margin-bottom:16px;display:block;width:888px;overflow:auto;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)"><thead><tr style="border-top-width:1px;border-top-style:solid;border-top-color:rgb(204,204,204)"><th style="padding:6px 13px;border:1px solid rgb(221,221,221)">Trigger</th><th style="padding:6px 13px;border:1px solid rgb(221,221,221)">Impact</th></tr></thead><tbody><tr style="border-top-width:1px;border-top-style:solid;border-top-color:rgb(204,204,204)"><td style="padding:6px 13px;border:1px solid rgb(221,221,221)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">as</code></td><td style="padding:6px 13px;border:1px solid rgb(221,221,221)">Explicitly narrows a type with <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">as!</code> failing and <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">as?</code> narrowing to <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">Type?</code> instead when this is not possible.</td></tr><tr style="background-color:rgb(248,248,248);border-top-width:1px;border-top-style:solid;border-top-color:rgb(204,204,204)"><td style="padding:6px 13px;border:1px solid rgb(221,221,221)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">is</code></td><td style="padding:6px 13px;border:1px solid rgb(221,221,221)">Anywhere a type is tested will allow the type-checker to infer the new type if there was a match (and other conditions agree).</td></tr><tr style="border-top-width:1px;border-top-style:solid;border-top-color:rgb(204,204,204)"><td style="padding:6px 13px;border:1px solid rgb(221,221,221)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">case</code></td><td style="padding:6px 13px;border:1px solid rgb(221,221,221)">Any form of exhaustive test on an enum type allows it to be narrowed either to that case or the opposite, e.g- <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">foo != nil</code> eliminates <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">.none</code>, leaving only <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">.some</code> as the type, which can then be implicitly unwrapped (see Enum Types above).</td></tr><tr style="background-color:rgb(248,248,248);border-top-width:1px;border-top-style:solid;border-top-color:rgb(204,204,204)"><td style="padding:6px 13px;border:1px solid rgb(221,221,221)"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">=</code></td><td style="padding:6px 13px;border:1px solid rgb(221,221,221)">Assigning a value to a type will either narrow it if the new value is a sub-type, or will trigger widening to find a new common type, before attempting to re-narrow from there.</td></tr></tbody></table><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">There may be other triggers that should be considered.</p><h2 style="margin-top:24px;margin-bottom:16px;line-height:1.25;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#impact-on-existing-code" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Impact on existing code</h2><p style="margin-top:0px;margin-bottom:16px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255)">Although this change is technically additive, it will impact any code in which there are currently errors that type-narrowing would have detected; for example, attempting to manipulate a predictably <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">nil</code> value.</p><h2 style="margin-top:24px;margin-bottom:16px;line-height:1.25;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';background-color:rgb(255,255,255)"><a href="https://github.com/Haravikk/swift-evolution/tree/master/proposals#alternatives-considered" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;float:left;padding-right:4px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Alternatives considered</h2><div style="margin-top:0px;color:rgb(51,51,51);font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Helvetica,Arial,sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol';font-size:16px;background-color:rgb(255,255,255);margin-bottom:0px!important">One of the main advantages of type-narrowing is that it functions as an alternative to other features. This includes alternative syntax for shadowing/unwrapping of optionals, in which case type-narrowing allows an optional to be implicitly unwrapped simply by testing it, and without the need to introduce any new syntax.</div></div></div></div></blockquote></div></div>