Skip to content

Commit 968507c

Browse files
committed
Sema: Allow "case let value as [Int]" and remove the diagnostic that it is not implemented
1 parent eb7a23f commit 968507c

File tree

4 files changed

+269
-22
lines changed

4 files changed

+269
-22
lines changed

lib/Sema/TypeCheckPattern.cpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1384,16 +1384,7 @@ Pattern *TypeChecker::coercePatternToType(ContextualPattern pattern,
13841384
// Valid checks.
13851385
case CheckedCastKind::ArrayDowncast:
13861386
case CheckedCastKind::DictionaryDowncast:
1387-
case CheckedCastKind::SetDowncast: {
1388-
diags.diagnose(IP->getLoc(),
1389-
diag::isa_collection_downcast_pattern_value_unimplemented,
1390-
IP->getCastType());
1391-
IP->setType(ErrorType::get(Context));
1392-
if (Pattern *sub = IP->getSubPattern())
1393-
sub->forEachVariable([](VarDecl *VD) { VD->setInvalid(); });
1394-
return P;
1395-
}
1396-
1387+
case CheckedCastKind::SetDowncast:
13971388
case CheckedCastKind::ValueCast:
13981389
IP->setCastKind(castKind);
13991390
break;

test/Parse/matching_patterns.swift

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -289,22 +289,54 @@ case (let (_, _, _)) + 1:
289289
()
290290
}
291291

292-
// FIXME: We don't currently allow subpatterns for "isa" patterns that
293-
// require interesting conditional downcasts.
294-
class Base { }
295-
class Derived : Base { }
292+
// "isa" patterns.
296293

294+
// https://github.com/apple/swift/issues/56139
295+
// Allow subpatterns for "isa" patterns that require conditional
296+
// collection downcasts
297+
do {
298+
class Base { }
299+
class Derived : Base { }
297300

298-
switch [Derived(), Derived(), Base()] {
299-
case let ds as [Derived]: // expected-error{{collection downcast in cast pattern is not implemented; use an explicit downcast to '[Derived]' instead}}
300-
()
301-
case is [Derived]: // expected-error{{collection downcast in cast pattern is not implemented; use an explicit downcast to '[Derived]' instead}}
302-
()
301+
let arr: [Base]
303302

304-
default:
305-
()
306-
}
303+
if case let _ as [Derived] = arr {}
304+
// expected-warning@-1 {{'let' pattern has no effect; sub-pattern didn't bind any variables}}
305+
guard case let _ as [Derived] = arr else {}
306+
// expected-warning@-1 {{'let' pattern has no effect; sub-pattern didn't bind any variables}}
307+
while case let _ as [Derived] = arr {}
308+
// expected-warning@-1 {{'let' pattern has no effect; sub-pattern didn't bind any variables}}
309+
for case _ as [Derived] in [arr] {}
310+
311+
if case is [Derived] = arr {}
307312

313+
guard case is [Derived] = arr else {}
314+
315+
while case is [Derived] = arr {}
316+
317+
for case is [Derived] in [arr] {}
318+
319+
switch arr {
320+
case let ds as [Derived]:
321+
// expected-warning@-1 {{immutable value 'ds' was never used; consider replacing with '_' or removing it}}
322+
()
323+
case is [Derived]:
324+
()
325+
326+
default:
327+
()
328+
}
329+
330+
let _ = { (arr: [Base]) -> Void in
331+
switch arr {
332+
case let ds as [Derived]:
333+
// expected-warning@-1 {{immutable value 'ds' was never used; consider replacing with '_' or removing it}}
334+
()
335+
default:
336+
()
337+
}
338+
}
339+
}
308340

309341
// Optional patterns.
310342
let op1 : Int?

test/SILGen/statements.swift

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,103 @@ func test_as_pattern(_ y : BaseClass) -> DerivedClass {
657657
// CHECK-NEXT: return [[RESULT]] : $DerivedClass
658658
return result
659659
}
660+
661+
// https://github.com/apple/swift/issues/56139
662+
663+
// CHECK-LABEL: sil hidden [ossa] @$s10statements31test_isa_pattern_array_downcastyySayAA9BaseClassCGF : $@convention(thin) (@guaranteed Array<BaseClass>) -> () {
664+
func test_isa_pattern_array_downcast(_ arr: [BaseClass]) {
665+
// CHECK: [[ARR_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF:ss21_arrayConditionalCastySayq_GSgSayxGr0_lF]] : $@convention(thin) <τ_0_0, τ_0_1> (@guaranteed Array<τ_0_0>) -> @owned Optional<Array<τ_0_1>>
666+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[ARR_CAST_FN]]<BaseClass, DerivedClass>
667+
// CHECK-NEXT: switch_enum [[RESULT]]
668+
if case _ as [DerivedClass] = arr {}
669+
// CHECK: [[ARR_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
670+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[ARR_CAST_FN]]<BaseClass, DerivedClass>
671+
// CHECK-NEXT: switch_enum [[RESULT]]
672+
guard case _ as [DerivedClass] = arr else {}
673+
// CHECK: [[ARR_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
674+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[ARR_CAST_FN]]<BaseClass, DerivedClass>
675+
// CHECK-NEXT: switch_enum [[RESULT]]
676+
while case _ as [DerivedClass] = arr {}
677+
678+
// CHECK: [[ARR_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
679+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[ARR_CAST_FN]]<BaseClass, DerivedClass>
680+
// CHECK-NEXT: switch_enum [[RESULT]]
681+
if case is [DerivedClass] = arr {}
682+
// CHECK: [[ARR_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
683+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[ARR_CAST_FN]]<BaseClass, DerivedClass>
684+
// CHECK-NEXT: switch_enum [[RESULT]]
685+
guard case is [DerivedClass] = arr else {}
686+
// CHECK: [[ARR_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
687+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[ARR_CAST_FN]]<BaseClass, DerivedClass>
688+
// CHECK-NEXT: switch_enum [[RESULT]]
689+
while case is [DerivedClass] = arr {}
690+
}
691+
// CHECK: } // end sil function '$s10statements31test_isa_pattern_array_downcastyySayAA9BaseClassCGF'
692+
693+
// CHECK-LABEL: sil hidden [ossa] @$s10statements36test_isa_pattern_dictionary_downcastyySDySSAA9BaseClassCGF : $@convention(thin) (@guaranteed Dictionary<String, BaseClass>) -> () {
694+
func test_isa_pattern_dictionary_downcast(_ dict: Dictionary<String, BaseClass>) {
695+
// CHECK: [[DICT_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF:ss30_dictionaryDownCastConditionalySDyq0_q1_GSgSDyxq_GSHRzSHR0_r2_lF]] : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2, τ_0_3 where τ_0_0 : Hashable, τ_0_2 : Hashable> (@guaranteed Dictionary<τ_0_0, τ_0_1>) -> @owned Optional<Dictionary<τ_0_2, τ_0_3>>
696+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[DICT_CAST_FN]]<String, BaseClass, String, DerivedClass>
697+
// CHECK-NEXT: switch_enum [[RESULT]]
698+
if case _ as [String : DerivedClass] = dict {}
699+
// CHECK: [[DICT_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
700+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[DICT_CAST_FN]]<String, BaseClass, String, DerivedClass>
701+
// CHECK-NEXT: switch_enum [[RESULT]]
702+
guard case _ as [String : DerivedClass] = dict else {}
703+
// CHECK: [[DICT_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
704+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[DICT_CAST_FN]]<String, BaseClass, String, DerivedClass>
705+
// CHECK-NEXT: switch_enum [[RESULT]]
706+
while case _ as [String : DerivedClass] = dict {}
707+
708+
// CHECK: [[DICT_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
709+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[DICT_CAST_FN]]<String, BaseClass, String, DerivedClass>
710+
// CHECK-NEXT: switch_enum [[RESULT]]
711+
if case is [String : DerivedClass] = dict {}
712+
// CHECK: [[DICT_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
713+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[DICT_CAST_FN]]<String, BaseClass, String, DerivedClass>
714+
// CHECK-NEXT: switch_enum [[RESULT]]
715+
guard case is [String : DerivedClass] = dict else {}
716+
// CHECK: [[DICT_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
717+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[DICT_CAST_FN]]<String, BaseClass, String, DerivedClass>
718+
// CHECK-NEXT: switch_enum [[RESULT]]
719+
while case is [String : DerivedClass] = dict {}
720+
}
721+
// CHECK: } // end sil function '$s10statements36test_isa_pattern_dictionary_downcastyySDySSAA9BaseClassCGF'
722+
723+
// CHECK-LABEL: sil hidden [ossa] @$s10statements29test_isa_pattern_set_downcastyyShyxGSHRzlF : $@convention(thin) <T where T : Hashable> (@guaranteed Set<T>) -> () {
724+
func test_isa_pattern_set_downcast<T: Hashable>(_ set: Set<T>) {
725+
// CHECK: [[SET_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF:ss23_setDownCastConditionalyShyq_GSgShyxGSHRzSHR_r0_lF]] : $@convention(thin) <τ_0_0, τ_0_1 where τ_0_0 : Hashable, τ_0_1 : Hashable> (@guaranteed Set<τ_0_0>) -> @owned Optional<Set<τ_0_1>>
726+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SET_CAST_FN]]<T, Bool>
727+
// CHECK-NEXT: switch_enum [[RESULT]]
728+
if case let t as Set<Bool> = set {}
729+
// FIXME: Get rid of these warnings when https://github.com/apple/swift/issues/60808 is fixed
730+
// expected-warning@-2 {{immutable value 't' was never used; consider replacing with '_' or removing it}}
731+
// CHECK: [[SET_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
732+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SET_CAST_FN]]<T, Bool>
733+
// CHECK-NEXT: switch_enum [[RESULT]]
734+
guard case let t as Set<Bool> = set else {}
735+
// expected-warning@-1 {{immutable value 't' was never used; consider replacing with '_' or removing it}}
736+
// CHECK: [[SET_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
737+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SET_CAST_FN]]<T, Bool>
738+
// CHECK-NEXT: switch_enum [[RESULT]]
739+
while case let t as Set<Bool> = set {}
740+
// expected-warning@-1 {{immutable value 't' was never used; consider replacing with '_' or removing it}}
741+
742+
// CHECK: [[SET_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
743+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SET_CAST_FN]]<T, Int>
744+
// CHECK-NEXT: switch_enum [[RESULT]]
745+
if case is Set<Int> = set {}
746+
// CHECK: [[SET_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
747+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SET_CAST_FN]]<T, Int>
748+
// CHECK-NEXT: switch_enum [[RESULT]]
749+
guard case is Set<Int> = set else {}
750+
// CHECK: [[SET_CAST_FN:%[0-9]+]] = function_ref @$[[FN_REF]]
751+
// CHECK-NEXT: [[RESULT:%[0-9]+]] = apply [[SET_CAST_FN]]<T, Int>
752+
// CHECK-NEXT: switch_enum [[RESULT]]
753+
while case is Set<Int> = set {}
754+
}
755+
// CHECK: } // end sil function '$s10statements29test_isa_pattern_set_downcastyyShyxGSHRzlF'
756+
660757
// CHECK-LABEL: sil hidden [ossa] @$s10statements22let_else_tuple_bindingyS2i_SitSgF
661758
func let_else_tuple_binding(_ a : (Int, Int)?) -> Int {
662759

test/SILGen/switch.swift

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,133 @@ func test_isa_class_2(x: B) -> AnyObject {
635635
}
636636
// CHECK: } // end sil function '$s6switch16test_isa_class_21xyXlAA1BC_tF'
637637

638+
// https://github.com/apple/swift/issues/56139
639+
640+
// CHECK-LABEL: sil hidden [ossa] @$s6switch31test_isa_pattern_array_downcast2psySayAA1P_pG_tF : $@convention(thin) (@guaranteed Array<P>) -> () {
641+
func test_isa_pattern_array_downcast(ps: Array<P>) {
642+
// CHECK: bb0(%0 : @guaranteed $Array<P>):
643+
switch ps {
644+
// CHECK: checked_cast_addr_br copy_on_success Array<P> in [[P:%[0-9]+]] : $*Array<P> to Array<X> in {{%[0-9]+}} : $*Array<X>, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
645+
case is [X]:
646+
// CHECK: [[IS_X]]:
647+
// CHECK: function_ref @$s6switch1ayyF
648+
a()
649+
// CHECK: br [[CONT:bb[0-9]+]]
650+
651+
// CHECK: [[IS_NOT_X]]:
652+
// CHECK: [[DEST:%[0-9]+]] = alloc_stack $Array<Y>
653+
// CHECK-NEXT: checked_cast_addr_br copy_on_success Array<P> in [[P:%[0-9]+]] : $*Array<P> to Array<Y> in [[DEST]] : $*Array<Y>, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
654+
case let _ as [Y]:
655+
// CHECK: [[IS_Y]]:
656+
// CHECK-NEXT: load [take] [[DEST]] : $*Array<Y>
657+
// CHECK: function_ref @$s6switch1byyF
658+
b()
659+
// CHECK: br [[CONT]]
660+
default:
661+
// CHECK: [[IS_NOT_Y]]:
662+
// CHECK: function_ref @$s6switch1cyyF
663+
c()
664+
// CHECK: br [[CONT]]
665+
}
666+
// CHECK: [[CONT]]:
667+
// CHECK: function_ref @$s6switch1dyyF
668+
d()
669+
}
670+
// CHECK: } // end sil function '$s6switch31test_isa_pattern_array_downcast2psySayAA1P_pG_tF'
671+
672+
// CHECK-LABEL: sil hidden [ossa] @$s6switch39test_isa_pattern_array_downcast_closureyyF : $@convention(thin) () -> () {
673+
// CHECK: function_ref @$s6switch39test_isa_pattern_array_downcast_closureyyFySayAA1P_pGcfU_
674+
// CHECK: } // end sil function '$s6switch39test_isa_pattern_array_downcast_closureyyF'
675+
func test_isa_pattern_array_downcast_closure() {
676+
// CHECK-LABEL: sil private [ossa] @$s6switch39test_isa_pattern_array_downcast_closureyyFySayAA1P_pGcfU_ : $@convention(thin) (@guaranteed Array<P>) -> () {
677+
let _ = { (ps: [P]) -> Void in
678+
// CHECK: bb0(%0 : @guaranteed $Array<P>):
679+
switch ps {
680+
// CHECK: [[DEST:%[0-9]+]] = alloc_stack $Array<X>
681+
// CHECK-NEXT: checked_cast_addr_br copy_on_success Array<P> in [[P:%[0-9]+]] : $*Array<P> to Array<X> in [[DEST]] : $*Array<X>, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
682+
case let _ as [X]:
683+
// CHECK: [[IS_X]]:
684+
// CHECK-NEXT: load [take] [[DEST]] : $*Array<X>
685+
// CHECK: function_ref @$s6switch1ayyF
686+
a()
687+
// CHECK: br [[CONT:bb[0-9]+]]
688+
689+
// CHECK: [[IS_NOT_X]]:
690+
// CHECK: br [[DEF:bb[0-9]+]]
691+
default:
692+
// CHECK: [[DEF]]:
693+
// CHECK: function_ref @$s6switch1byyF
694+
b()
695+
// CHECK: br [[CONT]]
696+
}
697+
}
698+
// CHECK: } // end sil function '$s6switch39test_isa_pattern_array_downcast_closureyyFySayAA1P_pGcfU_'
699+
}
700+
701+
// CHECK-LABEL: sil hidden [ossa] @$s6switch30test_isa_pattern_dict_downcast2psySDySSAA1P_pG_tF : $@convention(thin) (@guaranteed Dictionary<String, P>) -> () {
702+
func test_isa_pattern_dict_downcast(ps: Dictionary<String, P>) {
703+
// CHECK: bb0(%0 : @guaranteed $Dictionary<String, P>):
704+
switch ps {
705+
// CHECK: checked_cast_addr_br copy_on_success Dictionary<String, P> in [[P:%[0-9]+]] : $*Dictionary<String, P> to Dictionary<String, X> in {{%[0-9]+}} : $*Dictionary<String, X>, [[IS_X:bb[0-9]+]], [[IS_NOT_X:bb[0-9]+]]
706+
case is [String : X]:
707+
// CHECK: [[IS_X]]:
708+
// CHECK: function_ref @$s6switch1ayyF
709+
a()
710+
// CHECK: br [[CONT:bb[0-9]+]]
711+
712+
// CHECK: [[IS_NOT_X]]:
713+
// CHECK: [[DEST:%[0-9]+]] = alloc_stack $Dictionary<String, Y>
714+
// CHECK-NEXT: checked_cast_addr_br copy_on_success Dictionary<String, P> in [[P:%[0-9]+]] : $*Dictionary<String, P> to Dictionary<String, Y> in [[DEST]] : $*Dictionary<String, Y>, [[IS_Y:bb[0-9]+]], [[IS_NOT_Y:bb[0-9]+]]
715+
case let _ as [String : Y]:
716+
// CHECK: [[IS_Y]]:
717+
// CHECK-NEXT: load [take] [[DEST]] : $*Dictionary<String, Y>
718+
// CHECK: function_ref @$s6switch1byyF
719+
b()
720+
// CHECK: br [[CONT]]
721+
default:
722+
// CHECK: [[IS_NOT_Y]]:
723+
// CHECK: function_ref @$s6switch1cyyF
724+
c()
725+
// CHECK: br [[CONT]]
726+
}
727+
// CHECK: [[CONT]]:
728+
// CHECK: function_ref @$s6switch1dyyF
729+
d()
730+
}
731+
// CHECK-LABEL: } // end sil function '$s6switch30test_isa_pattern_dict_downcast2psySDySSAA1P_pG_tF'
732+
733+
// CHECK-LABEL: sil hidden [ossa] @$s6switch29test_isa_pattern_set_downcast2psyShyxG_tSHRzlF : $@convention(thin) <T where T : Hashable> (@guaranteed Set<T>) -> () {
734+
func test_isa_pattern_set_downcast<T: Hashable>(ps: Set<T>) {
735+
// CHECK: bb0(%0 : @guaranteed $Set<T>):
736+
switch ps {
737+
// CHECK: checked_cast_addr_br copy_on_success Set<T> in [[P:%[0-9]+]] : $*Set<T> to Set<Int> in {{%[0-9]+}} : $*Set<Int>, [[IS_INT:bb[0-9]+]], [[IS_NOT_INT:bb[0-9]+]]
738+
case is Set<Int>:
739+
// CHECK: [[IS_INT]]:
740+
// CHECK: function_ref @$s6switch1ayyF
741+
a()
742+
// CHECK: br [[CONT:bb[0-9]+]]
743+
744+
// CHECK: [[IS_NOT_INT]]:
745+
// CHECK: [[DEST:%[0-9]+]] = alloc_stack $Set<Bool>
746+
// CHECK-NEXT: checked_cast_addr_br copy_on_success Set<T> in [[P:%[0-9]+]] : $*Set<T> to Set<Bool> in [[DEST]] : $*Set<Bool>, [[IS_BOOL:bb[0-9]+]], [[IS_NOT_BOOL:bb[0-9]+]]
747+
case let _ as Set<Bool>:
748+
// CHECK: [[IS_BOOL]]:
749+
// CHECK-NEXT: load [take] [[DEST]] : $*Set<Bool>
750+
// CHECK: function_ref @$s6switch1byyF
751+
b()
752+
// CHECK: br [[CONT]]
753+
default:
754+
// CHECK: [[IS_NOT_BOOL]]:
755+
// CHECK: function_ref @$s6switch1cyyF
756+
c()
757+
// CHECK: br [[CONT]]
758+
}
759+
// CHECK: [[CONT]]:
760+
// CHECK: function_ref @$s6switch1dyyF
761+
d()
762+
}
763+
// CHECK: } // end sil function '$s6switch29test_isa_pattern_set_downcast2psyShyxG_tSHRzlF'
764+
638765
enum MaybePair {
639766
case Neither
640767
case Left(Int)

0 commit comments

Comments
 (0)