mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This PR refactors the ASTDumper to make it more structured, less mistake-prone, and more amenable to future changes. For example:
```cpp
// Before:
void visitUnresolvedDotExpr(UnresolvedDotExpr *E) {
printCommon(E, "unresolved_dot_expr")
<< " field '" << E->getName() << "'";
PrintWithColorRAII(OS, ExprModifierColor)
<< " function_ref=" << getFunctionRefKindStr(E->getFunctionRefKind());
if (E->getBase()) {
OS << '\n';
printRec(E->getBase());
}
PrintWithColorRAII(OS, ParenthesisColor) << ')';
}
// After:
void visitUnresolvedDotExpr(UnresolvedDotExpr *E, StringRef label) {
printCommon(E, "unresolved_dot_expr", label);
printFieldQuoted(E->getName(), "field");
printField(E->getFunctionRefKind(), "function_ref", ExprModifierColor);
if (E->getBase()) {
printRec(E->getBase());
}
printFoot();
}
```
* Values are printed through calls to base class methods, rather than direct access to the underlying `raw_ostream`.
* These methods tend to reduce the chances of bugs like missing/extra spaces or newlines, too much/too little indentation, etc.
* More values are quoted, and unprintable/non-ASCII characters in quoted values are escaped before printing.
* Infrastructure to label child nodes now exists.
* Some weird breaks from the normal "style", like `PatternBindingDecl`'s original and processed initializers, have been brought into line.
* Some types that previously used ad-hoc dumping functions, like conformances and substitution maps, are now structured similarly to the dumper classes.
* I've fixed the odd dumping bug along the way. For example, distributed actors were only marked `actor`, not `distributed actor`.
This PR doesn't change the overall style of AST dumps; they're still pseudo-S-expressions. But the logic that implements this style is now isolated into a relatively small base class, making it feasible to introduce e.g. JSON dumping in the future.
799 lines
48 KiB
Plaintext
799 lines
48 KiB
Plaintext
// RUN: %target-sil-opt -enable-objc-interop -enable-sil-verify-all %s -sil-combine -sil-print-generic-specialization-info | %FileCheck %s
|
|
// RUN: %target-swift-frontend -O %s -emit-ir
|
|
|
|
// REQUIRES: swift_in_compiler
|
|
|
|
// These tests exercise the same SILCombine optimization as
|
|
// existential_type_propagation.sil, but cover additional corner
|
|
// cases. These are pure unit tests. They do not run the devirtualizer
|
|
// or inliner.
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
import SwiftShims
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// testReturnSelf: Call to a protocol extension method with
|
|
// an existential self that can be type-propagated.
|
|
// SILCombine should bailout since it does not propagate
|
|
// type substitutions on the return value.
|
|
//
|
|
// rdar://40555427
|
|
// https://github.com/apple/swift/issues/50312
|
|
// 'SILCombiner::propagateConcreteTypeOfInitExistential' fails to fully
|
|
// propagate type substitutions.
|
|
//===----------------------------------------------------------------------===//
|
|
public protocol P : AnyObject {
|
|
}
|
|
|
|
extension P {
|
|
public func returnSelf() -> Self
|
|
}
|
|
|
|
final class C : P {
|
|
init()
|
|
deinit
|
|
}
|
|
|
|
public func testReturnSelf() -> P
|
|
|
|
// P.returnSelf()
|
|
sil @$s21extension_return_self1PPAAE0B4SelfxyF : $@convention(method) <Self where Self : P> (@guaranteed Self) -> @owned Self
|
|
|
|
// C.__allocating_init()
|
|
sil @$s21extension_return_self1CCACycfC : $@convention(method) (@thick C.Type) -> @owned C
|
|
|
|
// public func testReturnSelf() -> P {
|
|
// let p: P = C()
|
|
// return p.returnSelf().returnSelf()
|
|
// }
|
|
// Neither apply responds to type propagation.
|
|
//
|
|
// CHECK-LABEL: sil @$s21extension_return_self14testReturnSelfAA1P_pyF : $@convention(thin) () -> @owned any P {
|
|
// CHECK: [[E1:%.*]] = init_existential_ref %{{.*}} : $C : $C, $any P
|
|
// CHECK: [[O1:%.*]] = open_existential_ref [[E1]] : $any P to $@opened("{{.*}}", any P) Self
|
|
// CHECK: [[F1:%.*]] = function_ref @$s21extension_return_self1PPAAE0B4SelfxyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
|
|
// CHECK: [[C1:%.*]] = apply [[F1]]<@opened("{{.*}}", any P) Self>([[O1]]) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
|
|
// CHECK: [[E2:%.*]] = init_existential_ref [[C1]] : $@opened("{{.*}}", any P) Self : $@opened("{{.*}}", any P) Self, $any P
|
|
// CHECK: [[O2:%.*]] = open_existential_ref [[E2]] : $any P to $@opened("{{.*}}", any P) Self
|
|
// CHECK: [[F2:%.*]] = function_ref @$s21extension_return_self1PPAAE0B4SelfxyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
|
|
// CHECK: apply [[F2]]<@opened("{{.*}}", any P) Self>([[O2]]) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
|
|
// CHECK-LABEL: } // end sil function '$s21extension_return_self14testReturnSelfAA1P_pyF'
|
|
sil @$s21extension_return_self14testReturnSelfAA1P_pyF : $@convention(thin) () -> @owned P {
|
|
bb0:
|
|
%0 = metatype $@thick C.Type
|
|
// function_ref C.__allocating_init()
|
|
%1 = function_ref @$s21extension_return_self1CCACycfC : $@convention(method) (@thick C.Type) -> @owned C
|
|
%2 = apply %1(%0) : $@convention(method) (@thick C.Type) -> @owned C
|
|
%3 = init_existential_ref %2 : $C : $C, $P
|
|
%5 = open_existential_ref %3 : $P to $@opened("1217498E-72AC-11E8-9816-ACDE48001122", P) Self
|
|
// function_ref P.returnSelf()
|
|
%6 = function_ref @$s21extension_return_self1PPAAE0B4SelfxyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
|
|
%7 = apply %6<@opened("1217498E-72AC-11E8-9816-ACDE48001122", P) Self>(%5) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
|
|
%8 = init_existential_ref %7 : $@opened("1217498E-72AC-11E8-9816-ACDE48001122", P) Self : $@opened("1217498E-72AC-11E8-9816-ACDE48001122", P) Self, $P
|
|
%9 = open_existential_ref %8 : $P to $@opened("12174BD2-72AC-11E8-9816-ACDE48001122", P) Self
|
|
// function_ref P.returnSelf()
|
|
%10 = function_ref @$s21extension_return_self1PPAAE0B4SelfxyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
|
|
%11 = apply %10<@opened("12174BD2-72AC-11E8-9816-ACDE48001122", P) Self>(%9) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@guaranteed τ_0_0) -> @owned τ_0_0
|
|
%12 = init_existential_ref %11 : $@opened("12174BD2-72AC-11E8-9816-ACDE48001122", P) Self : $@opened("12174BD2-72AC-11E8-9816-ACDE48001122", P) Self, $P
|
|
strong_release %9 : $@opened("12174BD2-72AC-11E8-9816-ACDE48001122", P) Self
|
|
strong_release %3 : $P
|
|
return %12 : $P
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// testWitnessReturnOptionalSelf: Call to a witness method with an existential
|
|
// self that can be type-propagated. SILCombine should bailout since it does
|
|
// not propagate type substitutions on the return value, and it must walk the
|
|
// Optional type to find Self in the return type.
|
|
//===----------------------------------------------------------------------===//
|
|
public protocol PP : AnyObject {
|
|
func returnOptionalSelf() -> Self?
|
|
}
|
|
|
|
final class CC : PP {
|
|
init()
|
|
final func returnOptionalSelf() -> Self?
|
|
deinit
|
|
}
|
|
|
|
public func testWitnessReturnOptionalSelf() -> PP?
|
|
|
|
// CC.__allocating_init()
|
|
sil @$s28witness_return_optional_self2CCCACycfC : $@convention(method) (@thick CC.Type) -> @owned CC
|
|
|
|
// public func testWitnessReturnOptionalSelf() -> PP? {
|
|
// let p: PP = CC()
|
|
// return p.returnOptionalSelf()?.returnOptionalSelf()
|
|
// }
|
|
//
|
|
// Although SILCombine will not replace the self operand, it will still
|
|
// rewrite the witness_method.
|
|
//
|
|
// The first witness_method is rewritten for the concrete lookup type 'CC'.
|
|
//
|
|
// The second witness_method is rewritten for the first opened existential type.
|
|
// Neither apply is rewritten.
|
|
//
|
|
// CHECK-LABEL: sil @$s28witness_return_optional_self29testWitnessReturnOptionalSelfAA2PP_pSgyF : $@convention(thin) () -> @owned Optional<any PP> {
|
|
// CHECK: [[E1:%.*]] = init_existential_ref %{{.*}} : $CC : $CC, $any PP
|
|
// CHECK: [[O1:%.*]] = open_existential_ref [[E1]] : $any PP to $@opened("{{.*}}", any PP) Self
|
|
// CHECK: [[W1:%.*]] = witness_method $CC, #PP.returnOptionalSelf : <Self where Self : PP> (Self) -> () -> Self? : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> @owned Optional<τ_0_0>
|
|
// CHECK: apply [[W1]]<@opened("{{.*}}", any PP) Self>([[O1]]) : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> @owned Optional<τ_0_0>
|
|
// CHECK: [[E2:%.*]] = init_existential_ref %{{.*}} : $@opened("{{.*}}", any PP) Self : $@opened("{{.*}}", any PP) Self, $any PP
|
|
// CHECK: [[O2:%.*]] = open_existential_ref [[E2]] : $any PP to $@opened("{{.*}}", any PP) Self
|
|
// CHECK: [[W2:%.*]] = witness_method $@opened("{{.*}}", any PP) Self, #PP.returnOptionalSelf : <Self where Self : PP> (Self) -> () -> Self?, [[O1]] : $@opened("{{.*}}", any PP) Self : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> @owned Optional<τ_0_0>
|
|
// CHECK: apply [[W2]]<@opened("{{.*}}", any PP) Self>([[O2]]) : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> @owned Optional<τ_0_0>
|
|
// CHECK-LABEL: } // end sil function '$s28witness_return_optional_self29testWitnessReturnOptionalSelfAA2PP_pSgyF'
|
|
sil @$s28witness_return_optional_self29testWitnessReturnOptionalSelfAA2PP_pSgyF : $@convention(thin) () -> @owned Optional<PP> {
|
|
bb0:
|
|
%0 = metatype $@thick CC.Type
|
|
// function_ref CC.__allocating_init()
|
|
%1 = function_ref @$s28witness_return_optional_self2CCCACycfC : $@convention(method) (@thick CC.Type) -> @owned CC
|
|
%2 = apply %1(%0) : $@convention(method) (@thick CC.Type) -> @owned CC
|
|
%3 = init_existential_ref %2 : $CC : $CC, $PP
|
|
%5 = open_existential_ref %3 : $PP to $@opened("00000000-72AD-11E8-88DF-ACDE48001122", PP) Self
|
|
%6 = witness_method $@opened("00000000-72AD-11E8-88DF-ACDE48001122", PP) Self, #PP.returnOptionalSelf : <Self where Self : PP> (Self) -> () -> Self?, %5 : $@opened("00000000-72AD-11E8-88DF-ACDE48001122", PP) Self : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> @owned Optional<τ_0_0>
|
|
%7 = apply %6<@opened("00000000-72AD-11E8-88DF-ACDE48001122", PP) Self>(%5) : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> @owned Optional<τ_0_0>
|
|
%8 = unchecked_enum_data %7 : $Optional<@opened("00000000-72AD-11E8-88DF-ACDE48001122", PP) Self>, #Optional.some!enumelt
|
|
%11 = init_existential_ref %8 : $@opened("00000000-72AD-11E8-88DF-ACDE48001122", PP) Self : $@opened("00000000-72AD-11E8-88DF-ACDE48001122", PP) Self, $PP
|
|
%12 = enum $Optional<PP>, #Optional.some!enumelt, %11 : $PP
|
|
%13 = unchecked_enum_data %12 : $Optional<PP>, #Optional.some!enumelt
|
|
%18 = open_existential_ref %13 : $PP to $@opened("FFFFFFFF-72AD-11E8-88DF-ACDE48001122", PP) Self
|
|
%19 = witness_method $@opened("FFFFFFFF-72AD-11E8-88DF-ACDE48001122", PP) Self, #PP.returnOptionalSelf : <Self where Self : PP> (Self) -> () -> Self?, %18 : $@opened("FFFFFFFF-72AD-11E8-88DF-ACDE48001122", PP) Self : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> @owned Optional<τ_0_0>
|
|
%20 = apply %19<@opened("FFFFFFFF-72AD-11E8-88DF-ACDE48001122", PP) Self>(%18) : $@convention(witness_method: PP) <τ_0_0 where τ_0_0 : PP> (@guaranteed τ_0_0) -> @owned Optional<τ_0_0>
|
|
%21 = unchecked_enum_data %20 : $Optional<@opened("FFFFFFFF-72AD-11E8-88DF-ACDE48001122", PP) Self>, #Optional.some!enumelt
|
|
%22 = init_existential_ref %21 : $@opened("FFFFFFFF-72AD-11E8-88DF-ACDE48001122", PP) Self : $@opened("FFFFFFFF-72AD-11E8-88DF-ACDE48001122", PP) Self, $PP
|
|
%23 = enum $Optional<PP>, #Optional.some!enumelt, %22 : $PP
|
|
strong_release %18 : $@opened("FFFFFFFF-72AD-11E8-88DF-ACDE48001122", PP) Self
|
|
strong_release %3 : $PP
|
|
return %23 : $Optional<PP>
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// testWitnessReturnOptionalIndirectSelf: Call to a witness method with an
|
|
// existential self that can be type-propagated. SILCombine should bailout
|
|
// since it does not propagate type substitutions on non-self arguments. It must
|
|
// walk the Optional type to find Self in the non-self argument.
|
|
//===----------------------------------------------------------------------===//
|
|
protocol PPP {
|
|
func returnsOptionalIndirect() -> Self?
|
|
}
|
|
|
|
struct S : PPP {
|
|
func returnsOptionalIndirect() -> S?
|
|
init()
|
|
}
|
|
|
|
public func testWitnessReturnOptionalIndirectSelf()
|
|
|
|
// S.init()
|
|
sil @$s37witness_return_optional_indirect_self1SVACycfC : $@convention(method) (@thin S.Type) -> S
|
|
|
|
// testWitnessReturnOptionalIndirectSelf()
|
|
// public func testWitnessReturnOptionalIndirectSelf() {
|
|
// let p: PPP = S()
|
|
// p.returnsOptionalIndirect()?.returnsOptionalIndirect()
|
|
// }
|
|
//
|
|
// Although SILCombine will not replace the self operand, it will still
|
|
// rewrite the witness_method. The devirtualizer could then handle the first call.
|
|
//
|
|
// CHECK-LABEL: sil @$s37witness_return_optional_indirect_self37testWitnessReturnOptionalIndirectSelfyyF : $@convention(thin) () -> () {
|
|
// CHECK: [[O1:%.*]] = open_existential_addr immutable_access %0 : $*any PPP to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", any PPP) Self
|
|
// CHECK: [[R1:%.*]] = alloc_stack $Optional<@opened("83DE9694-7315-11E8-955C-ACDE48001122", any PPP) Self>
|
|
// CHECK: [[W1:%.*]] = witness_method $S, #PPP.returnsOptionalIndirect : <Self where Self : PPP> (Self) -> () -> Self? : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
|
|
// CHECK: apply [[W1]]<@opened("83DE9694-7315-11E8-955C-ACDE48001122", any PPP) Self>([[R1]], [[O1]]) : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
|
|
// CHECK: [[E1:%.*]] = unchecked_take_enum_data_addr
|
|
// CHECK: [[O2:%.*]] = open_existential_addr immutable_access {{.*}} : $*any PPP to $*@opened("83DE97CA-7315-11E8-955C-ACDE48001122", any PPP) Self
|
|
// CHECK: [[R2:%.*]] = alloc_stack $Optional<@opened("83DE97CA-7315-11E8-955C-ACDE48001122", any PPP) Self>
|
|
// CHECK: [[W2:%.*]] = witness_method $@opened("{{.*}}", any PPP) Self, #PPP.returnsOptionalIndirect
|
|
// CHECK: apply [[W2]]<@opened("83DE97CA-7315-11E8-955C-ACDE48001122", any PPP) Self>([[R2]], [[O2]]) : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
|
|
// CHECK-LABEL: } // end sil function '$s37witness_return_optional_indirect_self37testWitnessReturnOptionalIndirectSelfyyF'
|
|
sil @$s37witness_return_optional_indirect_self37testWitnessReturnOptionalIndirectSelfyyF : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = alloc_stack $PPP, let, name "p"
|
|
%1 = init_existential_addr %0 : $*PPP, $S
|
|
%2 = metatype $@thin S.Type
|
|
// function_ref S.init()
|
|
%3 = function_ref @$s37witness_return_optional_indirect_self1SVACycfC : $@convention(method) (@thin S.Type) -> S
|
|
%4 = apply %3(%2) : $@convention(method) (@thin S.Type) -> S
|
|
store %4 to %1 : $*S
|
|
%6 = alloc_stack $Optional<PPP>
|
|
%7 = alloc_stack $Optional<PPP>
|
|
%8 = open_existential_addr immutable_access %0 : $*PPP to $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self
|
|
%9 = init_enum_data_addr %7 : $*Optional<PPP>, #Optional.some!enumelt
|
|
%10 = init_existential_addr %9 : $*PPP, $@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self
|
|
%11 = alloc_stack $Optional<@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self>
|
|
%12 = witness_method $@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self, #PPP.returnsOptionalIndirect : <Self where Self : PPP> (Self) -> () -> Self?, %8 : $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
|
|
%13 = apply %12<@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self>(%11, %8) : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
|
|
%14 = unchecked_take_enum_data_addr %11 : $*Optional<@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self>, #Optional.some!enumelt
|
|
copy_addr [take] %14 to [init] %10 : $*@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self
|
|
inject_enum_addr %7 : $*Optional<PPP>, #Optional.some!enumelt
|
|
dealloc_stack %11 : $*Optional<@opened("83DE9694-7315-11E8-955C-ACDE48001122", PPP) Self>
|
|
%28 = unchecked_take_enum_data_addr %7 : $*Optional<PPP>, #Optional.some!enumelt
|
|
%29 = open_existential_addr immutable_access %28 : $*PPP to $*@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self
|
|
%30 = init_enum_data_addr %6 : $*Optional<PPP>, #Optional.some!enumelt
|
|
%31 = init_existential_addr %30 : $*PPP, $@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self
|
|
%32 = alloc_stack $Optional<@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self>
|
|
%33 = witness_method $@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self, #PPP.returnsOptionalIndirect : <Self where Self : PPP> (Self) -> () -> Self?, %29 : $*@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
|
|
%34 = apply %33<@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self>(%32, %29) : $@convention(witness_method: PPP) <τ_0_0 where τ_0_0 : PPP> (@in_guaranteed τ_0_0) -> @out Optional<τ_0_0>
|
|
%41 = unchecked_take_enum_data_addr %32 : $*Optional<@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self>, #Optional.some!enumelt
|
|
copy_addr [take] %41 to [init] %31 : $*@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self
|
|
inject_enum_addr %6 : $*Optional<PPP>, #Optional.some!enumelt
|
|
dealloc_stack %32 : $*Optional<@opened("83DE97CA-7315-11E8-955C-ACDE48001122", PPP) Self>
|
|
destroy_addr %28 : $*PPP
|
|
dealloc_stack %7 : $*Optional<PPP>
|
|
destroy_addr %6 : $*Optional<PPP>
|
|
dealloc_stack %6 : $*Optional<PPP>
|
|
destroy_addr %0 : $*PPP
|
|
dealloc_stack %0 : $*PPP
|
|
%52 = tuple ()
|
|
return %52 : $()
|
|
}
|
|
|
|
|
|
// ===----------------------------------------------------------------------===//
|
|
// testOptionalSelfArg: Call a protocol extension method with an
|
|
// existential self that can be type-propagated. SILCombine should
|
|
// bailout since it does not know how to rewrite non-self operands.
|
|
// SILCombine would previously generate incorrect SIL because it did
|
|
// not properly walk all types in the function signature to find
|
|
// dependencies on the Self type.
|
|
// ===----------------------------------------------------------------------===//
|
|
protocol PPPP {}
|
|
|
|
extension PPPP {
|
|
func takeOptionalSelf(_ s: Self?)
|
|
}
|
|
|
|
class CCCC : PPPP {
|
|
init()
|
|
deinit
|
|
}
|
|
|
|
sil [noinline] @takeOptionalSelf : $@convention(method) <Self where Self : PPPP> (@in_guaranteed Optional<Self>, @in_guaranteed Self) -> ()
|
|
|
|
// CHECK-LABEL: sil @testOptionalSelfArg : $@convention(thin) (@guaranteed CCCC) -> () {
|
|
// CHECK: init_existential_addr [[A:%.*]] : $*any PPPP, $CCCC // user: %4
|
|
// CHECK: [[OE:%.*]] = open_existential_addr immutable_access [[A]] : $*any PPPP to $*@opened("{{.*}}", any PPPP) Self // users: %11, %11, %8, %6
|
|
// CHECK: [[F:%.*]] = function_ref @takeOptionalSelf : $@convention(method) <τ_0_0 where τ_0_0 : PPPP> (@in_guaranteed Optional<τ_0_0>, @in_guaranteed τ_0_0) -> () // user: %11
|
|
// CHECK: apply [[F]]<@opened("{{.*}}", any PPPP) Self>(%{{.*}}, [[OE]]) : $@convention(method) <τ_0_0 where τ_0_0 : PPPP> (@in_guaranteed Optional<τ_0_0>, @in_guaranteed τ_0_0) -> () // type-defs: %5
|
|
// CHECK-LABEL: } // end sil function 'testOptionalSelfArg'
|
|
sil @testOptionalSelfArg : $@convention(thin) (@guaranteed CCCC) -> () {
|
|
bb0(%0 : $CCCC):
|
|
strong_retain %0 : $CCCC
|
|
|
|
%pa = alloc_stack $PPPP, let, name "p"
|
|
%ea = init_existential_addr %pa : $*PPPP, $CCCC
|
|
store %0 to %ea : $*CCCC
|
|
%oe = open_existential_addr immutable_access %pa : $*PPPP to $*@opened("A6DDDAF6-70BD-11E8-ADF1-ACDE48001122", PPPP) Self
|
|
|
|
%optional = alloc_stack $Optional<@opened("A6DDDAF6-70BD-11E8-ADF1-ACDE48001122", PPPP) Self>
|
|
%someadr = init_enum_data_addr %optional : $*Optional<@opened("A6DDDAF6-70BD-11E8-ADF1-ACDE48001122", PPPP) Self>, #Optional.some!enumelt
|
|
copy_addr %oe to [init] %someadr : $*@opened("A6DDDAF6-70BD-11E8-ADF1-ACDE48001122", PPPP) Self
|
|
inject_enum_addr %optional : $*Optional<@opened("A6DDDAF6-70BD-11E8-ADF1-ACDE48001122", PPPP) Self>, #Optional.some!enumelt
|
|
|
|
%f = function_ref @takeOptionalSelf : $@convention(method) <τ_0_0 where τ_0_0 : PPPP> (@in_guaranteed Optional<τ_0_0>, @in_guaranteed τ_0_0) -> ()
|
|
%call = apply %f<@opened("A6DDDAF6-70BD-11E8-ADF1-ACDE48001122", PPPP) Self>(%optional, %oe) : $@convention(method) <τ_0_0 where τ_0_0 : PPPP> (@in_guaranteed Optional<τ_0_0>, @in_guaranteed τ_0_0) -> ()
|
|
|
|
destroy_addr %optional : $*Optional<@opened("A6DDDAF6-70BD-11E8-ADF1-ACDE48001122", PPPP) Self>
|
|
dealloc_stack %optional : $*Optional<@opened("A6DDDAF6-70BD-11E8-ADF1-ACDE48001122", PPPP) Self>
|
|
|
|
destroy_addr %pa : $*PPPP
|
|
dealloc_stack %pa : $*PPPP
|
|
%10 = tuple ()
|
|
return %10 : $()
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// testExtensionProtocolComposition: Call to a witness method with an
|
|
// existential self that can be type-propagated. Handle an existential with
|
|
// multiple conformances.
|
|
//
|
|
// This previously crashed in SILCombiner::propagateConcreteTypeOfInitExistential
|
|
// with assertion failed: (proto == Conformance.getRequirement()).
|
|
// ===----------------------------------------------------------------------===//
|
|
public protocol Q {}
|
|
|
|
extension P where Self : Q {
|
|
public func witnessComposition() {}
|
|
}
|
|
|
|
public class C_PQ: P & Q {}
|
|
|
|
// P<>.witnessComposition()
|
|
sil @$s32sil_combine_concrete_existential1PPA2A1QRzrlE18witnessCompositionyyF : $@convention(method) <τ_0_0 where τ_0_0 : P, τ_0_0 : Q> (@guaranteed τ_0_0) -> ()
|
|
|
|
// testExtensionProtocolComposition(c:)
|
|
// public func testExtensionProtocolComposition(c: C_PQ) {
|
|
// let pp: P & Q = c
|
|
// pp.witnessComposition()
|
|
// }
|
|
//
|
|
// SILCombine substitutes the applies opened extension parameter with a concrete type <C : P & Q>
|
|
// CHECK-LABEL: sil @$s32sil_combine_concrete_existential32testExtensionProtocolComposition1cyAA4C_PQC_tF : $@convention(thin) (@guaranteed C_PQ) -> () {
|
|
// CHECK-NOT: init_existential_ref
|
|
// CHECK-NOT: open_existential_ref
|
|
// function_ref P<>.witnessComposition()
|
|
// CHECK: [[F:%.*]] = function_ref @$s32sil_combine_concrete_existential1PPA2A1QRzrlE18witnessCompositionyyF : $@convention(method) <τ_0_0 where τ_0_0 : P, τ_0_0 : Q> (@guaranteed τ_0_0) -> ()
|
|
// CHECK: apply [[F]]<C_PQ>(%0) : $@convention(method) <τ_0_0 where τ_0_0 : P, τ_0_0 : Q> (@guaranteed τ_0_0) -> ()
|
|
// CHECK-LABEL: } // end sil function '$s32sil_combine_concrete_existential32testExtensionProtocolComposition1cyAA4C_PQC_tF'
|
|
sil @$s32sil_combine_concrete_existential32testExtensionProtocolComposition1cyAA4C_PQC_tF : $@convention(thin) (@guaranteed C_PQ) -> () {
|
|
bb0(%0 : $C_PQ):
|
|
strong_retain %0 : $C_PQ
|
|
%3 = init_existential_ref %0 : $C_PQ : $C_PQ, $P & Q
|
|
%5 = open_existential_ref %3 : $P & Q to $@opened("044D530E-7327-11E8-A998-ACDE48001122", P & Q) Self
|
|
// function_ref P<>.witnessCompositionOwned()
|
|
%6 = function_ref @$s32sil_combine_concrete_existential1PPA2A1QRzrlE18witnessCompositionyyF : $@convention(method) <τ_0_0 where τ_0_0 : P, τ_0_0 : Q> (@guaranteed τ_0_0) -> ()
|
|
%7 = apply %6<@opened("044D530E-7327-11E8-A998-ACDE48001122", P & Q) Self>(%5) : $@convention(method) <τ_0_0 where τ_0_0 : P, τ_0_0 : Q> (@guaranteed τ_0_0) -> ()
|
|
strong_release %3 : $P & Q
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
// ===----------------------------------------------------------------------===//
|
|
// testDefaultStaticMethod: Test concrete type propagation into a direct
|
|
// apply of a default witness method.
|
|
// ===----------------------------------------------------------------------===//
|
|
public protocol PDefaultStatic: class {
|
|
static func witnessDefaultStatic()
|
|
}
|
|
|
|
extension PDefaultStatic {
|
|
@inline(never)
|
|
public static func witnessDefaultStatic() {}
|
|
}
|
|
|
|
public class CDefaultStatic : PDefaultStatic {}
|
|
|
|
public func callDefaultStatic() {
|
|
return CDefaultStatic.witnessDefaultStatic()
|
|
}
|
|
|
|
// static P<>.witnessDefaultStatic(_:)
|
|
sil @witnessDefaultStatic : $@convention(method) <Self where Self : PDefaultStatic> (@thick Self.Type) -> ()
|
|
|
|
// CHECK-LABEL: sil @testDefaultStaticMethod : $@convention(thin) () -> () {
|
|
// CHECK: %0 = metatype $@thick CDefaultStatic.Type
|
|
// CHECK-NOT: init_existential_metatype
|
|
// CHECK-NOT: open_existential_metatype
|
|
// CHECK: [[F:%.*]] = function_ref @witnessDefaultStatic : $@convention(method) <τ_0_0 where τ_0_0 : PDefaultStatic> (@thick τ_0_0.Type) -> ()
|
|
// CHECK: apply [[F]]<CDefaultStatic>(%0) : $@convention(method) <τ_0_0 where τ_0_0 : PDefaultStatic> (@thick τ_0_0.Type) -> ()
|
|
// CHECK-LABEL: } // end sil function 'testDefaultStaticMethod'
|
|
sil @testDefaultStaticMethod : $@convention(thin) () -> () {
|
|
bb0:
|
|
%mt = metatype $@thick CDefaultStatic.Type
|
|
%em = init_existential_metatype %mt : $@thick CDefaultStatic.Type, $@thick PDefaultStatic.Type
|
|
%om = open_existential_metatype %em : $@thick PDefaultStatic.Type to $@thick (@opened("22222222-72AC-11E8-9816-ACDE48001122", PDefaultStatic) Self).Type
|
|
%f = function_ref @witnessDefaultStatic : $@convention(method) <Self where Self : PDefaultStatic> (@thick Self.Type) -> ()
|
|
%call = apply %f<@opened("22222222-72AC-11E8-9816-ACDE48001122", PDefaultStatic) Self>(%om) : $@convention(method) <Self where Self : PDefaultStatic> (@thick Self.Type) -> ()
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// testWitnessCopiedSelfWithIndirectResult: Call to a witness method
|
|
// with an existential self that can be type-propagated. Exercise
|
|
// `SILCombiner::canReplaceArg` when `self` is not in argument position zero.
|
|
//
|
|
// rdar://45415719 Assertion failed: (Index < Length && "Invalid index!")
|
|
// ===----------------------------------------------------------------------===//
|
|
|
|
protocol AnyP {
|
|
func returnsSelf() -> Self
|
|
}
|
|
|
|
struct StructOfAnyP : AnyP {
|
|
func returnsSelf() -> StructOfAnyP
|
|
}
|
|
|
|
// CHECK-LABEL: sil @testWitnessCopiedSelfWithIndirectResult : $@convention(thin) () -> () {
|
|
// CHECK: [[IN:%[0-9]+]] = alloc_stack $StructOfAnyP
|
|
// CHECK: [[OUT:%[0-9]+]] = alloc_stack $StructOfAnyP
|
|
// CHECK: witness_method $StructOfAnyP, #AnyP.returnsSelf : <Self where Self : AnyP> (Self) -> () -> Self : $@convention(witness_method: AnyP) <τ_0_0 where τ_0_0 : AnyP> (@in_guaranteed τ_0_0) -> @out StructOfAnyP
|
|
// CHECK: apply %{{.*}}<StructOfAnyP>([[OUT]], [[IN]]) : $@convention(witness_method: AnyP) <τ_0_0 where τ_0_0 : AnyP> (@in_guaranteed τ_0_0) -> @out StructOfAnyP
|
|
// CHECK-LABEL: } // end sil function 'testWitnessCopiedSelfWithIndirectResult'
|
|
sil @testWitnessCopiedSelfWithIndirectResult : $() -> () {
|
|
bb0:
|
|
%a0 = alloc_stack $AnyP
|
|
%ie0 = init_existential_addr %a0 : $*AnyP, $StructOfAnyP
|
|
%a1 = alloc_stack $AnyP
|
|
copy_addr %a0 to [init] %a1 : $*AnyP
|
|
%o0 = open_existential_addr immutable_access %a1 : $*AnyP to $*@opened("7C4DAF8E-D722-11E8-920A-D0817AD9F6DD", AnyP) Self
|
|
%a2 = alloc_stack $StructOfAnyP
|
|
%w0 = witness_method $@opened("7C4DAF8E-D722-11E8-920A-D0817AD9F6DD", AnyP) Self, #AnyP.returnsSelf : <Self where Self : AnyP> (Self) -> () -> Self, %o0 : $*@opened("7C4DAF8E-D722-11E8-920A-D0817AD9F6DD", AnyP) Self : $@convention(witness_method: AnyP) <τ_0_0 where τ_0_0 : AnyP> (@in_guaranteed τ_0_0) -> @out StructOfAnyP
|
|
%c0 = apply %w0<@opened("7C4DAF8E-D722-11E8-920A-D0817AD9F6DD", AnyP) Self>(%a2, %o0) : $@convention(witness_method: AnyP) <τ_0_0 where τ_0_0 : AnyP> (@in_guaranteed τ_0_0) -> @out StructOfAnyP
|
|
dealloc_stack %a2 : $*StructOfAnyP
|
|
dealloc_stack %a1 : $*AnyP
|
|
dealloc_stack %a0 : $*AnyP
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
sil @takeany : $@convention(thin) (@in_guaranteed AnyP) -> ()
|
|
|
|
// CHECK-LABEL: sil @testWitnessCopiedSelfWithIndirectResult2 : $@convention(thin) () -> () {
|
|
// CHECK: [[IN:%[0-9]+]] = alloc_stack $any AnyP
|
|
// CHECK: [[EA:%[0-9]+]] = init_existential_addr [[IN]]
|
|
// CHECK: [[OUT:%[0-9]+]] = alloc_stack $StructOfAnyP
|
|
// CHECK: witness_method $StructOfAnyP, #AnyP.returnsSelf : <Self where Self : AnyP> (Self) -> () -> Self : $@convention(witness_method: AnyP) <τ_0_0 where τ_0_0 : AnyP> (@in_guaranteed τ_0_0) -> @out StructOfAnyP
|
|
// CHECK: apply %{{.*}}<StructOfAnyP>([[OUT]], [[EA]]) : $@convention(witness_method: AnyP) <τ_0_0 where τ_0_0 : AnyP> (@in_guaranteed τ_0_0) -> @out StructOfAnyP
|
|
// CHECK-LABEL: } // end sil function 'testWitnessCopiedSelfWithIndirectResult2'
|
|
sil @testWitnessCopiedSelfWithIndirectResult2 : $() -> () {
|
|
bb0:
|
|
%a0 = alloc_stack $AnyP
|
|
%ie0 = init_existential_addr %a0 : $*AnyP, $StructOfAnyP
|
|
%f1 = function_ref @takeany : $@convention(thin) (@in_guaranteed AnyP) -> ()
|
|
%c1 = apply %f1(%a0) : $@convention(thin) (@in_guaranteed AnyP) -> ()
|
|
%a1 = alloc_stack $AnyP
|
|
copy_addr %a0 to [init] %a1 : $*AnyP
|
|
%o0 = open_existential_addr immutable_access %a1 : $*AnyP to $*@opened("8C4DAF8E-D722-11E8-920A-D0817AD9F6DD", AnyP) Self
|
|
%a2 = alloc_stack $StructOfAnyP
|
|
%w0 = witness_method $@opened("8C4DAF8E-D722-11E8-920A-D0817AD9F6DD", AnyP) Self, #AnyP.returnsSelf : <Self where Self : AnyP> (Self) -> () -> Self, %o0 : $*@opened("8C4DAF8E-D722-11E8-920A-D0817AD9F6DD", AnyP) Self : $@convention(witness_method: AnyP) <τ_0_0 where τ_0_0 : AnyP> (@in_guaranteed τ_0_0) -> @out StructOfAnyP
|
|
%c0 = apply %w0<@opened("8C4DAF8E-D722-11E8-920A-D0817AD9F6DD", AnyP) Self>(%a2, %o0) : $@convention(witness_method: AnyP) <τ_0_0 where τ_0_0 : AnyP> (@in_guaranteed τ_0_0) -> @out StructOfAnyP
|
|
dealloc_stack %a2 : $*StructOfAnyP
|
|
dealloc_stack %a1 : $*AnyP
|
|
dealloc_stack %a0 : $*AnyP
|
|
%v = tuple ()
|
|
return %v : $()
|
|
}
|
|
|
|
// <rdar://problem/46322928> Failure to devirtualize a protocol method
|
|
// applied to an opened existential blocks implementation of
|
|
// DataProtocol.
|
|
public protocol ContiguousBytes {
|
|
func withUnsafeBytes<R>(_ body: (UnsafeRawBufferPointer) throws -> R) rethrows -> R
|
|
}
|
|
|
|
extension Array : ContiguousBytes {
|
|
}
|
|
|
|
// specialized thunk for @callee_guaranteed (@unowned UnsafeRawBufferPointer) -> (@error @owned Error)
|
|
sil [transparent] [reabstraction_thunk] @testDevirtExistentialEnumThunk : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error Error)
|
|
|
|
// Test that the witness method's opened archetype is replaced by a
|
|
// concrete conformance.
|
|
//
|
|
// Note that the enum is destroyed by unchecked_take_enum_data_addr
|
|
// before the apply (and the extracted data is destroy by the copy
|
|
// itself), so SILCombine cannot replace the call's self
|
|
// argument. Instead, we expect a later devirtualizer pass to just
|
|
// insert a cast of the opened existential.
|
|
//
|
|
// CHECK-LABEL: sil shared [noinline] @testDevirtExistentialEnum : $@convention(thin) (@guaranteed Array<Int>) -> () {
|
|
// CHECK: [[ALLOC_EXISTENTIAL:%.*]] = alloc_stack $any ContiguousBytes
|
|
// CHECK: [[ALLOC_ENUM:%.*]] = alloc_stack $any ContiguousBytes
|
|
// CHECK: [[INIT_DATA:%.*]] = init_existential_addr [[ALLOC_ENUM]] : $*any ContiguousBytes, $Array<Int>
|
|
// CHECK: store %0 to [[INIT_DATA]] : $*Array<Int>
|
|
// CHECK: copy_addr [take] [[ALLOC_ENUM]] to [init] [[ALLOC_EXISTENTIAL]] : $*any ContiguousBytes
|
|
// CHECK: [[OPENED:%.*]] = open_existential_addr immutable_access [[ALLOC_EXISTENTIAL]] : $*any ContiguousBytes to $*@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD", any ContiguousBytes) Self
|
|
// CHECK: [[THUNK:%.*]] = function_ref @testDevirtExistentialEnumThunk : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error any Error)
|
|
// CHECK: [[TTF:%.*]] = thin_to_thick_function [[THUNK:%.*]] : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error any Error) to $@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out (), @error any Error)
|
|
// CHECK: [[WM:%.*]] = witness_method $Array<Int>, #ContiguousBytes.withUnsafeBytes : <Self where Self : ContiguousBytes><R> (Self) -> ((UnsafeRawBufferPointer) throws -> R) throws -> R : $@convention(witness_method: ContiguousBytes) <τ_0_0 where τ_0_0 : ContiguousBytes><τ_1_0> (@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out τ_1_0, @error any Error), @in_guaranteed τ_0_0) -> (@out τ_1_0, @error any Error)
|
|
// CHECK: [[CAST:%.*]] = unchecked_addr_cast [[OPENED]]
|
|
// CHECK: apply [nothrow] [[WM]]<Array<Int>, ()>(%{{.*}}, [[TTF]], [[CAST]]) : $@convention(witness_method: ContiguousBytes) <τ_0_0 where τ_0_0 : ContiguousBytes><τ_1_0> (@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out τ_1_0, @error any Error), @in_guaranteed τ_0_0) -> (@out τ_1_0, @error any Error)
|
|
// CHECK: destroy_addr [[ALLOC_EXISTENTIAL]] : $*any ContiguousBytes
|
|
// CHECK-LABEL: } // end sil function 'testDevirtExistentialEnum'
|
|
sil shared [noinline] @testDevirtExistentialEnum : $@convention(thin) (@guaranteed Array<Int>) -> () {
|
|
bb0(%0 : $Array<Int>):
|
|
%3 = alloc_stack $ContiguousBytes
|
|
%4 = alloc_stack $Optional<ContiguousBytes>
|
|
%5 = init_enum_data_addr %4 : $*Optional<ContiguousBytes>, #Optional.some!enumelt
|
|
%6 = init_existential_addr %5 : $*ContiguousBytes, $Array<Int>
|
|
store %0 to %6 : $*Array<Int>
|
|
inject_enum_addr %4 : $*Optional<ContiguousBytes>, #Optional.some!enumelt
|
|
%9 = unchecked_take_enum_data_addr %4 : $*Optional<ContiguousBytes>, #Optional.some!enumelt
|
|
copy_addr [take] %9 to [init] %3 : $*ContiguousBytes
|
|
dealloc_stack %4 : $*Optional<ContiguousBytes>
|
|
%12 = open_existential_addr immutable_access %3 : $*ContiguousBytes to $*@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD", ContiguousBytes) Self
|
|
%13 = alloc_stack $()
|
|
%14 = function_ref @testDevirtExistentialEnumThunk : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error Error)
|
|
%15 = thin_to_thick_function %14 : $@convention(thin) (UnsafeRawBufferPointer) -> (@out (), @error Error) to $@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out (), @error Error)
|
|
%16 = witness_method $@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD", ContiguousBytes) Self, #ContiguousBytes.withUnsafeBytes : <Self where Self : ContiguousBytes><R> (Self) -> ((UnsafeRawBufferPointer) throws -> R) throws -> R, %12 : $*@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD", ContiguousBytes) Self : $@convention(witness_method: ContiguousBytes) <τ_0_0 where τ_0_0 : ContiguousBytes><τ_1_0> (@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out τ_1_0, @error Error), @in_guaranteed τ_0_0) -> (@out τ_1_0, @error Error)
|
|
%21 = apply [nothrow] %16<@opened("8402EC1A-F35D-11E8-950A-D0817AD9F6DD", ContiguousBytes) Self, ()>(%13, %15, %12) : $@convention(witness_method: ContiguousBytes) <τ_0_0 where τ_0_0 : ContiguousBytes><τ_1_0> (@noescape @callee_guaranteed (UnsafeRawBufferPointer) -> (@out τ_1_0, @error Error), @in_guaranteed τ_0_0) -> (@out τ_1_0, @error Error)
|
|
dealloc_stack %13 : $*()
|
|
destroy_addr %3 : $*ContiguousBytes
|
|
dealloc_stack %3 : $*ContiguousBytes
|
|
%25 = tuple ()
|
|
return %25 : $()
|
|
}
|
|
|
|
struct InGuaranteedArgTestNativeObjectWrapper {
|
|
var i: Builtin.NativeObject
|
|
}
|
|
|
|
protocol InGuaranteedArgTestProtocol {}
|
|
extension InGuaranteedArgTestNativeObjectWrapper : InGuaranteedArgTestProtocol {}
|
|
|
|
sil @in_guaranteed_arg_test_callee : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
|
|
|
|
// CHECK-LABEL: sil @in_guaranteed_arg_test_caller : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> () {
|
|
// CHECK: bb0(%0 : $*τ_0_0):
|
|
// CHECK: [[ALLOC1:%.*]] = alloc_stack $τ_0_0
|
|
// CHECK: copy_addr [take] %0 to [init] [[ALLOC1]] : $*τ_0_0
|
|
// CHECK: [[F:%.*]] = function_ref @in_guaranteed_arg_test_callee : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
|
|
// CHECK: [[ALLOC2:%.*]] = alloc_stack $τ_0_0
|
|
// CHECK: copy_addr %1 to [init] [[ALLOC2]] : $*τ_0_0
|
|
// CHECK: apply [[F]]<τ_0_0>(%4) : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
|
|
// CHECK: dealloc_stack [[ALLOC2]] : $*τ_0_0
|
|
// CHECK: destroy_addr [[ALLOC1]] : $*τ_0_0
|
|
// CHECK: dealloc_stack [[ALLOC1]] : $*τ_0_0
|
|
// CHECK: } // end sil function 'in_guaranteed_arg_test_caller'
|
|
sil @in_guaranteed_arg_test_caller : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> () {
|
|
bb0(%0 : $*τ_0_0):
|
|
%1 = alloc_stack $InGuaranteedArgTestProtocol
|
|
%2 = init_existential_addr %1 : $*InGuaranteedArgTestProtocol, $τ_0_0
|
|
copy_addr [take] %0 to [init] %2 : $*τ_0_0
|
|
%3 = function_ref @in_guaranteed_arg_test_callee : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
|
|
%4 = alloc_stack $InGuaranteedArgTestProtocol
|
|
copy_addr %1 to [init] %4 : $*InGuaranteedArgTestProtocol
|
|
%5 = open_existential_addr mutable_access %4 : $*InGuaranteedArgTestProtocol to $*@opened("C494A60E-71EA-11E9-B8C0-D0817AD3F8AD", InGuaranteedArgTestProtocol) Self
|
|
apply %3<@opened("C494A60E-71EA-11E9-B8C0-D0817AD3F8AD", InGuaranteedArgTestProtocol) Self>(%5) : $@convention(thin) <τ_0_0 where τ_0_0 : InGuaranteedArgTestProtocol> (@in τ_0_0) -> ()
|
|
dealloc_stack %4 : $*InGuaranteedArgTestProtocol
|
|
destroy_addr %1 : $*InGuaranteedArgTestProtocol
|
|
dealloc_stack %1 : $*InGuaranteedArgTestProtocol
|
|
%9999 = tuple()
|
|
return %9999 : $()
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// Test concrete substitution for an owned references.
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
extension P {
|
|
public func witnessOwned()
|
|
}
|
|
|
|
extension C {
|
|
public func witnessOwned()
|
|
}
|
|
|
|
sil @$s32sil_combine_concrete_existential1PPAAE12witnessOwnedyyF : $@convention(method) <Self where Self : P> (@owned Self) -> ()
|
|
|
|
// CHECK-LABEL: sil hidden @$s1t12testOwnedRef1cyAA1CC_tF : $@convention(thin) (@guaranteed C) -> () {
|
|
// CHECK: bb0(%0 : $C):
|
|
// CHECK: strong_retain %0 : $C // id: %1
|
|
// CHECK: [[F:%.*]] = function_ref @$s32sil_combine_concrete_existential1PPAAE12witnessOwnedyyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0) -> ()
|
|
// CHECK: apply [[F]]<C>(%0) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0) -> ()
|
|
// CHECK-NEXT: tuple
|
|
// CHECK-NEXT: return
|
|
// CHECK-LABEL: } // end sil function '$s1t12testOwnedRef1cyAA1CC_tF'
|
|
sil hidden @$s1t12testOwnedRef1cyAA1CC_tF : $@convention(thin) (@guaranteed C) -> () {
|
|
bb0(%0 : $C):
|
|
strong_retain %0 : $C
|
|
%3 = init_existential_ref %0 : $C : $C, $P
|
|
%5 = open_existential_ref %3 : $P to $@opened("044D530E-7327-11E8-A998-ACDE48001133", P) Self
|
|
%6 = function_ref @$s32sil_combine_concrete_existential1PPAAE12witnessOwnedyyF : $@convention(method) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0) -> ()
|
|
%7 = apply %6<@opened("044D530E-7327-11E8-A998-ACDE48001133", P) Self>(%5) : $@convention(method) <τ_0_0 where τ_0_0 : P> (@owned τ_0_0) -> ()
|
|
%9 = tuple ()
|
|
return %9 : $()
|
|
}
|
|
|
|
protocol P1 { }
|
|
protocol P2 { }
|
|
protocol P3 { }
|
|
|
|
sil @callee : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P1, τ_0_1 : P2, τ_0_2 : P3> (@in τ_0_0, @in τ_0_2, @in τ_0_1) -> ()
|
|
|
|
// Check that the deallocations are created in the right order and the SILVerifier does not complain.
|
|
|
|
// CHECK-LABEL: sil @test_multiple_propagated_args
|
|
// CHECK-NOT: open_existential_addr
|
|
// CHECK-LABEL: } // end sil function 'test_multiple_propagated_args'
|
|
sil @test_multiple_propagated_args : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P1, τ_0_1 : P2, τ_0_2 : P3> (@in τ_0_0, @in τ_0_2, @in τ_0_1) -> () {
|
|
bb0(%0 : $*τ_0_0, %1 : $*τ_0_2, %2 : $*τ_0_1):
|
|
%5 = alloc_stack $P1
|
|
%6 = init_existential_addr %5 : $*P1, $τ_0_0
|
|
copy_addr [take] %0 to [init] %6 : $*τ_0_0
|
|
%8 = alloc_stack $P3
|
|
%9 = init_existential_addr %8 : $*P3, $τ_0_2
|
|
copy_addr [take] %1 to [init] %9 : $*τ_0_2
|
|
%11 = alloc_stack $P2
|
|
%12 = init_existential_addr %11 : $*P2, $τ_0_1
|
|
copy_addr [take] %2 to [init] %12 : $*τ_0_1
|
|
%15 = function_ref @callee : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P1, τ_0_1 : P2, τ_0_2 : P3> (@in τ_0_0, @in τ_0_2, @in τ_0_1) -> ()
|
|
%16 = open_existential_addr mutable_access %5 : $*P1 to $*@opened("76D54B80-FF66-11E9-B604-8C8590A6A134", P1) Self
|
|
%17 = alloc_stack $@opened("76D54B80-FF66-11E9-B604-8C8590A6A134", P1) Self
|
|
copy_addr %16 to [init] %17 : $*@opened("76D54B80-FF66-11E9-B604-8C8590A6A134", P1) Self
|
|
%19 = open_existential_addr mutable_access %8 : $*P3 to $*@opened("76D54C34-FF66-11E9-B604-8C8590A6A134", P3) Self
|
|
%20 = alloc_stack $@opened("76D54C34-FF66-11E9-B604-8C8590A6A134", P3) Self
|
|
copy_addr %19 to [init] %20 : $*@opened("76D54C34-FF66-11E9-B604-8C8590A6A134", P3) Self
|
|
%22 = open_existential_addr mutable_access %11 : $*P2 to $*@opened("76D54C84-FF66-11E9-B604-8C8590A6A134", P2) Self
|
|
%23 = alloc_stack $@opened("76D54C84-FF66-11E9-B604-8C8590A6A134", P2) Self
|
|
copy_addr %22 to [init] %23 : $*@opened("76D54C84-FF66-11E9-B604-8C8590A6A134", P2) Self
|
|
%25 = apply %15<@opened("76D54B80-FF66-11E9-B604-8C8590A6A134", P1) Self, @opened("76D54C84-FF66-11E9-B604-8C8590A6A134", P2) Self, @opened("76D54C34-FF66-11E9-B604-8C8590A6A134", P3) Self>(%17, %20, %23) : $@convention(thin) <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : P1, τ_0_1 : P2, τ_0_2 : P3> (@in τ_0_0, @in τ_0_2, @in τ_0_1) -> ()
|
|
destroy_addr %11 : $*P2
|
|
dealloc_stack %23 : $*@opened("76D54C84-FF66-11E9-B604-8C8590A6A134", P2) Self
|
|
destroy_addr %8 : $*P3
|
|
dealloc_stack %20 : $*@opened("76D54C34-FF66-11E9-B604-8C8590A6A134", P3) Self
|
|
destroy_addr %5 : $*P1
|
|
dealloc_stack %17 : $*@opened("76D54B80-FF66-11E9-B604-8C8590A6A134", P1) Self
|
|
dealloc_stack %11 : $*P2
|
|
dealloc_stack %8 : $*P3
|
|
dealloc_stack %5 : $*P1
|
|
return %25 : $()
|
|
}
|
|
|
|
|
|
public class MyObject {
|
|
deinit
|
|
init()
|
|
}
|
|
|
|
public protocol SubscriptionViewControllerDelegate { }
|
|
|
|
public class SubscriptionViewController {
|
|
deinit
|
|
init()
|
|
}
|
|
|
|
public protocol ResourceKitProtocol : MyObject { }
|
|
|
|
public protocol ResourceKitDelegate {
|
|
func subscriptionViewController(for resourceKit: ResourceKitProtocol)
|
|
}
|
|
|
|
class ViewController : ResourceKitDelegate {
|
|
func subscriptionViewController(for resourceKit: ResourceKitProtocol)
|
|
deinit
|
|
init()
|
|
}
|
|
|
|
class SubscriptionViewControllerBuilder {
|
|
@_hasStorage final let delegate: SubscriptionViewControllerDelegate { get }
|
|
init(delegate: SubscriptionViewControllerDelegate)
|
|
deinit
|
|
}
|
|
|
|
extension MyObject : SubscriptionViewControllerDelegate { }
|
|
|
|
// Make sure that we correctly update the substitution map of the apply.
|
|
// To satisfy ``τ_0_0 : SubscriptionViewControllerDelegate`` the updated
|
|
// substitution map of
|
|
// apply %10<$@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", ResourceKitProtocol) Self>
|
|
// needs to contain the concrete conformance
|
|
// ``(normal_conformance type=NSObject protocol=SubscriptionViewControllerDelegate)``
|
|
// not ``(abstract_conformance protocol=SubscriptionViewControllerDelegate)``
|
|
|
|
sil @callee2 : $@convention(thin) <τ_0_0 where τ_0_0 : SubscriptionViewControllerDelegate> (@in τ_0_0, @thick SubscriptionViewControllerBuilder.Type) -> @owned SubscriptionViewControllerBuilder
|
|
|
|
// CHECK: sil @test_opend_archetype_concrete_conformance_substitution : $@convention(method) (@guaranteed any ResourceKitProtocol, @guaranteed ViewController) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : $any ResourceKitProtocol, [[ARG2:%.*]] : $ViewController):
|
|
// CHECK: [[T1:%.*]] = metatype $@thick SubscriptionViewControllerBuilder.Type
|
|
// CHECK: [[T2:%.*]] = open_existential_ref [[ARG]] : $any ResourceKitProtocol to $@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", any ResourceKitProtocol) Self
|
|
// CHECK: [[T3:%.*]] = alloc_stack $any SubscriptionViewControllerDelegate
|
|
// CHECK: [[T4:%.*]] = init_existential_addr [[T3]] : $*any SubscriptionViewControllerDelegate, $@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", any ResourceKitProtocol) Self
|
|
// CHECK: store [[T2]] to [[T4]] : $*@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", any ResourceKitProtocol) Self
|
|
// CHECK: [[T5:%.*]] = function_ref @callee2 : $@convention(thin) <τ_0_0 where τ_0_0 : SubscriptionViewControllerDelegate> (@in τ_0_0, @thick SubscriptionViewControllerBuilder.Type) -> @owned SubscriptionViewControllerBuilder
|
|
// CHECK: [[T6:%.*]] = alloc_stack $@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", any ResourceKitProtocol) Self
|
|
// CHECK: copy_addr [[T4]] to [init] [[T6]] : $*@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", any ResourceKitProtocol) Self
|
|
// CHECK: Generic specialization information for call-site callee2 <any ResourceKitProtocol> conformances <(inherited_conformance type="any ResourceKitProtocol" protocol="SubscriptionViewControllerDelegate"
|
|
// CHECK: (normal_conformance type="MyObject" protocol="SubscriptionViewControllerDelegate"))>:
|
|
// CHECK: apply [[T5]]<@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", any ResourceKitProtocol) Self>([[T6]], [[T1]])
|
|
|
|
sil @test_opend_archetype_concrete_conformance_substitution : $@convention(method) (@guaranteed ResourceKitProtocol, @guaranteed ViewController) -> () {
|
|
bb0(%0 : $ResourceKitProtocol, %1 : $ViewController):
|
|
%4 = metatype $@thick SubscriptionViewControllerBuilder.Type
|
|
%5 = open_existential_ref %0 : $ResourceKitProtocol to $@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", ResourceKitProtocol) Self
|
|
%6 = alloc_stack $SubscriptionViewControllerDelegate
|
|
%7 = init_existential_addr %6 : $*SubscriptionViewControllerDelegate, $@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", ResourceKitProtocol) Self
|
|
strong_retain %5 : $@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", ResourceKitProtocol) Self
|
|
store %5 to %7 : $*@opened("E4D92D2A-8893-11EA-9C89-ACDE48001122", ResourceKitProtocol) Self
|
|
%10 = function_ref @callee2: $@convention(thin) <τ_0_0 where τ_0_0 : SubscriptionViewControllerDelegate> (@in τ_0_0, @thick SubscriptionViewControllerBuilder.Type) -> @owned SubscriptionViewControllerBuilder
|
|
%11 = open_existential_addr mutable_access %6 : $*SubscriptionViewControllerDelegate to $*@opened("FAA82796-8893-11EA-9C89-ACDE48001122", SubscriptionViewControllerDelegate) Self
|
|
%12 = alloc_stack $@opened("FAA82796-8893-11EA-9C89-ACDE48001122", SubscriptionViewControllerDelegate) Self
|
|
copy_addr %11 to [init] %12 : $*@opened("FAA82796-8893-11EA-9C89-ACDE48001122", SubscriptionViewControllerDelegate) Self
|
|
%14 = apply %10<@opened("FAA82796-8893-11EA-9C89-ACDE48001122", SubscriptionViewControllerDelegate) Self>(%12, %4) : $@convention(thin) <τ_0_0 where τ_0_0 : SubscriptionViewControllerDelegate> (@in τ_0_0, @thick SubscriptionViewControllerBuilder.Type) -> @owned SubscriptionViewControllerBuilder
|
|
destroy_addr %6 : $*SubscriptionViewControllerDelegate
|
|
dealloc_stack %12 : $*@opened("FAA82796-8893-11EA-9C89-ACDE48001122", SubscriptionViewControllerDelegate) Self
|
|
dealloc_stack %6 : $*SubscriptionViewControllerDelegate
|
|
strong_release %14 : $SubscriptionViewControllerBuilder
|
|
%19 = tuple ()
|
|
return %19 : $()
|
|
}
|
|
|
|
sil @calleWhichThrows : $@convention(thin) () -> (@out S, @error Error)
|
|
|
|
// CHECK-LABEL: sil @initExistentialWithDeinitExistential
|
|
// CHECK: [[S:%[0-9]+]] = alloc_stack $S
|
|
// CHECK-NOT: init_existential_addr
|
|
// CHECK: try_apply %{{[0-9]+}}([[S]])
|
|
// CHECK: destroy_addr [[S]] : $*S
|
|
// CHECK: dealloc_stack [[S]] : $*S
|
|
// CHECK: } // end sil function 'initExistentialWithDeinitExistential'
|
|
sil @initExistentialWithDeinitExistential : $@convention(thin) () -> @error Error {
|
|
bb0:
|
|
%4 = alloc_stack $PPP
|
|
%5 = function_ref @calleWhichThrows : $@convention(thin) () -> (@out S, @error Error)
|
|
%6 = init_existential_addr %4 : $*PPP, $S
|
|
try_apply %5(%6) : $@convention(thin) () -> (@out S, @error Error), normal bb1, error bb3
|
|
|
|
bb1(%8 : $()):
|
|
destroy_addr %4 : $*PPP
|
|
dealloc_stack %4 : $*PPP
|
|
%18 = tuple ()
|
|
return %18 : $()
|
|
|
|
|
|
bb3(%20 : $Error):
|
|
deinit_existential_addr %4 : $*PPP
|
|
dealloc_stack %4 : $*PPP
|
|
throw %20 : $Error
|
|
}
|
|
|
|
// -----------------------------------------------------------------------------
|
|
// rdar://88664423
|
|
// https://github.com/apple/swift/issues/58068
|
|
// Miscompile under -O with mutating protocol method
|
|
//
|
|
// Basic outline (test case has more copies):
|
|
// %1 = alloc_stack $PPP
|
|
// %2 = init_existential %1
|
|
// %3 = open_existential_addr mutable_access %1
|
|
// apply mutatingFunc(%3)
|
|
// %5 = open_existential_addr %1
|
|
// %6 = alloc_stack $@opened P
|
|
// copy_addr %5 to [init] %6 : $*@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", PPP) Self
|
|
// apply callee3(%5)
|
|
//
|
|
// When ConcreteExistentialInfo identified the initialization of:
|
|
// %4 = alloc_stack [lexical] $PPP, var, name "mergedCommand"
|
|
//
|
|
// It checks for any mutation other than the initialization itself.
|
|
// In this case, `open_existential_addr mutable_access` must be
|
|
// considered a possible mutation of the on-stack value.
|
|
|
|
sil @mutatingFunc : $@convention(method) (@inout S) -> ()
|
|
|
|
sil @callee3 : $@convention(thin) <τ_0_0 where τ_0_0 : PPP> (@in τ_0_0) -> ()
|
|
|
|
// CHECK-LABEL: sil @testMutatingCopiedOpenExistential : $@convention(thin) (S) -> () {
|
|
// CHECK: bb0(%0 : $S):
|
|
// CHECK: [[EXISCP:%.*]] = alloc_stack [lexical] $any PPP, var, name "mergedCommand"
|
|
// CHECK: apply %{{.*}} : $@convention(method) (@inout S) -> ()
|
|
// CHECK: [[OPENED:%.*]] = open_existential_addr mutable_access [[EXISCP]] : $*any PPP to $*@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", any PPP) Self
|
|
// CHECK: [[OPENEDCP:%.*]] = alloc_stack $@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", any PPP) Self
|
|
// CHECK: copy_addr [[OPENED]] to [init] [[OPENEDCP]] : $*@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", any PPP) Self
|
|
// CHECK: [[CALLEE3:%.*]] = function_ref @callee3 : $@convention(thin) <τ_0_0 where τ_0_0 : PPP> (@in τ_0_0) -> ()
|
|
// CHECK: apply [[CALLEE3]]<@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", any PPP) Self>([[OPENEDCP]]) : $@convention(thin) <τ_0_0 where τ_0_0 : PPP> (@in τ_0_0) -> ()
|
|
// CHECK-LABEL: } // end sil function 'testMutatingCopiedOpenExistential'
|
|
sil @testMutatingCopiedOpenExistential : $@convention(thin) (S) -> () {
|
|
bb0(%0 : $S):
|
|
%1 = alloc_stack $PPP
|
|
%2 = init_existential_addr %1 : $*PPP, $S
|
|
store %0 to %2 : $*S
|
|
%4 = alloc_stack [lexical] $PPP, var, name "mergedCommand"
|
|
copy_addr %1 to [init] %4 : $*PPP
|
|
%6 = open_existential_addr mutable_access %4 : $*PPP to $*@opened("3818BC52-89A1-11EC-999A-D0817AD9985D", PPP) Self
|
|
%7 = unchecked_addr_cast %6 : $*@opened("3818BC52-89A1-11EC-999A-D0817AD9985D", PPP) Self to $*S
|
|
|
|
%8 = function_ref @mutatingFunc : $@convention(method) (@inout S) -> ()
|
|
%9 = apply %8(%7) : $@convention(method) (@inout S) -> ()
|
|
%10 = open_existential_addr mutable_access %4 : $*PPP to $*@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", PPP) Self
|
|
%11 = alloc_stack $@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", PPP) Self
|
|
copy_addr %10 to [init] %11 : $*@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", PPP) Self
|
|
|
|
%13 = function_ref @callee3 : $@convention(thin) <τ_0_0 where τ_0_0 : PPP> (@in τ_0_0) -> ()
|
|
%14 = apply %13<@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", PPP) Self>(%11) : $@convention(thin) <τ_0_0 where τ_0_0 : PPP> (@in τ_0_0) -> ()
|
|
dealloc_stack %11 : $*@opened("381F6B6A-89A1-11EC-999A-D0817AD9985D", PPP) Self
|
|
destroy_addr %4 : $*PPP
|
|
dealloc_stack %4 : $*PPP
|
|
destroy_addr %1 : $*PPP
|
|
dealloc_stack %1 : $*PPP
|
|
%20 = tuple ()
|
|
return %20 : $()
|
|
}
|
|
|
|
sil_vtable SubscriptionViewControllerBuilder {}
|
|
sil_vtable SubscriptionViewController {}
|
|
sil_vtable ViewController {}
|
|
sil_vtable CCCC {}
|
|
sil_vtable CC {}
|
|
sil_vtable C {}
|
|
sil_vtable C_PQ {}
|
|
sil_vtable CDefaultStatic {}
|
|
sil_vtable MyObject {}
|