@@ -25,6 +25,9 @@ extension ApplyInst : OnoneSimplifiable, SILCombineSimplifiable {
2525 if context. tryDevirtualize ( apply: self , isMandatory: false ) != nil {
2626 return
2727 }
28+ if tryRemoveArrayCast ( apply: self , context) {
29+ return
30+ }
2831 if !context. preserveDebugInfo {
2932 _ = tryReplaceExistentialArchetype ( of: self , context)
3033 }
@@ -73,6 +76,40 @@ private func tryTransformThickToThinCallee(of apply: ApplyInst, _ context: Simpl
7376 return false
7477}
7578
79+ /// Removes casts between arrays of the same type.
80+ ///
81+ /// %1 = function_ref @_arrayConditionalCast : (@guaranteed Array<Int>) -> @owned Optional<Array<Int>>
82+ /// %2 = apply %1(%0) : (@guaranteed Array<Int>) -> @owned Optional<Array<Int>>
83+ /// ->
84+ /// %1 = copy_value %0
85+ /// %2 = enum $Optional<Array<Int>>, #Optional.some!enumelt, %1
86+ ///
87+ private func tryRemoveArrayCast( apply: ApplyInst , _ context: SimplifyContext ) -> Bool {
88+ guard let callee = apply. referencedFunction,
89+ callee. hasSemanticsAttribute ( " array.conditional_cast " ) ,
90+ apply. parentFunction. hasOwnership,
91+
92+ // Check if the cast function has the expected calling convention
93+ apply. arguments. count == 1 ,
94+ apply. convention ( of: apply. argumentOperands [ 0 ] ) == . directGuaranteed,
95+ apply. functionConvention. results [ 0 ] . convention == . owned,
96+ apply. type. isOptional,
97+
98+ // Check if the source and target type of the cast is identical.
99+ // Note that we are checking the _formal_ element types and not the lowered types, because
100+ // the element types are replacement type in the Array's substitution map and this is a formal type.
101+ apply. arguments [ 0 ] . type == apply. type. optionalPayloadType ( in: apply. parentFunction)
102+ else {
103+ return false
104+ }
105+
106+ let builder = Builder ( after: apply, context)
107+ let copiedArray = builder. createCopyValue ( operand: apply. arguments [ 0 ] )
108+ let optional = builder. createEnum ( caseIndex: 1 , payload: copiedArray, enumType: apply. type)
109+ apply. replace ( with: optional, context)
110+ return true
111+ }
112+
76113/// If the apply uses an existential archetype (`@opened("...")`) and the concrete type is known,
77114/// replace the existential archetype with the concrete type
78115/// 1. in the apply's substitution map
@@ -199,3 +236,10 @@ private extension FullApplySite {
199236 return SubstitutionMap ( genericSignature: genSig, replacementTypes: newReplacementTypes)
200237 }
201238}
239+
240+ private extension Type {
241+ func optionalPayloadType( in function: Function ) -> Type {
242+ let subs = contextSubstitutionMap
243+ return subs. replacementTypes [ 0 ] . loweredType ( in: function)
244+ }
245+ }
0 commit comments