Skip to content

Commit 3b415f0

Browse files
committed
Sema: Allow collection downcast in cast pattern and remove the diagnostic that it is not implemented
1 parent c11647f commit 3b415f0

File tree

5 files changed

+272
-26
lines changed

5 files changed

+272
-26
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4467,10 +4467,6 @@ NOTE(unowned_assignment_requires_strong,none,
44674467
"a strong reference is required to prevent the instance from being "
44684468
"deallocated", ())
44694469

4470-
ERROR(isa_collection_downcast_pattern_value_unimplemented,none,
4471-
"collection downcast in cast pattern is not implemented; use an explicit "
4472-
"downcast to %0 instead", (Type))
4473-
44744470
//------------------------------------------------------------------------------
44754471
// MARK: Error-handling diagnostics
44764472
//------------------------------------------------------------------------------

lib/Sema/TypeCheckPattern.cpp

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

test/Parse/matching_patterns.swift

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -289,22 +289,57 @@ 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+
310+
// FIXME: https://github.com/apple/swift/issues/61850
311+
// expected-warning@+1 {{heterogeneous collection literal could only be inferred to '[[Base]]'; add explicit type annotation if this is intentional}}
312+
for case _ as [Derived] in [arr] {}
313+
314+
if case is [Derived] = arr {}
315+
316+
guard case is [Derived] = arr else {}
317+
318+
while case is [Derived] = arr {}
319+
320+
for case is [Derived] in [arr] {}
321+
322+
switch arr {
323+
case let ds as [Derived]:
324+
// expected-warning@-1 {{immutable value 'ds' was never used; consider replacing with '_' or removing it}}
325+
()
326+
case is [Derived]:
327+
()
328+
329+
default:
330+
()
331+
}
307332

333+
let _ = { (arr: [Base]) -> Void in
334+
switch arr {
335+
case let ds as [Derived]:
336+
// expected-warning@-1 {{immutable value 'ds' was never used; consider replacing with '_' or removing it}}
337+
()
338+
default:
339+
()
340+
}
341+
}
342+
}
308343

309344
// Optional patterns.
310345
let op1 : Int?

test/SILGen/statements.swift

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

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<any P>) -> () {
641+
func test_isa_pattern_array_downcast(ps: Array<P>) {
642+
// CHECK: bb0(%0 : @guaranteed $Array<any P>):
643+
switch ps {
644+
// CHECK: checked_cast_addr_br copy_on_success Array<any P> in [[P:%[0-9]+]] : $*Array<any 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<any P> in [[P:%[0-9]+]] : $*Array<any 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<any P>) -> () {
677+
let _ = { (ps: [P]) -> Void in
678+
// CHECK: bb0(%0 : @guaranteed $Array<any P>):
679+
switch ps {
680+
// CHECK: [[DEST:%[0-9]+]] = alloc_stack $Array<X>
681+
// CHECK-NEXT: checked_cast_addr_br copy_on_success Array<any P> in [[P:%[0-9]+]] : $*Array<any 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, any P>) -> () {
702+
func test_isa_pattern_dict_downcast(ps: Dictionary<String, P>) {
703+
// CHECK: bb0(%0 : @guaranteed $Dictionary<String, any P>):
704+
switch ps {
705+
// CHECK: checked_cast_addr_br copy_on_success Dictionary<String, any P> in [[P:%[0-9]+]] : $*Dictionary<String, any 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, any P> in [[P:%[0-9]+]] : $*Dictionary<String, any 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)